summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
Diffstat (limited to 'gst')
-rw-r--r--gst/Makefile.am4
-rw-r--r--gst/Makefile.in794
-rw-r--r--gst/asfdemux/Makefile.am27
-rw-r--r--gst/asfdemux/Makefile.in888
-rw-r--r--gst/asfdemux/README88
-rw-r--r--gst/asfdemux/asfheaders.c212
-rw-r--r--gst/asfdemux/asfheaders.h188
-rwxr-xr-xgst/asfdemux/asfpacket.c658
-rw-r--r--gst/asfdemux/asfpacket.h74
-rw-r--r--gst/asfdemux/gstasf.c72
-rw-r--r--gst/asfdemux/gstasfdemux.c4367
-rw-r--r--gst/asfdemux/gstasfdemux.h223
-rw-r--r--gst/asfdemux/gstrtpasfdepay.c545
-rw-r--r--gst/asfdemux/gstrtpasfdepay.h64
-rw-r--r--gst/asfdemux/gstrtspwms.c236
-rw-r--r--gst/asfdemux/gstrtspwms.h50
-rw-r--r--gst/dvdlpcmdec/Makefile.am24
-rw-r--r--gst/dvdlpcmdec/Makefile.in839
-rw-r--r--gst/dvdlpcmdec/gstdvdlpcmdec.c863
-rw-r--r--gst/dvdlpcmdec/gstdvdlpcmdec.h69
-rw-r--r--gst/dvdsub/Makefile.am25
-rw-r--r--gst/dvdsub/Makefile.in852
-rw-r--r--gst/dvdsub/gstdvdsubdec.c1160
-rw-r--r--gst/dvdsub/gstdvdsubdec.h102
-rw-r--r--gst/dvdsub/gstdvdsubparse.c241
-rw-r--r--gst/dvdsub/gstdvdsubparse.h65
-rw-r--r--gst/realmedia/Makefile.am39
-rw-r--r--gst/realmedia/Makefile.in986
-rw-r--r--gst/realmedia/asmrules.c711
-rw-r--r--gst/realmedia/asmrules.h115
-rw-r--r--gst/realmedia/gstrdtbuffer.c477
-rw-r--r--gst/realmedia/gstrdtbuffer.h122
-rw-r--r--gst/realmedia/pnmsrc.c240
-rw-r--r--gst/realmedia/pnmsrc.h59
-rw-r--r--gst/realmedia/rademux.c1007
-rw-r--r--gst/realmedia/rademux.h104
-rw-r--r--gst/realmedia/rdtdepay.c501
-rw-r--r--gst/realmedia/rdtdepay.h74
-rw-r--r--gst/realmedia/rdtjitterbuffer.c531
-rw-r--r--gst/realmedia/rdtjitterbuffer.h91
-rw-r--r--gst/realmedia/rdtmanager.c1374
-rw-r--r--gst/realmedia/rdtmanager.h93
-rw-r--r--gst/realmedia/realhash.c321
-rw-r--r--gst/realmedia/realhash.h31
-rw-r--r--gst/realmedia/realmedia.c59
-rw-r--r--gst/realmedia/rmdemux.c2586
-rw-r--r--gst/realmedia/rmdemux.h165
-rw-r--r--gst/realmedia/rmutils.c294
-rw-r--r--gst/realmedia/rmutils.h50
-rw-r--r--gst/realmedia/rtspreal.c735
-rw-r--r--gst/realmedia/rtspreal.h92
-rw-r--r--gst/xingmux/Makefile.am25
-rw-r--r--gst/xingmux/Makefile.in851
-rw-r--r--gst/xingmux/gstxingmux.c678
-rw-r--r--gst/xingmux/gstxingmux.h85
-rw-r--r--gst/xingmux/plugin.c41
56 files changed, 25267 insertions, 0 deletions
diff --git a/gst/Makefile.am b/gst/Makefile.am
new file mode 100644
index 0000000..db96293
--- /dev/null
+++ b/gst/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS=$(GST_PLUGINS_SELECTED)
+DIST_SUBDIRS=$(GST_PLUGINS_ALL)
+
+include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/gst/Makefile.in b/gst/Makefile.in
new file mode 100644
index 0000000..6cd649a
--- /dev/null
+++ b/gst/Makefile.in
@@ -0,0 +1,794 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# include this at the end of $MODULE/ext/Makefile.am to force make to
+# build subdirectories in parallel when make -jN is used. We will end up
+# descending into all subdirectories a second time, but only after the first
+# (parallel) run has finished, so it should go right through the second time.
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(top_srcdir)/common/parallel-subdirs.mak \
+ $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+subdir = gst
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-function.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/a52.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-sid.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+A52DEC_CFLAGS = @A52DEC_CFLAGS@
+A52DEC_LIBS = @A52DEC_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMRNB_CFLAGS = @AMRNB_CFLAGS@
+AMRNB_LIBS = @AMRNB_LIBS@
+AMRWB_CFLAGS = @AMRWB_CFLAGS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDIO_CFLAGS = @CDIO_CFLAGS@
+CDIO_LIBS = @CDIO_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVDREAD_LIBS = @DVDREAD_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DVDREAD = @HAVE_DVDREAD@
+HAVE_LAME = @HAVE_LAME@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LAME_CFLAGS = @LAME_CFLAGS@
+LAME_LIBS = @LAME_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPEG2DEC_CFLAGS = @MPEG2DEC_CFLAGS@
+MPEG2DEC_LIBS = @MPEG2DEC_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIDPLAY_CFLAGS = @SIDPLAY_CFLAGS@
+SIDPLAY_LIBS = @SIDPLAY_LIBS@
+STRIP = @STRIP@
+TWOLAME_CFLAGS = @TWOLAME_CFLAGS@
+TWOLAME_LIBS = @TWOLAME_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WIN32_LIBS = @WIN32_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = $(GST_PLUGINS_SELECTED)
+DIST_SUBDIRS = $(GST_PLUGINS_ALL)
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common/parallel-subdirs.mak $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/common/parallel-subdirs.mak:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+
+.PHONY: independent-subdirs $(SUBDIRS)
+
+independent-subdirs: $(SUBDIRS)
+
+$(SUBDIRS):
+ $(MAKE) -C $@
+
+all-recursive: independent-subdirs
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/asfdemux/Makefile.am b/gst/asfdemux/Makefile.am
new file mode 100644
index 0000000..93fa1e8
--- /dev/null
+++ b/gst/asfdemux/Makefile.am
@@ -0,0 +1,27 @@
+plugin_LTLIBRARIES = libgstasf.la
+
+libgstasf_la_SOURCES = gstasfdemux.c gstasf.c asfheaders.c asfpacket.c gstrtpasfdepay.c gstrtspwms.c
+libgstasf_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstasf_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ -lgstriff-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \
+ -lgstrtp-@GST_API_VERSION@ -lgstaudio-@GST_API_VERSION@ -lgsttag-@GST_API_VERSION@ \
+ $(GST_BASE_LIBS) $(GST_LIBS) \
+ $(WIN32_LIBS)
+libgstasf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstasf_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = gstasfdemux.h asfheaders.h asfpacket.h gstrtpasfdepay.h gstrtspwms.h
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstasf -:SHARED libgstasf \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstasf_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstasf_la_CFLAGS) \
+ -:LDFLAGS $(libgstasf_la_LDFLAGS) \
+ $(libgstasf_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
diff --git a/gst/asfdemux/Makefile.in b/gst/asfdemux/Makefile.in
new file mode 100644
index 0000000..b64afd9
--- /dev/null
+++ b/gst/asfdemux/Makefile.in
@@ -0,0 +1,888 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = gst/asfdemux
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS) README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-function.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/a52.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-sid.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstasf_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstasf_la_OBJECTS = libgstasf_la-gstasfdemux.lo \
+ libgstasf_la-gstasf.lo libgstasf_la-asfheaders.lo \
+ libgstasf_la-asfpacket.lo libgstasf_la-gstrtpasfdepay.lo \
+ libgstasf_la-gstrtspwms.lo
+libgstasf_la_OBJECTS = $(am_libgstasf_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgstasf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstasf_la_CFLAGS) $(CFLAGS) \
+ $(libgstasf_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgstasf_la_SOURCES)
+DIST_SOURCES = $(libgstasf_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A52DEC_CFLAGS = @A52DEC_CFLAGS@
+A52DEC_LIBS = @A52DEC_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMRNB_CFLAGS = @AMRNB_CFLAGS@
+AMRNB_LIBS = @AMRNB_LIBS@
+AMRWB_CFLAGS = @AMRWB_CFLAGS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDIO_CFLAGS = @CDIO_CFLAGS@
+CDIO_LIBS = @CDIO_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVDREAD_LIBS = @DVDREAD_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DVDREAD = @HAVE_DVDREAD@
+HAVE_LAME = @HAVE_LAME@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LAME_CFLAGS = @LAME_CFLAGS@
+LAME_LIBS = @LAME_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPEG2DEC_CFLAGS = @MPEG2DEC_CFLAGS@
+MPEG2DEC_LIBS = @MPEG2DEC_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIDPLAY_CFLAGS = @SIDPLAY_CFLAGS@
+SIDPLAY_LIBS = @SIDPLAY_LIBS@
+STRIP = @STRIP@
+TWOLAME_CFLAGS = @TWOLAME_CFLAGS@
+TWOLAME_LIBS = @TWOLAME_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WIN32_LIBS = @WIN32_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstasf.la
+libgstasf_la_SOURCES = gstasfdemux.c gstasf.c asfheaders.c asfpacket.c gstrtpasfdepay.c gstrtspwms.c
+libgstasf_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstasf_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ -lgstriff-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \
+ -lgstrtp-@GST_API_VERSION@ -lgstaudio-@GST_API_VERSION@ -lgsttag-@GST_API_VERSION@ \
+ $(GST_BASE_LIBS) $(GST_LIBS) \
+ $(WIN32_LIBS)
+
+libgstasf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstasf_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+noinst_HEADERS = gstasfdemux.h asfheaders.h asfpacket.h gstrtpasfdepay.h gstrtspwms.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/asfdemux/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/asfdemux/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgstasf.la: $(libgstasf_la_OBJECTS) $(libgstasf_la_DEPENDENCIES) $(EXTRA_libgstasf_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstasf_la_LINK) -rpath $(plugindir) $(libgstasf_la_OBJECTS) $(libgstasf_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstasf_la-asfheaders.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstasf_la-asfpacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstasf_la-gstasf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstasf_la-gstasfdemux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstasf_la-gstrtpasfdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstasf_la-gstrtspwms.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstasf_la-gstasfdemux.lo: gstasfdemux.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -MT libgstasf_la-gstasfdemux.lo -MD -MP -MF $(DEPDIR)/libgstasf_la-gstasfdemux.Tpo -c -o libgstasf_la-gstasfdemux.lo `test -f 'gstasfdemux.c' || echo '$(srcdir)/'`gstasfdemux.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstasf_la-gstasfdemux.Tpo $(DEPDIR)/libgstasf_la-gstasfdemux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstasfdemux.c' object='libgstasf_la-gstasfdemux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -c -o libgstasf_la-gstasfdemux.lo `test -f 'gstasfdemux.c' || echo '$(srcdir)/'`gstasfdemux.c
+
+libgstasf_la-gstasf.lo: gstasf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -MT libgstasf_la-gstasf.lo -MD -MP -MF $(DEPDIR)/libgstasf_la-gstasf.Tpo -c -o libgstasf_la-gstasf.lo `test -f 'gstasf.c' || echo '$(srcdir)/'`gstasf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstasf_la-gstasf.Tpo $(DEPDIR)/libgstasf_la-gstasf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstasf.c' object='libgstasf_la-gstasf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -c -o libgstasf_la-gstasf.lo `test -f 'gstasf.c' || echo '$(srcdir)/'`gstasf.c
+
+libgstasf_la-asfheaders.lo: asfheaders.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -MT libgstasf_la-asfheaders.lo -MD -MP -MF $(DEPDIR)/libgstasf_la-asfheaders.Tpo -c -o libgstasf_la-asfheaders.lo `test -f 'asfheaders.c' || echo '$(srcdir)/'`asfheaders.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstasf_la-asfheaders.Tpo $(DEPDIR)/libgstasf_la-asfheaders.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asfheaders.c' object='libgstasf_la-asfheaders.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -c -o libgstasf_la-asfheaders.lo `test -f 'asfheaders.c' || echo '$(srcdir)/'`asfheaders.c
+
+libgstasf_la-asfpacket.lo: asfpacket.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -MT libgstasf_la-asfpacket.lo -MD -MP -MF $(DEPDIR)/libgstasf_la-asfpacket.Tpo -c -o libgstasf_la-asfpacket.lo `test -f 'asfpacket.c' || echo '$(srcdir)/'`asfpacket.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstasf_la-asfpacket.Tpo $(DEPDIR)/libgstasf_la-asfpacket.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asfpacket.c' object='libgstasf_la-asfpacket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -c -o libgstasf_la-asfpacket.lo `test -f 'asfpacket.c' || echo '$(srcdir)/'`asfpacket.c
+
+libgstasf_la-gstrtpasfdepay.lo: gstrtpasfdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -MT libgstasf_la-gstrtpasfdepay.lo -MD -MP -MF $(DEPDIR)/libgstasf_la-gstrtpasfdepay.Tpo -c -o libgstasf_la-gstrtpasfdepay.lo `test -f 'gstrtpasfdepay.c' || echo '$(srcdir)/'`gstrtpasfdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstasf_la-gstrtpasfdepay.Tpo $(DEPDIR)/libgstasf_la-gstrtpasfdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpasfdepay.c' object='libgstasf_la-gstrtpasfdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -c -o libgstasf_la-gstrtpasfdepay.lo `test -f 'gstrtpasfdepay.c' || echo '$(srcdir)/'`gstrtpasfdepay.c
+
+libgstasf_la-gstrtspwms.lo: gstrtspwms.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -MT libgstasf_la-gstrtspwms.lo -MD -MP -MF $(DEPDIR)/libgstasf_la-gstrtspwms.Tpo -c -o libgstasf_la-gstrtspwms.lo `test -f 'gstrtspwms.c' || echo '$(srcdir)/'`gstrtspwms.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstasf_la-gstrtspwms.Tpo $(DEPDIR)/libgstasf_la-gstrtspwms.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtspwms.c' object='libgstasf_la-gstrtspwms.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstasf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstasf_la_CFLAGS) $(CFLAGS) -c -o libgstasf_la-gstrtspwms.lo `test -f 'gstrtspwms.c' || echo '$(srcdir)/'`gstrtspwms.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstasf -:SHARED libgstasf \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstasf_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstasf_la_CFLAGS) \
+ -:LDFLAGS $(libgstasf_la_LDFLAGS) \
+ $(libgstasf_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/asfdemux/README b/gst/asfdemux/README
new file mode 100644
index 0000000..d864eb0
--- /dev/null
+++ b/gst/asfdemux/README
@@ -0,0 +1,88 @@
+ASF Demuxer Plugin
+==================
+
+Overview
+--------
+
+This plugin is a demuxer for Microsoft's ASF Advanced Streaming Format
+or ASF [1]. This demuxer only supports ASF v1.0 since the vast
+majority of existing ASF files use that version. The specification
+has been derived from a third party source [2] without reference to
+the original.
+
+Design
+------
+
+The ASF format can carry any combination of audio, video or
+'ASF_Command_Media' streams. For simplicity it is assumed that each
+file can carry up to 16 audio streams and 16 video streams. These are
+implemented as dynamic pads and appear as appropriate once the file
+headers have been parsed.
+
+ (-------------------------)
+ ! asfdemux !
+ ! (video/raw0)---
+ ! (video/raw1)---
+ ! (video/raw...
+ --- src !
+ ! (audio/raw0)---
+ ! (audio/raw1)---
+ ! (audio/raw...
+ ! !
+ (-------------------------)
+
+
+Known stream fourccs are:
+
+Type Tags MIME type
+------------------------------------------
+H263 H263 I263 video/x-h263
+MJPEG MJPG image/jpeg
+MPEG4 DIVX divx DX50 video/mpeg
+ XVID xvid mp4s
+ MP4S M4S2 m4s2
+ 0x04000000
+MSMPEG4V1 MPG4 video/mpeg
+MSMPEG4V2 MP42 video/mpeg
+MSMPEG4V3 MP43 DIV3 video/mpeg
+WMV1 WMV1 video/x-wmv, wmvversion = (int) 1
+WMV2 WMV2 video/x-wmv, wmvversion = (int) 2
+WMV3 WMV3 video/x-wmv, wmvversion = (int) 3
+WMA1 WMA1 audio/x-wma, wmaversion = (int) 1
+WMA2 WMA2 audio/x-wma, wmaversion = (int) 2
+ audio/x-wma, wmaversion = (int) 3
+
+These video stream headers is very similar to that used in the AVI
+format as are the audio stream headers. In addition the content types
+are basically the same also so, for compatibility with existing
+plugins the src pads are set up as video/x-msvideo. This enables
+compatibility with the ffmpeg plugin.
+
+The demuxing process begins with the loop function gst_asf_demux_loop
+and parses the file in a recursive tree as follows:
+
+ gst_asf_demux_loop()
+ +-> gst_asf_demux_process_object() <----
+ +-> gst_asf_demux_process_stream() \
+ |-> gst_asf_demux_process_file() |
+ |-> gst_asf_demux_process_header() --+
+ |-> gst_asf_demux_process_data()
+ +-> gst_asf_demux_process_segment()
+ +-> gst_asf_demux_process_chunk()
+
+Todo
+----
+
+- Support for ASF v2.0
+- Support for command media streams
+
+
+
+References
+----------
+
+[1] Microsoft. ASF Specification - Windows Media Technologies.
+http://www.microsoft.com/windows/windowsmedia/format/asfspec.aspx (v01.20.01e, September 2003)
+
+[2] divx at euro.ru. ASF format version 1.0,
+reconstruction. http://avifile.sourceforge.net/asf-1.0.htm
diff --git a/gst/asfdemux/asfheaders.c b/gst/asfdemux/asfheaders.c
new file mode 100644
index 0000000..b8e8a3c
--- /dev/null
+++ b/gst/asfdemux/asfheaders.c
@@ -0,0 +1,212 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+#include "asfheaders.h"
+
+const ASFGuidHash asf_payload_ext_guids[] = {
+ {ASF_PAYLOAD_EXTENSION_DURATION, "ASF_PAYLOAD_EXTENSION_DURATION",
+ {0xC6BD9450, 0x4907867F, 0x79C7A383, 0xAD33B721}
+ },
+ {ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT, "ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT",
+ {0xD590DC20, 0x436C07BC, 0xBBF3f79C, 0xDCA4F1FB}},
+ {ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO,
+ "ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO",
+ {0x1b1ee554, 0x4bc8f9ea, 0x6b371a82, 0xb8c4e474}},
+ {ASF_PAYLOAD_EXTENSION_TIMING, "ASF_PAYLOAD_EXTENSION_TIMING",
+ {0XFD3CC02A, 0X4CFA06DB, 0X12721C80, 0XE44587D3}},
+ {ASF_PAYLOAD_EXTENSION_UNDEFINED, "ASF_PAYLOAD_EXTENSION_UNDEFINED",
+ {0, 0, 0, 0}
+ }
+};
+
+const ASFGuidHash asf_correction_guids[] = {
+ {ASF_CORRECTION_ON, "ASF_CORRECTION_ON",
+ {0xBFC3CD50, 0x11CF618F, 0xAA00B28B, 0x20E2B400}
+ },
+ {ASF_CORRECTION_OFF, "ASF_CORRECTION_OFF",
+ {0x20FB5700, 0x11CF5B55, 0x8000FDA8, 0x2B445C5F}
+ },
+ /* CHECKME: where does this 49F1A440... GUID come from? (tpm) */
+ {ASF_CORRECTION_OFF, "ASF_CORRECTION_OFF",
+ {0x49F1A440, 0x11D04ECE, 0xA000ACA3, 0xF64803C9}
+ },
+ {ASF_CORRECTION_UNDEFINED, "ASF_CORRECTION_UNDEFINED",
+ {0, 0, 0, 0}
+ }
+};
+
+const ASFGuidHash asf_stream_guids[] = {
+ {ASF_STREAM_VIDEO, "ASF_STREAM_VIDEO",
+ {0xBC19EFC0, 0x11CF5B4D, 0x8000FDA8, 0x2B445C5F}
+ },
+ {ASF_STREAM_AUDIO, "ASF_STREAM_AUDIO",
+ {0xF8699E40, 0x11CF5B4D, 0x8000FDA8, 0x2B445C5F}
+ },
+ {ASF_STREAM_EXT_EMBED_HEADER, "ASF_STREAM_EXT_EMBED_HEADER",
+ {0X3AFB65E2, 0X40F247EF, 0XA9702CAC, 0X43D3710D}},
+ {ASF_STREAM_UNDEFINED, "ASF_STREAM_UNDEFINED",
+ {0, 0, 0, 0}
+ }
+};
+
+const ASFGuidHash asf_ext_stream_guids[] = {
+ {ASF_EXT_STREAM_AUDIO, "ASF_EXT_STREAM_AUDIO",
+ {0X31178C9D, 0X452803E1, 0XF93D82B5, 0X03F522DB}
+ },
+ {ASF_EXT_STREAM_UNDEFINED, "ASF_EXT_STREAM_UNDEFINED",
+ {0, 0, 0, 0}
+ }
+};
+
+const ASFGuidHash asf_object_guids[] = {
+ {ASF_OBJ_STREAM, "ASF_OBJ_STREAM",
+ {0xB7DC0791, 0x11CFA9B7, 0xC000E68E, 0x6553200C}
+ },
+ {ASF_OBJ_DATA, "ASF_OBJ_DATA",
+ {0x75b22636, 0x11cf668e, 0xAA00D9a6, 0x6Cce6200}
+ },
+ {ASF_OBJ_FILE, "ASF_OBJ_FILE",
+ {0x8CABDCA1, 0x11CFA947, 0xC000E48E, 0x6553200C}
+ },
+ {ASF_OBJ_HEADER, "ASF_OBJ_HEADER",
+ {0x75B22630, 0x11CF668E, 0xAA00D9A6, 0x6CCE6200}
+ },
+ {ASF_OBJ_CONCEAL_NONE, "ASF_OBJ_CONCEAL_NONE",
+ {0x20fb5700, 0x11cf5b55, 0x8000FDa8, 0x2B445C5f}
+ },
+ {ASF_OBJ_COMMENT, "ASF_OBJ_COMMENT",
+ {0x75b22633, 0x11cf668e, 0xAA00D9a6, 0x6Cce6200}
+ },
+ {ASF_OBJ_CODEC_COMMENT, "ASF_OBJ_CODEC_COMMENT",
+ {0x86D15240, 0x11D0311D, 0xA000A4A3, 0xF64803C9}
+ },
+ {ASF_OBJ_CODEC_COMMENT1, "ASF_OBJ_CODEC_COMMENT1",
+ {0x86d15241, 0x11d0311d, 0xA000A4a3, 0xF64803c9}
+ },
+ {ASF_OBJ_SIMPLE_INDEX, "ASF_OBJ_SIMPLE_INDEX",
+ {0x33000890, 0x11cfe5b1, 0xA000F489, 0xCB4903c9}
+ },
+ {ASF_OBJ_INDEX, "ASF_OBJ_INDEX",
+ {0xd6e229d3, 0x11d135da, 0xa0003490, 0xbe4903c9}
+ },
+ {ASF_OBJ_HEAD1, "ASF_OBJ_HEAD1",
+ {0x5fbf03b5, 0x11cfa92e, 0xC000E38e, 0x6553200c}
+ },
+ {ASF_OBJ_HEAD2, "ASF_OBJ_HEAD2",
+ {0xabd3d211, 0x11cfa9ba, 0xC000E68e, 0x6553200c}
+ },
+ {ASF_OBJ_PADDING, "ASF_OBJ_PADDING",
+ {0x1806D474, 0x4509CADF, 0xAB9ABAA4, 0xE8AA96CB}
+ },
+ {ASF_OBJ_BITRATE_PROPS, "ASF_OBJ_BITRATE_PROPS",
+ {0x7bf875ce, 0x11d1468d, 0x6000828d, 0xb2a2c997}
+ },
+ {ASF_OBJ_EXT_CONTENT_DESC, "ASF_OBJ_EXT_CONTENT_DESC",
+ {0xd2d0a440, 0x11d2e307, 0xa000f097, 0x50a85ec9}
+ },
+ {ASF_OBJ_BITRATE_MUTEX, "ASF_OBJ_BITRATE_MUTEX",
+ {0xd6e229dc, 0x11d135da, 0xa0003490, 0xbe4903c9}
+ },
+ {ASF_OBJ_LANGUAGE_LIST, "ASF_OBJ_LANGUAGE_LIST",
+ {0x7c4346a9, 0x4bfcefe0, 0x3e3929b2, 0x855c41de}
+ },
+ {ASF_OBJ_METADATA_OBJECT, "ASF_OBJ_METADATA_OBJECT",
+ {0xc5f8cbea, 0x48775baf, 0x8caa6784, 0xca4cfa44}
+ },
+ {ASF_OBJ_EXTENDED_STREAM_PROPS, "ASF_OBJ_EXTENDED_STREAM_PROPS",
+ {0x14e6a5cb, 0x4332c672, 0x69a99983, 0x5a5b0652}
+ },
+ {ASF_OBJ_COMPATIBILITY, "ASF_OBJ_COMPATIBILITY",
+ {0x26f18b5d, 0x47ec4584, 0x650e5f9f, 0xc952041f}
+ },
+ {ASF_OBJ_INDEX_PLACEHOLDER, "ASF_OBJ_INDEX_PLACEHOLDER",
+ {0xd9aade20, 0x4f9c7c17, 0x558528bc, 0xa2e298dd}
+ },
+ {ASF_OBJ_INDEX_PARAMETERS, "ASF_OBJ_INDEX_PARAMETERS",
+ {0xd6e229df, 0x11d135da, 0xa0003490, 0xbe4903c9}
+ },
+ {ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION, "ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION",
+ {0xa08649cf, 0x46704775, 0x356e168a, 0xcd667535}
+ },
+ {ASF_OBJ_STREAM_PRIORITIZATION, "ASF_OBJ_STREAM_PRIORITIZATION",
+ {0xd4fed15b, 0x454f88d3, 0x5cedf081, 0x249e9945}
+ },
+ {ASF_OBJ_CONTENT_ENCRYPTION, "ASF_OBJ_CONTENT_ENCRYPTION",
+ {0x2211b3fb, 0x11d2bd23, 0xa000b7b4, 0x6efc55c9}
+ },
+ {ASF_OBJ_EXT_CONTENT_ENCRYPTION, "ASF_OBJ_EXT_CONTENT_ENCRYPTION",
+ {0x298ae614, 0x4c172622, 0xe0da35b9, 0x9c28e97e}
+ },
+ {ASF_OBJ_DIGITAL_SIGNATURE_OBJECT, "ASF_OBJ_DIGITAL_SIGNATURE_OBJECT",
+ {0x2211b3fc, 0x11d2bd23, 0xa000b7b4, 0x6efc55c9}
+ },
+ {ASF_OBJ_SCRIPT_COMMAND, "ASF_OBJ_SCRIPT_COMMAND",
+ {0x1efb1a30, 0x11d00b62, 0xa0009ba3, 0xf64803c9}
+ },
+ {ASF_OBJ_MARKER, "ASF_OBJ_MARKER",
+ {0xf487cd01, 0x11cfa951, 0xc000e68e, 0x6553200c}
+ },
+ /* This guid is definitely used for encryption (mentioned in MS smooth
+ * streaming docs) in new PlayReady (c) (tm) (wtf) system, but I haven't
+ * found a proper name for it.
+ * (Edward Jan 11 2011).*/
+ {ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT, "ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT",
+ {0x9a04f079, 0x42869840, 0x5be692ab, 0x955f88e0}
+ },
+ {ASF_OBJ_METADATA_LIBRARY_OBJECT, "ASF_OBJ_METADATA_LIBRARY_OBJECT",
+ {0x44231c94, 0x49d19498, 0x131d41a1, 0x5470454e}
+ },
+ {ASF_OBJ_UNDEFINED, "ASF_OBJ_UNDEFINED",
+ {0, 0, 0, 0}
+ }
+};
+
+guint32
+gst_asf_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
+{
+ gint i;
+
+ for (i = 0; guids[i].obj_id != ASF_OBJ_UNDEFINED; ++i) {
+ if (guids[i].guid.v1 == guid->v1 &&
+ guids[i].guid.v2 == guid->v2 &&
+ guids[i].guid.v3 == guid->v3 && guids[i].guid.v4 == guid->v4) {
+ return guids[i].obj_id;
+ }
+ }
+
+ /* The base case if none is found */
+ return ASF_OBJ_UNDEFINED;
+}
+
+const gchar *
+gst_asf_get_guid_nick (const ASFGuidHash * guids, guint32 obj_id)
+{
+ gint i;
+
+ for (i = 0; guids[i].obj_id != ASF_OBJ_UNDEFINED; ++i) {
+ if (guids[i].obj_id == obj_id) {
+ return guids[i].obj_id_str;
+ }
+ }
+
+ /* The base case if none is found */
+ return "ASF_OBJ_UNDEFINED";
+}
diff --git a/gst/asfdemux/asfheaders.h b/gst/asfdemux/asfheaders.h
new file mode 100644
index 0000000..9e8d972
--- /dev/null
+++ b/gst/asfdemux/asfheaders.h
@@ -0,0 +1,188 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ASFHEADERS_H__
+#define __ASFHEADERS_H__
+
+G_BEGIN_DECLS
+
+typedef struct {
+ guint32 v1;
+ guint32 v2;
+ guint32 v3;
+ guint32 v4;
+} ASFGuid;
+
+
+
+typedef struct {
+ guint8 obj_id;
+ const gchar *obj_id_str;
+ ASFGuid guid;
+} ASFGuidHash;
+
+typedef enum {
+ ASF_OBJ_UNDEFINED = 0,
+ ASF_OBJ_STREAM,
+ ASF_OBJ_DATA,
+ ASF_OBJ_FILE,
+ ASF_OBJ_HEADER,
+ ASF_OBJ_CONCEAL_NONE,
+ ASF_OBJ_COMMENT,
+ ASF_OBJ_CODEC_COMMENT,
+ ASF_OBJ_CODEC_COMMENT1,
+ ASF_OBJ_SIMPLE_INDEX,
+ ASF_OBJ_INDEX,
+ ASF_OBJ_HEAD1,
+ ASF_OBJ_HEAD2,
+ ASF_OBJ_PADDING,
+ ASF_OBJ_BITRATE_PROPS,
+ ASF_OBJ_EXT_CONTENT_DESC,
+ ASF_OBJ_BITRATE_MUTEX,
+ ASF_OBJ_LANGUAGE_LIST,
+ ASF_OBJ_METADATA_OBJECT,
+ ASF_OBJ_EXTENDED_STREAM_PROPS,
+ ASF_OBJ_COMPATIBILITY,
+ ASF_OBJ_INDEX_PLACEHOLDER,
+ ASF_OBJ_INDEX_PARAMETERS,
+ ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION,
+ ASF_OBJ_STREAM_PRIORITIZATION,
+ ASF_OBJ_CONTENT_ENCRYPTION,
+ ASF_OBJ_EXT_CONTENT_ENCRYPTION,
+ ASF_OBJ_DIGITAL_SIGNATURE_OBJECT,
+ ASF_OBJ_SCRIPT_COMMAND,
+ ASF_OBJ_MARKER,
+ ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT,
+ ASF_OBJ_METADATA_LIBRARY_OBJECT,
+} AsfObjectID;
+
+typedef enum {
+ ASF_STREAM_UNDEFINED = 0,
+ ASF_STREAM_VIDEO,
+ ASF_STREAM_AUDIO,
+ ASF_STREAM_EXT_EMBED_HEADER
+} AsfStreamType;
+
+typedef enum {
+ ASF_EXT_STREAM_UNDEFINED = 0,
+ ASF_EXT_STREAM_AUDIO
+} AsfExtStreamType;
+
+typedef enum {
+ ASF_CORRECTION_UNDEFINED = 0,
+ ASF_CORRECTION_ON,
+ ASF_CORRECTION_OFF
+} AsfCorrectionType;
+
+typedef enum {
+ ASF_PAYLOAD_EXTENSION_UNDEFINED = 0,
+ ASF_PAYLOAD_EXTENSION_DURATION,
+ ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT,
+ ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO,
+ ASF_PAYLOAD_EXTENSION_TIMING
+} AsfPayloadExtensionID;
+
+extern const ASFGuidHash asf_payload_ext_guids[];
+
+extern const ASFGuidHash asf_correction_guids[];
+
+extern const ASFGuidHash asf_stream_guids[];
+
+extern const ASFGuidHash asf_ext_stream_guids[];
+
+extern const ASFGuidHash asf_object_guids[];
+
+/* GUID utilities */
+guint32 gst_asf_identify_guid (const ASFGuidHash * guids,
+ ASFGuid * guid);
+
+const gchar *gst_asf_get_guid_nick (const ASFGuidHash * guids,
+ guint32 obj_id);
+
+struct _asf_stream_audio {
+ guint16 codec_tag;
+ guint16 channels;
+ guint32 sample_rate;
+ guint32 byte_rate;
+ guint16 block_align;
+ guint16 word_size;
+ guint16 size;
+};
+
+typedef struct _asf_stream_audio asf_stream_audio;
+
+struct _asf_stream_video {
+ guint32 width;
+ guint32 height;
+ guint8 unknown;
+ guint16 size;
+};
+
+typedef struct _asf_stream_video asf_stream_video;
+
+struct _asf_stream_video_format {
+ guint32 size;
+ guint32 width;
+ guint32 height;
+ guint16 planes;
+ guint16 depth;
+ guint32 tag;
+ guint32 image_size;
+ guint32 xpels_meter;
+ guint32 ypels_meter;
+ guint32 num_colors;
+ guint32 imp_colors;
+};
+
+typedef struct _asf_stream_video_format asf_stream_video_format;
+
+struct _asf_obj_data_correction {
+ guint8 type;
+ guint8 cycle;
+};
+
+typedef struct _asf_obj_data_correction asf_obj_data_correction;
+
+struct _asf_packet_info {
+ guint32 padsize;
+ guint8 replicsizetype;
+ guint8 fragoffsettype;
+ guint8 seqtype;
+ guint8 segsizetype;
+ gboolean multiple;
+ guint32 size_left;
+};
+
+typedef struct _asf_packet_info asf_packet_info;
+
+struct _asf_segment_info {
+ guint8 stream_number;
+ guint32 chunk_size;
+ guint32 frag_offset;
+ guint32 segment_size;
+ guint32 sequence;
+ guint32 frag_timestamp;
+ gboolean compressed;
+};
+
+typedef struct _asf_segment_info asf_segment_info;
+
+G_END_DECLS
+
+#endif /* __ASFHEADERS_H__ */
diff --git a/gst/asfdemux/asfpacket.c b/gst/asfdemux/asfpacket.c
new file mode 100755
index 0000000..7379d86
--- /dev/null
+++ b/gst/asfdemux/asfpacket.c
@@ -0,0 +1,658 @@
+/* GStreamer ASF/WMV/WMA demuxer
+ * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME:
+ * file:///home/tpm/samples/video/asf//336370-regis-velo862.wmv
+ * file:///home/tpm/samples/video/asf//336370-eichhoer.wmv
+ * throw errors (not always necessarily) in this code path
+ * (looks like they carry broken payloads/packets though) */
+
+#include "asfpacket.h"
+
+#include <gst/gstutils.h>
+#include <gst/gstinfo.h>
+#include <string.h>
+
+/* we are unlikely to deal with lengths > 2GB here any time soon, so just
+ * return a signed int and use that for error reporting */
+static inline gint
+asf_packet_read_varlen_int (guint lentype_flags, guint lentype_bit_offset,
+ const guint8 ** p_data, guint * p_size)
+{
+ static const guint lens[4] = { 0, 1, 2, 4 };
+ guint len, val;
+
+ len = lens[(lentype_flags >> lentype_bit_offset) & 0x03];
+
+ /* will make caller bail out with a short read if there's not enough data */
+ if (G_UNLIKELY (*p_size < len)) {
+ GST_WARNING ("need %u bytes, but only %u bytes available", len, *p_size);
+ return -1;
+ }
+
+ switch (len) {
+ case 0:
+ val = 0;
+ break;
+ case 1:
+ val = GST_READ_UINT8 (*p_data);
+ break;
+ case 2:
+ val = GST_READ_UINT16_LE (*p_data);
+ break;
+ case 4:
+ val = GST_READ_UINT32_LE (*p_data);
+ break;
+ default:
+ val = 0;
+ g_assert_not_reached ();
+ }
+
+ *p_data += len;
+ *p_size -= len;
+
+ return (gint) val;
+}
+
+static GstBuffer *
+asf_packet_create_payload_buffer (AsfPacket * packet, const guint8 ** p_data,
+ guint * p_size, guint payload_len)
+{
+ guint off;
+
+ g_assert (payload_len <= *p_size);
+
+ off = (guint) (*p_data - packet->bdata);
+ g_assert (off < gst_buffer_get_size (packet->buf));
+
+ *p_data += payload_len;
+ *p_size -= payload_len;
+
+ return gst_buffer_copy_region (packet->buf, GST_BUFFER_COPY_ALL, off,
+ payload_len);
+}
+
+static AsfPayload *
+asf_payload_find_previous_fragment (AsfPayload * payload, AsfStream * stream)
+{
+ AsfPayload *ret;
+
+ if (G_UNLIKELY (stream->payloads->len == 0)) {
+ GST_DEBUG ("No previous fragments to merge with for stream %u", stream->id);
+ return NULL;
+ }
+
+ ret =
+ &g_array_index (stream->payloads, AsfPayload, stream->payloads->len - 1);
+
+ if (G_UNLIKELY (ret->mo_size != payload->mo_size ||
+ ret->mo_number != payload->mo_number || ret->mo_offset != 0)) {
+ if (payload->mo_size != 0) {
+ GST_WARNING ("Previous fragment does not match continued fragment");
+ return NULL;
+ } else {
+ /* Warn about this case, but accept it anyway: files in the wild sometimes
+ * have continued packets where the subsequent fragments say that they're
+ * zero-sized. */
+ GST_WARNING ("Previous fragment found, but current fragment has "
+ "zero size, accepting anyway");
+ }
+ }
+#if 0
+ if (this_fragment->mo_offset + this_payload_len > first_fragment->mo_size) {
+ GST_WARNING ("Merged fragments would be bigger than the media object");
+ return FALSE;
+ }
+#endif
+
+ return ret;
+}
+
+/* TODO: if we have another payload already queued for this stream and that
+ * payload doesn't have a duration, maybe we can calculate a duration for it
+ * (if the previous timestamp is smaller etc. etc.) */
+static void
+gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload,
+ AsfStream * stream)
+{
+ GST_DEBUG_OBJECT (demux, "Got payload for stream %d ts:%" GST_TIME_FORMAT,
+ stream->id, GST_TIME_ARGS (payload->ts));
+
+ /* make timestamps start from 0; first_ts will be determined during activation (once we have enough data),
+ which will also update ts of all packets queued before we knew first_ts; */
+ if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (demux->first_ts)
+ && GST_CLOCK_TIME_IS_VALID (payload->ts))) {
+ if (payload->ts > demux->first_ts)
+ payload->ts -= demux->first_ts;
+ else
+ payload->ts = 0;
+ }
+
+ /* remove any incomplete payloads that will never be completed */
+ while (stream->payloads->len > 0) {
+ AsfPayload *prev;
+ guint idx_last;
+
+ idx_last = stream->payloads->len - 1;
+ prev = &g_array_index (stream->payloads, AsfPayload, idx_last);
+
+ if (G_UNLIKELY (gst_asf_payload_is_complete (prev)))
+ break;
+
+ GST_DEBUG_OBJECT (demux, "Dropping incomplete fragmented media object "
+ "queued for stream %u", stream->id);
+
+ gst_buffer_replace (&prev->buf, NULL);
+ g_array_remove_index (stream->payloads, idx_last);
+
+ /* there's data missing, so there's a discontinuity now */
+ GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+ }
+
+ /* If we're about to queue a key frame that is before the segment start, we
+ * can ditch any previously queued payloads (which would also be before the
+ * segment start). This makes sure the decoder doesn't decode more than
+ * absolutely necessary after a seek (we don't push out payloads that are
+ * before the segment start until we have at least one that falls within the
+ * segment) */
+ if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+ payload->ts < demux->segment.start && payload->keyframe)) {
+ GST_DEBUG_OBJECT (demux, "Queueing keyframe before segment start, removing"
+ " %u previously-queued payloads, which would be out of segment too and"
+ " hence don't have to be decoded", stream->payloads->len);
+ while (stream->payloads->len > 0) {
+ AsfPayload *last;
+ guint idx_last;
+
+ idx_last = stream->payloads->len - 1;
+ last = &g_array_index (stream->payloads, AsfPayload, idx_last);
+ gst_buffer_replace (&last->buf, NULL);
+ g_array_remove_index (stream->payloads, idx_last);
+ }
+
+ /* Mark discontinuity (should be done via stream->discont anyway though) */
+ GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+ }
+
+ g_array_append_vals (stream->payloads, payload, 1);
+}
+
+static void
+asf_payload_parse_replicated_data_extensions (AsfStream * stream,
+ AsfPayload * payload)
+{
+ AsfPayloadExtension *ext;
+ guint off;
+ guint16 ext_len;
+
+ if (!stream->ext_props.valid || stream->ext_props.payload_extensions == NULL)
+ return;
+
+ off = 8;
+ for (ext = stream->ext_props.payload_extensions; ext->len > 0; ++ext) {
+ ext_len = ext->len;
+ if (ext_len == 0xFFFF) { /* extension length is determined by first two bytes in replicated data */
+ ext_len = GST_READ_UINT16_LE (payload->rep_data + off);
+ off += 2;
+ }
+ if (G_UNLIKELY (off + ext_len > payload->rep_data_len)) {
+ GST_WARNING ("not enough replicated data for defined extensions");
+ return;
+ }
+ switch (ext->id) {
+ case ASF_PAYLOAD_EXTENSION_DURATION:
+ if (G_LIKELY (ext_len == 2)) {
+ guint16 tdur = GST_READ_UINT16_LE (payload->rep_data + off);
+ /* packet durations of 1ms are mostly invalid */
+ if (tdur != 1)
+ payload->duration = tdur * GST_MSECOND;
+ } else {
+ GST_WARNING ("unexpected DURATION extensions len %u", ext_len);
+ }
+ break;
+ case ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT:
+ if (G_LIKELY (ext_len == 1)) {
+ guint8 data = payload->rep_data[off];
+
+ payload->interlaced = data & 0x1;
+ payload->rff = data & 0x8;
+ payload->tff = (data & 0x2) || !(data & 0x4);
+ GST_DEBUG ("SYSTEM_CONTENT: interlaced:%d, rff:%d, tff:%d",
+ payload->interlaced, payload->rff, payload->tff);
+ } else {
+ GST_WARNING ("unexpected SYSTEM_CONTE extensions len %u", ext_len);
+ }
+ break;
+ case ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO:
+ if (G_LIKELY (ext_len == 2)) {
+ payload->par_x = payload->rep_data[off];
+ payload->par_y = payload->rep_data[off + 1];
+ GST_DEBUG ("PAR %d / %d", payload->par_x, payload->par_y);
+ } else {
+ GST_WARNING ("unexpected SYSTEM_PIXEL_ASPECT_RATIO extensions len %u",
+ ext_len);
+ }
+ break;
+ case ASF_PAYLOAD_EXTENSION_TIMING:
+ {
+ /* dvr-ms timing - this will override packet timestamp */
+ guint64 time = GST_READ_UINT64_LE (payload->rep_data + off + 8);
+ if (time != 0xFFFFFFFFFFFFFFFF)
+ payload->ts = time * 100;
+ else
+ payload->ts = GST_CLOCK_TIME_NONE;
+ }
+ break;
+ default:
+ GST_LOG ("UNKNOWN PAYLOAD EXTENSION!");
+ break;
+ }
+ off += ext_len;
+ }
+}
+
+static gboolean
+gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet,
+ gint lentype, const guint8 ** p_data, guint * p_size)
+{
+ AsfPayload payload = { 0, };
+ AsfStream *stream;
+ gboolean is_compressed;
+ guint payload_len;
+ guint stream_num;
+
+ if (G_UNLIKELY (*p_size < 1)) {
+ GST_WARNING_OBJECT (demux, "Short packet!");
+ return FALSE;
+ }
+
+ stream_num = GST_READ_UINT8 (*p_data) & 0x7f;
+ payload.keyframe = ((GST_READ_UINT8 (*p_data) & 0x80) != 0);
+
+ *p_data += 1;
+ *p_size -= 1;
+
+ payload.ts = GST_CLOCK_TIME_NONE;
+ payload.duration = GST_CLOCK_TIME_NONE;
+ payload.par_x = 0;
+ payload.par_y = 0;
+ payload.interlaced = FALSE;
+ payload.tff = FALSE;
+ payload.rff = FALSE;
+
+ payload.mo_number =
+ asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size);
+ payload.mo_offset =
+ asf_packet_read_varlen_int (packet->prop_flags, 2, p_data, p_size);
+ payload.rep_data_len =
+ asf_packet_read_varlen_int (packet->prop_flags, 0, p_data, p_size);
+
+ is_compressed = (payload.rep_data_len == 1);
+
+ GST_LOG_OBJECT (demux, "payload for stream %u", stream_num);
+ GST_LOG_OBJECT (demux, "keyframe : %s", (payload.keyframe) ? "yes" : "no");
+ GST_LOG_OBJECT (demux, "compressed : %s", (is_compressed) ? "yes" : "no");
+
+ if (G_UNLIKELY (*p_size < payload.rep_data_len)) {
+ GST_WARNING_OBJECT (demux, "Short packet! rep_data_len=%u, size=%u",
+ payload.rep_data_len, *p_size);
+ return FALSE;
+ }
+
+ memcpy (payload.rep_data, *p_data,
+ MIN (sizeof (payload.rep_data), payload.rep_data_len));
+
+ *p_data += payload.rep_data_len;
+ *p_size -= payload.rep_data_len;
+
+ if (G_UNLIKELY (*p_size == 0)) {
+ GST_WARNING_OBJECT (demux, "payload without data!?");
+ return FALSE;
+ }
+
+ /* we use -1 as lentype for a single payload that's the size of the packet */
+ if (G_UNLIKELY ((lentype >= 0 && lentype <= 3))) {
+ payload_len = asf_packet_read_varlen_int (lentype, 0, p_data, p_size);
+ if (*p_size < payload_len) {
+ GST_WARNING_OBJECT (demux, "Short packet! payload_len=%u, size=%u",
+ payload_len, *p_size);
+ return FALSE;
+ }
+ } else {
+ payload_len = *p_size;
+ }
+
+ GST_LOG_OBJECT (demux, "payload length: %u", payload_len);
+
+ stream = gst_asf_demux_get_stream (demux, stream_num);
+
+ if (G_UNLIKELY (stream == NULL)) {
+ if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
+ GST_WARNING_OBJECT (demux, "Payload for unknown stream %u, skipping",
+ stream_num);
+ }
+ if (*p_size < payload_len) {
+ *p_data += *p_size;
+ *p_size = 0;
+ } else {
+ *p_data += payload_len;
+ *p_size -= payload_len;
+ }
+ return TRUE;
+ }
+
+ if (G_UNLIKELY (!is_compressed)) {
+ GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len);
+
+ if (payload.rep_data_len >= 8) {
+ payload.mo_size = GST_READ_UINT32_LE (payload.rep_data);
+ payload.ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND;
+ if (G_UNLIKELY (payload.ts < demux->preroll))
+ payload.ts = 0;
+ else
+ payload.ts -= demux->preroll;
+ asf_payload_parse_replicated_data_extensions (stream, &payload);
+
+ GST_LOG_OBJECT (demux, "media object size : %u", payload.mo_size);
+ GST_LOG_OBJECT (demux, "media object ts : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (payload.ts));
+ GST_LOG_OBJECT (demux, "media object dur : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (payload.duration));
+ } else if (payload.rep_data_len == 0) {
+ payload.mo_size = 0;
+ } else if (payload.rep_data_len != 0) {
+ GST_WARNING_OBJECT (demux, "invalid replicated data length, very bad");
+ *p_data += payload_len;
+ *p_size -= payload_len;
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (demux, "media object offset : %u", payload.mo_offset);
+
+ GST_LOG_OBJECT (demux, "payload length: %u", payload_len);
+
+ if (payload_len == 0) {
+ GST_DEBUG_OBJECT (demux, "skipping empty payload");
+ } else if (payload.mo_offset == 0 && payload.mo_size == payload_len) {
+ /* if the media object is not fragmented, just create a sub-buffer */
+ GST_LOG_OBJECT (demux, "unfragmented media object size %u", payload_len);
+ payload.buf = asf_packet_create_payload_buffer (packet, p_data, p_size,
+ payload_len);
+ payload.buf_filled = payload_len;
+ gst_asf_payload_queue_for_stream (demux, &payload, stream);
+ } else {
+ const guint8 *payload_data = *p_data;
+
+ g_assert (payload_len <= *p_size);
+
+ *p_data += payload_len;
+ *p_size -= payload_len;
+
+ /* n-th fragment of a fragmented media object? */
+ if (payload.mo_offset != 0) {
+ AsfPayload *prev;
+
+ if ((prev = asf_payload_find_previous_fragment (&payload, stream))) {
+ if (prev->buf == NULL || (payload.mo_size > 0
+ && payload.mo_size != prev->mo_size)
+ || payload.mo_offset >= gst_buffer_get_size (prev->buf)
+ || payload.mo_offset + payload_len >
+ gst_buffer_get_size (prev->buf)) {
+ GST_WARNING_OBJECT (demux, "Offset doesn't match previous data?!");
+ } else {
+ /* we assume fragments are payloaded with increasing mo_offset */
+ if (payload.mo_offset != prev->buf_filled) {
+ GST_WARNING_OBJECT (demux, "media object payload discontinuity: "
+ "offset=%u vs buf_filled=%u", payload.mo_offset,
+ prev->buf_filled);
+ }
+ gst_buffer_fill (prev->buf, payload.mo_offset,
+ payload_data, payload_len);
+ prev->buf_filled =
+ MAX (prev->buf_filled, payload.mo_offset + payload_len);
+ GST_LOG_OBJECT (demux, "Merged media object fragments, size now %u",
+ prev->buf_filled);
+ }
+ } else {
+ GST_DEBUG_OBJECT (demux, "n-th payload fragment, but don't have "
+ "any previous fragment, ignoring payload");
+ }
+ } else {
+ GST_LOG_OBJECT (demux, "allocating buffer of size %u for fragmented "
+ "media object", payload.mo_size);
+ payload.buf = gst_buffer_new_allocate (NULL, payload.mo_size, NULL);
+ gst_buffer_fill (payload.buf, 0, payload_data, payload_len);
+ payload.buf_filled = payload_len;
+
+ gst_asf_payload_queue_for_stream (demux, &payload, stream);
+ }
+ }
+ } else {
+ const guint8 *payload_data;
+ GstClockTime ts, ts_delta;
+ guint num;
+
+ GST_LOG_OBJECT (demux, "Compressed payload, length=%u", payload_len);
+
+ payload_data = *p_data;
+
+ *p_data += payload_len;
+ *p_size -= payload_len;
+
+ ts = payload.mo_offset * GST_MSECOND;
+ if (G_UNLIKELY (ts < demux->preroll))
+ ts = 0;
+ else
+ ts -= demux->preroll;
+ ts_delta = payload.rep_data[0] * GST_MSECOND;
+
+ for (num = 0; payload_len > 0; ++num) {
+ guint sub_payload_len;
+
+ sub_payload_len = GST_READ_UINT8 (payload_data);
+
+ GST_LOG_OBJECT (demux, "subpayload #%u: len=%u, ts=%" GST_TIME_FORMAT,
+ num, sub_payload_len, GST_TIME_ARGS (ts));
+
+ ++payload_data;
+ --payload_len;
+
+ if (G_UNLIKELY (payload_len < sub_payload_len)) {
+ GST_WARNING_OBJECT (demux, "Short payload! %u bytes left", payload_len);
+ return FALSE;
+ }
+
+ if (G_LIKELY (sub_payload_len > 0)) {
+ payload.buf = asf_packet_create_payload_buffer (packet,
+ &payload_data, &payload_len, sub_payload_len);
+ payload.buf_filled = sub_payload_len;
+
+ payload.ts = ts;
+ if (G_LIKELY (ts_delta))
+ payload.duration = ts_delta;
+ else
+ payload.duration = GST_CLOCK_TIME_NONE;
+
+ gst_asf_payload_queue_for_stream (demux, &payload, stream);
+ }
+
+ ts += ts_delta;
+ }
+ }
+
+ return TRUE;
+}
+
+GstAsfDemuxParsePacketError
+gst_asf_demux_parse_packet (GstASFDemux * demux, GstBuffer * buf)
+{
+ AsfPacket packet = { 0, };
+ GstMapInfo map;
+ const guint8 *data;
+ gboolean has_multiple_payloads;
+ GstAsfDemuxParsePacketError ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE;
+ guint8 ec_flags, flags1;
+ guint size;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+ GST_LOG_OBJECT (demux, "Buffer size: %u", size);
+
+ /* need at least two payload flag bytes, send time, and duration */
+ if (G_UNLIKELY (size < 2 + 4 + 2)) {
+ GST_WARNING_OBJECT (demux, "Packet size is < 8");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
+ goto done;
+ }
+
+ packet.buf = buf;
+ /* evidently transient */
+ packet.bdata = data;
+
+ ec_flags = GST_READ_UINT8 (data);
+
+ /* skip optional error correction stuff */
+ if ((ec_flags & 0x80) != 0) {
+ guint ec_len_type, ec_len;
+
+ ec_len_type = (ec_flags & 0x60) >> 5;
+ if (ec_len_type == 0) {
+ ec_len = ec_flags & 0x0f;
+ } else {
+ GST_WARNING_OBJECT (demux, "unexpected error correction length type %u",
+ ec_len_type);
+ ec_len = 2;
+ }
+ GST_LOG_OBJECT (demux, "packet has error correction (%u bytes)", ec_len);
+
+ /* still need at least two payload flag bytes, send time, and duration */
+ if (size <= (1 + ec_len) + 2 + 4 + 2) {
+ GST_WARNING_OBJECT (demux, "Packet size is < 8 with Error Correction");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL;
+ goto done;
+ }
+
+ data += 1 + ec_len;
+ size -= 1 + ec_len;
+ }
+
+ /* parse payload info */
+ flags1 = GST_READ_UINT8 (data);
+ packet.prop_flags = GST_READ_UINT8 (data + 1);
+
+ data += 2;
+ size -= 2;
+
+ has_multiple_payloads = (flags1 & 0x01) != 0;
+
+ packet.length = asf_packet_read_varlen_int (flags1, 5, &data, &size);
+
+ packet.sequence = asf_packet_read_varlen_int (flags1, 1, &data, &size);
+
+ packet.padding = asf_packet_read_varlen_int (flags1, 3, &data, &size);
+
+ if (G_UNLIKELY (size < 6)) {
+ GST_WARNING_OBJECT (demux, "Packet size is < 6");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL;
+ goto done;
+ }
+
+ packet.send_time = GST_READ_UINT32_LE (data) * GST_MSECOND;
+ packet.duration = GST_READ_UINT16_LE (data + 4) * GST_MSECOND;
+
+ data += 4 + 2;
+ size -= 4 + 2;
+
+ GST_LOG_OBJECT (demux, "flags : 0x%x", flags1);
+ GST_LOG_OBJECT (demux, "multiple payloads: %u", has_multiple_payloads);
+ GST_LOG_OBJECT (demux, "packet length : %u", packet.length);
+ GST_LOG_OBJECT (demux, "sequence : %u", packet.sequence);
+ GST_LOG_OBJECT (demux, "padding : %u", packet.padding);
+ GST_LOG_OBJECT (demux, "send time : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (packet.send_time));
+ GST_LOG_OBJECT (demux, "duration : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (packet.duration));
+
+ if (G_UNLIKELY (packet.padding == (guint) - 1 || size < packet.padding)) {
+ GST_WARNING_OBJECT (demux, "No padding, or padding bigger than buffer");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
+ goto done;
+ }
+
+ size -= packet.padding;
+
+ /* adjust available size for parsing if there's less actual packet data for
+ * parsing than there is data in bytes (for sample see bug 431318) */
+ if (G_UNLIKELY (packet.length != 0 && packet.padding == 0
+ && packet.length < demux->packet_size)) {
+ GST_LOG_OBJECT (demux, "shortened packet with implicit padding, "
+ "adjusting available data size");
+ if (size < demux->packet_size - packet.length) {
+ /* the buffer is smaller than the implicit padding */
+ GST_WARNING_OBJECT (demux, "Buffer is smaller than the implicit padding");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
+ goto done;
+ } else {
+ /* subtract the implicit padding */
+ size -= (demux->packet_size - packet.length);
+ }
+ }
+
+ if (has_multiple_payloads) {
+ guint i, num, lentype;
+
+ if (G_UNLIKELY (size < 1)) {
+ GST_WARNING_OBJECT (demux, "No room more in buffer");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
+ goto done;
+ }
+
+ num = (GST_READ_UINT8 (data) & 0x3F) >> 0;
+ lentype = (GST_READ_UINT8 (data) & 0xC0) >> 6;
+
+ ++data;
+ --size;
+
+ GST_LOG_OBJECT (demux, "num payloads : %u", num);
+
+ for (i = 0; i < num; ++i) {
+ GST_LOG_OBJECT (demux, "Parsing payload %u/%u, size left: %u", i + 1, num,
+ size);
+
+ if (G_UNLIKELY (!gst_asf_demux_parse_payload (demux, &packet, lentype,
+ &data, &size))) {
+ GST_WARNING_OBJECT (demux, "Failed to parse payload %u/%u", i + 1, num);
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL;
+ break;
+ }
+ }
+ } else {
+ GST_LOG_OBJECT (demux, "Parsing single payload");
+ if (G_UNLIKELY (!gst_asf_demux_parse_payload (demux, &packet, -1, &data,
+ &size))) {
+ GST_WARNING_OBJECT (demux, "Failed to parse payload");
+ ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
+ }
+ }
+
+done:
+ gst_buffer_unmap (buf, &map);
+ return ret;
+}
diff --git a/gst/asfdemux/asfpacket.h b/gst/asfdemux/asfpacket.h
new file mode 100644
index 0000000..a812e74
--- /dev/null
+++ b/gst/asfdemux/asfpacket.h
@@ -0,0 +1,74 @@
+/* GStreamer ASF/WMV/WMA demuxer
+ * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ASF_PACKET_H__
+#define __ASF_PACKET_H__
+
+#include <gst/gstbuffer.h>
+#include <gst/gstclock.h>
+
+#include "gstasfdemux.h"
+
+G_BEGIN_DECLS
+
+typedef struct {
+ gboolean keyframe; /* buffer flags might not survive merge.. */
+ guint mo_number; /* media object number (unused) */
+ guint mo_offset; /* offset (timestamp for compressed data) */
+ guint mo_size; /* size of media-object-to-be, or 0 */
+ guint buf_filled; /* how much of the mo data we got so far */
+ GstBuffer *buf; /* buffer to assemble media-object or NULL*/
+ guint rep_data_len; /* should never be more than 256, since */
+ guint8 rep_data[256]; /* the length should be stored in a byte */
+ GstClockTime ts;
+ GstClockTime duration; /* is not always available */
+ guint8 par_x; /* not always available (0:deactivated) */
+ guint8 par_y; /* not always available (0:deactivated) */
+ gboolean interlaced; /* default: FALSE */
+ gboolean tff;
+ gboolean rff;
+} AsfPayload;
+
+typedef struct {
+ GstBuffer *buf;
+ const guint8 *bdata;
+ guint length; /* packet length (unused) */
+ guint padding; /* length of padding at end of packet */
+ guint sequence; /* sequence (unused) */
+ GstClockTime send_time;
+ GstClockTime duration;
+
+ guint8 prop_flags; /* payload length types */
+} AsfPacket;
+
+typedef enum {
+ GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE,
+ GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE,
+ GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL
+} GstAsfDemuxParsePacketError;
+
+GstAsfDemuxParsePacketError gst_asf_demux_parse_packet (GstASFDemux * demux, GstBuffer * buf);
+
+#define gst_asf_payload_is_complete(payload) \
+ ((payload)->buf_filled >= (payload)->mo_size)
+
+G_END_DECLS
+
+#endif /* __ASF_PACKET_H__ */
+
diff --git a/gst/asfdemux/gstasf.c b/gst/asfdemux/gstasf.c
new file mode 100644
index 0000000..01d289f
--- /dev/null
+++ b/gst/asfdemux/gstasf.c
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/riff/riff-read.h>
+#include "gst/gst-i18n-plugin.h"
+
+#include "gstasfdemux.h"
+#include "gstrtspwms.h"
+#include "gstrtpasfdepay.h"
+
+/* #include "gstasfmux.h" */
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (asfdemux_dbg, "asfdemux", 0, "asf demuxer element");
+
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ gst_riff_init ();
+
+ if (!gst_element_register (plugin, "asfdemux", GST_RANK_SECONDARY,
+ GST_TYPE_ASF_DEMUX)) {
+ return FALSE;
+ }
+ if (!gst_element_register (plugin, "rtspwms", GST_RANK_SECONDARY,
+ GST_TYPE_RTSP_WMS)) {
+ return FALSE;
+ }
+ if (!gst_element_register (plugin, "rtpasfdepay", GST_RANK_MARGINAL,
+ GST_TYPE_RTP_ASF_DEPAY)) {
+ return FALSE;
+ }
+/*
+ if (!gst_element_register (plugin, "asfmux", GST_RANK_NONE, GST_TYPE_ASFMUX))
+ return FALSE;
+*/
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ asf,
+ "Demuxes and muxes audio and video in Microsofts ASF format",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c
new file mode 100644
index 0000000..1794380
--- /dev/null
+++ b/gst/asfdemux/gstasfdemux.c
@@ -0,0 +1,4367 @@
+/* GStreamer ASF/WMV/WMA demuxer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* TODO:
+ *
+ * - _loop():
+ * stop if at end of segment if != end of file, ie. demux->segment.stop
+ *
+ * - fix packet parsing:
+ * there's something wrong with timestamps for packets with keyframes,
+ * and durations too.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gstutils.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gsttypefindhelper.h>
+#include <gst/riff/riff-media.h>
+#include <gst/tag/tag.h>
+#include <gst/gst-i18n-plugin.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstasfdemux.h"
+#include "asfheaders.h"
+#include "asfpacket.h"
+
+static GstStaticPadTemplate gst_asf_demux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-ms-asf")
+ );
+
+static GstStaticPadTemplate audio_src_template =
+GST_STATIC_PAD_TEMPLATE ("audio_%u",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate video_src_template =
+GST_STATIC_PAD_TEMPLATE ("video_%u",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+/* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
+#define ASF_OBJECT_HEADER_SIZE (16+8)
+
+/* FIXME: get rid of this */
+/* abuse this GstFlowReturn enum for internal usage */
+#define ASF_FLOW_NEED_MORE_DATA 99
+
+#define gst_asf_get_flow_name(flow) \
+ (flow == ASF_FLOW_NEED_MORE_DATA) ? \
+ "need-more-data" : gst_flow_get_name (flow)
+
+GST_DEBUG_CATEGORY (asfdemux_dbg);
+
+static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
+ GstStateChange transition);
+static gboolean gst_asf_demux_element_send_event (GstElement * element,
+ GstEvent * event);
+static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
+ GstEvent * event);
+static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
+ GstObject * parent, GstQuery * query);
+static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buf);
+static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
+ guint8 ** p_data, guint64 * p_size);
+static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
+static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
+ GstObject * parent, GstPadMode mode, gboolean active);
+static void gst_asf_demux_loop (GstASFDemux * demux);
+static void
+gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
+static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
+static void gst_asf_demux_pull_indices (GstASFDemux * demux);
+static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
+static gboolean
+gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
+static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
+ AsfStream * stream, GstBuffer ** p_buffer);
+static void gst_asf_demux_activate_stream (GstASFDemux * demux,
+ AsfStream * stream);
+static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
+ guint stream_num);
+static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
+ gboolean force);
+
+#define gst_asf_demux_parent_class parent_class
+G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
+
+static void
+gst_asf_demux_class_init (GstASFDemuxClass * klass)
+{
+ GstElementClass *gstelement_class;
+
+ gstelement_class = (GstElementClass *) klass;
+
+ gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
+ "Codec/Demuxer",
+ "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&audio_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&video_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_asf_demux_sink_template));
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
+ gstelement_class->send_event =
+ GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
+}
+
+static void
+gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
+{
+ gst_caps_replace (&stream->caps, NULL);
+ if (stream->pending_tags) {
+ gst_tag_list_unref (stream->pending_tags);
+ stream->pending_tags = NULL;
+ }
+ if (stream->pad) {
+ if (stream->active) {
+ gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
+ gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
+ } else
+ gst_object_unref (stream->pad);
+ stream->pad = NULL;
+ }
+
+ if (stream->payloads) {
+ while (stream->payloads->len > 0) {
+ AsfPayload *payload;
+ guint last;
+
+ last = stream->payloads->len - 1;
+ payload = &g_array_index (stream->payloads, AsfPayload, last);
+ gst_buffer_replace (&payload->buf, NULL);
+ g_array_remove_index (stream->payloads, last);
+ }
+ g_array_free (stream->payloads, TRUE);
+ stream->payloads = NULL;
+ }
+ if (stream->ext_props.valid) {
+ g_free (stream->ext_props.payload_extensions);
+ stream->ext_props.payload_extensions = NULL;
+ }
+}
+
+static void
+gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
+{
+ GST_LOG_OBJECT (demux, "resetting");
+
+ gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
+ demux->segment_running = FALSE;
+ if (demux->adapter && !chain_reset) {
+ gst_adapter_clear (demux->adapter);
+ g_object_unref (demux->adapter);
+ demux->adapter = NULL;
+ }
+ if (demux->taglist) {
+ gst_tag_list_unref (demux->taglist);
+ demux->taglist = NULL;
+ }
+ if (demux->metadata) {
+ gst_caps_unref (demux->metadata);
+ demux->metadata = NULL;
+ }
+ if (demux->global_metadata) {
+ gst_structure_free (demux->global_metadata);
+ demux->global_metadata = NULL;
+ }
+
+ demux->state = GST_ASF_DEMUX_STATE_HEADER;
+ g_free (demux->objpath);
+ demux->objpath = NULL;
+ g_strfreev (demux->languages);
+ demux->languages = NULL;
+ demux->num_languages = 0;
+ g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
+ NULL);
+ g_slist_free (demux->ext_stream_props);
+ demux->ext_stream_props = NULL;
+
+ while (demux->old_num_streams > 0) {
+ gst_asf_demux_free_stream (demux,
+ &demux->old_stream[demux->old_num_streams - 1]);
+ --demux->old_num_streams;
+ }
+ memset (demux->old_stream, 0, sizeof (demux->old_stream));
+ demux->old_num_streams = 0;
+
+ /* when resetting for a new chained asf, we don't want to remove the pads
+ * before adding the new ones */
+ if (chain_reset) {
+ memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
+ demux->old_num_streams = demux->num_streams;
+ demux->num_streams = 0;
+ }
+
+ while (demux->num_streams > 0) {
+ gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
+ --demux->num_streams;
+ }
+ memset (demux->stream, 0, sizeof (demux->stream));
+ if (!chain_reset) {
+ /* do not remove those for not adding pads with same name */
+ demux->num_audio_streams = 0;
+ demux->num_video_streams = 0;
+ demux->have_group_id = FALSE;
+ demux->group_id = G_MAXUINT;
+ }
+ demux->num_streams = 0;
+ demux->activated_streams = FALSE;
+ demux->first_ts = GST_CLOCK_TIME_NONE;
+ demux->segment_ts = GST_CLOCK_TIME_NONE;
+ demux->in_gap = 0;
+ if (!chain_reset)
+ gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
+ demux->state = GST_ASF_DEMUX_STATE_HEADER;
+ demux->seekable = FALSE;
+ demux->broadcast = FALSE;
+ demux->sidx_interval = 0;
+ demux->sidx_num_entries = 0;
+ g_free (demux->sidx_entries);
+ demux->sidx_entries = NULL;
+
+ demux->speed_packets = 1;
+
+ if (chain_reset) {
+ GST_LOG_OBJECT (demux, "Restarting");
+ gst_segment_init (&demux->segment, GST_FORMAT_TIME);
+ demux->need_newsegment = TRUE;
+ demux->segment_seqnum = 0;
+ demux->segment_running = FALSE;
+ demux->accurate = FALSE;
+ demux->metadata = gst_caps_new_empty ();
+ demux->global_metadata = gst_structure_new_empty ("metadata");
+ demux->data_size = 0;
+ demux->data_offset = 0;
+ demux->index_offset = 0;
+ } else {
+ demux->base_offset = 0;
+ }
+
+ g_slist_free (demux->other_streams);
+ demux->other_streams = NULL;
+}
+
+static void
+gst_asf_demux_init (GstASFDemux * demux)
+{
+ demux->sinkpad =
+ gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
+ gst_pad_set_chain_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
+ gst_pad_set_event_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
+ gst_pad_set_activate_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
+ gst_pad_set_activatemode_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
+ gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
+
+ /* set initial state */
+ gst_asf_demux_reset (demux, FALSE);
+}
+
+static gboolean
+gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
+{
+ GstQuery *query;
+ gboolean pull_mode;
+
+ query = gst_query_new_scheduling ();
+
+ if (!gst_pad_peer_query (sinkpad, query)) {
+ gst_query_unref (query);
+ goto activate_push;
+ }
+
+ pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+ GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+ gst_query_unref (query);
+
+ if (!pull_mode)
+ goto activate_push;
+
+ GST_DEBUG_OBJECT (sinkpad, "activating pull");
+ return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+ {
+ GST_DEBUG_OBJECT (sinkpad, "activating push");
+ return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+ }
+}
+
+static gboolean
+gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
+ GstPadMode mode, gboolean active)
+{
+ gboolean res;
+ GstASFDemux *demux;
+
+ demux = GST_ASF_DEMUX (parent);
+
+ switch (mode) {
+ case GST_PAD_MODE_PUSH:
+ demux->state = GST_ASF_DEMUX_STATE_HEADER;
+ demux->streaming = TRUE;
+ res = TRUE;
+ break;
+ case GST_PAD_MODE_PULL:
+ if (active) {
+ demux->state = GST_ASF_DEMUX_STATE_HEADER;
+ demux->streaming = FALSE;
+
+ res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
+ demux, NULL);
+ } else {
+ res = gst_pad_stop_task (sinkpad);
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
+static gboolean
+gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstASFDemux *demux;
+ gboolean ret = TRUE;
+
+ demux = GST_ASF_DEMUX (parent);
+
+ GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:{
+ const GstSegment *segment;
+
+ gst_event_parse_segment (event, &segment);
+
+ if (segment->format == GST_FORMAT_BYTES) {
+ if (demux->packet_size && segment->start > demux->data_offset)
+ demux->packet = (segment->start - demux->data_offset) /
+ demux->packet_size;
+ else
+ demux->packet = 0;
+ } else if (segment->format == GST_FORMAT_TIME) {
+ /* do not know packet position, not really a problem */
+ demux->packet = -1;
+ } else {
+ GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
+ gst_event_unref (event);
+ break;
+ }
+
+ /* record upstream segment for interpolation */
+ if (segment->format != demux->in_segment.format)
+ gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
+ gst_segment_copy_into (segment, &demux->in_segment);
+
+ /* in either case, clear some state and generate newsegment later on */
+ GST_OBJECT_LOCK (demux);
+ demux->segment_ts = GST_CLOCK_TIME_NONE;
+ demux->in_gap = GST_CLOCK_TIME_NONE;
+ demux->need_newsegment = TRUE;
+ demux->segment_seqnum = gst_event_get_seqnum (event);
+ gst_asf_demux_reset_stream_state_after_discont (demux);
+ GST_OBJECT_UNLOCK (demux);
+
+ gst_event_unref (event);
+ break;
+ }
+ case GST_EVENT_EOS:{
+ GstFlowReturn flow;
+
+ if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
+ (_("This stream contains no data.")),
+ ("got eos and didn't receive a complete header object"));
+ break;
+ }
+ flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
+ if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
+ GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+ (_("Internal data stream error.")),
+ ("streaming stopped, reason %s", gst_flow_get_name (flow)));
+ break;
+ }
+
+ GST_OBJECT_LOCK (demux);
+ gst_adapter_clear (demux->adapter);
+ GST_OBJECT_UNLOCK (demux);
+ gst_asf_demux_send_event_unlocked (demux, event);
+ break;
+ }
+
+ case GST_EVENT_FLUSH_STOP:
+ GST_OBJECT_LOCK (demux);
+ gst_asf_demux_reset_stream_state_after_discont (demux);
+ GST_OBJECT_UNLOCK (demux);
+ gst_asf_demux_send_event_unlocked (demux, event);
+ /* upon activation, latency is no longer introduced, e.g. after seek */
+ if (demux->activated_streams)
+ demux->latency = 0;
+ break;
+
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
+ GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
+ gboolean next, gboolean * eos)
+{
+ GstClockTime idx_time;
+ guint idx;
+
+ if (eos)
+ *eos = FALSE;
+
+ if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
+ return FALSE;
+
+ idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
+
+ if (next) {
+ /* if we want the next keyframe, we have to go forward till we find
+ a different packet number */
+ guint idx2 = idx;
+ if (idx >= demux->sidx_num_entries - 1) {
+ /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
+ if (eos)
+ *eos = TRUE;
+ return FALSE;
+ }
+ for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
+ if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
+ idx = idx2;
+ break;
+ }
+ }
+ }
+
+ if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
+ if (eos)
+ *eos = TRUE;
+ return FALSE;
+ }
+
+ *packet = demux->sidx_entries[idx].packet;
+ if (speed)
+ *speed = demux->sidx_entries[idx].count;
+
+ /* so we get closer to the actual time of the packet ... actually, let's not
+ * do this, since we throw away superfluous payloads before the seek position
+ * anyway; this way, our key unit seek 'snap resolution' is a bit better
+ * (ie. same as index resolution) */
+ /*
+ while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
+ --idx;
+ */
+
+ idx_time = demux->sidx_interval * idx;
+ if (G_LIKELY (idx_time >= demux->preroll))
+ idx_time -= demux->preroll;
+
+ GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
+ GST_TIME_ARGS (idx_time));
+
+ if (G_LIKELY (p_idx_time))
+ *p_idx_time = idx_time;
+
+ return TRUE;
+}
+
+static void
+gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
+{
+ guint n;
+
+ gst_adapter_clear (demux->adapter);
+
+ GST_DEBUG_OBJECT (demux, "reset stream state");
+
+ for (n = 0; n < demux->num_streams; n++) {
+ demux->stream[n].discont = TRUE;
+
+ while (demux->stream[n].payloads->len > 0) {
+ AsfPayload *payload;
+ guint last;
+
+ last = demux->stream[n].payloads->len - 1;
+ payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
+ gst_buffer_replace (&payload->buf, NULL);
+ g_array_remove_index (demux->stream[n].payloads, last);
+ }
+ }
+}
+
+static void
+gst_asf_demux_mark_discont (GstASFDemux * demux)
+{
+ guint n;
+
+ GST_DEBUG_OBJECT (demux, "Mark stream discont");
+
+ for (n = 0; n < demux->num_streams; n++)
+ demux->stream[n].discont = TRUE;
+}
+
+/* do a seek in push based mode */
+static gboolean
+gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
+{
+ gdouble rate;
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
+ guint packet;
+ gboolean res;
+ GstEvent *byte_event;
+
+ gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+ &stop_type, &stop);
+
+ stop_type = GST_SEEK_TYPE_NONE;
+ stop = -1;
+
+ GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
+
+ /* determine packet, by index or by estimation */
+ if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
+ NULL)) {
+ packet =
+ (guint) gst_util_uint64_scale (demux->num_packets, cur,
+ demux->play_time);
+ }
+
+ if (packet > demux->num_packets) {
+ GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
+ "seek aborted.");
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
+
+ cur = demux->data_offset + (packet * demux->packet_size);
+
+ GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
+ "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
+ /* BYTE seek event */
+ byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
+ cur, stop_type, stop);
+ gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
+ res = gst_pad_push_event (demux->sinkpad, byte_event);
+
+ return res;
+}
+
+static gboolean
+gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
+{
+ GstClockTime idx_time;
+ GstSegment segment;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ GstFormat format;
+ gboolean only_need_update;
+ gboolean keyunit_sync, after, before, next;
+ gboolean flush;
+ gdouble rate;
+ gint64 cur, stop;
+ gint64 seek_time;
+ guint packet, speed_count = 1;
+ gboolean eos;
+ guint32 seqnum;
+ GstEvent *fevent;
+
+ if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
+ demux->num_packets == 0 || demux->play_time == 0)) {
+ GST_LOG_OBJECT (demux, "stream is not seekable");
+ return FALSE;
+ }
+
+ if (G_UNLIKELY (!demux->activated_streams)) {
+ GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
+ return FALSE;
+ }
+
+ gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+ &stop_type, &stop);
+ seqnum = gst_event_get_seqnum (event);
+
+ if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
+ GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
+ return FALSE;
+ }
+
+ if (G_UNLIKELY (rate <= 0.0)) {
+ GST_LOG_OBJECT (demux, "backward playback is not supported yet");
+ return FALSE;
+ }
+
+ flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
+ demux->accurate =
+ ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
+ keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
+ after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
+ before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
+ next = after && !before;
+
+ if (G_UNLIKELY (demux->streaming)) {
+ /* support it safely needs more segment handling, e.g. closing etc */
+ if (!flush) {
+ GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
+ return FALSE;
+ }
+ /* we can (re)construct the start later on, but not the end */
+ if (stop_type != GST_SEEK_TYPE_NONE &&
+ (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
+ GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
+ return FALSE;
+ }
+ gst_event_ref (event);
+ /* upstream might handle TIME seek, e.g. mms or rtsp,
+ * or not, e.g. http, then we give it a hand */
+ if (!gst_pad_push_event (demux->sinkpad, event))
+ return gst_asf_demux_handle_seek_push (demux, event);
+ else
+ return TRUE;
+ }
+
+ /* unlock the streaming thread */
+ if (G_LIKELY (flush)) {
+ fevent = gst_event_new_flush_start ();
+
+ gst_event_set_seqnum (fevent, seqnum);
+ gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
+ gst_asf_demux_send_event_unlocked (demux, fevent);
+ } else {
+ gst_pad_pause_task (demux->sinkpad);
+ }
+
+ /* grab the stream lock so that streaming cannot continue, for
+ * non flushing seeks when the element is in PAUSED this could block
+ * forever */
+ GST_PAD_STREAM_LOCK (demux->sinkpad);
+
+ /* we now can stop flushing, since we have the stream lock now */
+ fevent = gst_event_new_flush_stop (TRUE);
+ gst_event_set_seqnum (fevent, seqnum);
+ gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
+
+ if (G_LIKELY (flush))
+ gst_asf_demux_send_event_unlocked (demux, fevent);
+ else
+ gst_event_unref (fevent);
+
+ /* operating on copy of segment until we know the seek worked */
+ segment = demux->segment;
+
+ if (G_UNLIKELY (demux->segment_running && !flush)) {
+ GstSegment newsegment;
+ GstEvent *newseg;
+
+ /* create the segment event to close the current segment */
+ gst_segment_copy_into (&segment, &newsegment);
+ newseg = gst_event_new_segment (&newsegment);
+ gst_event_set_seqnum (newseg, seqnum);
+
+ gst_asf_demux_send_event_unlocked (demux, newseg);
+ }
+
+ gst_segment_do_seek (&segment, rate, format, flags, cur_type,
+ cur, stop_type, stop, &only_need_update);
+
+ GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
+ "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
+
+ if (cur_type != GST_SEEK_TYPE_SET)
+ seek_time = segment.start;
+ else
+ seek_time = cur;
+
+ /* FIXME: should check the KEY_UNIT flag; need to adjust position to
+ * real start of data and segment_start to indexed time for key unit seek*/
+ if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
+ &idx_time, &speed_count, next, &eos))) {
+ gint64 offset;
+
+ if (eos) {
+ demux->packet = demux->num_packets;
+ goto skip;
+ }
+
+ /* First try to query our source to see if it can convert for us. This is
+ the case when our source is an mms stream, notice that in this case
+ gstmms will do a time based seek to get the byte offset, this is not a
+ problem as the seek to this offset needs to happen anway. */
+ if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
+ GST_FORMAT_BYTES, &offset)) {
+ packet = (offset - demux->data_offset) / demux->packet_size;
+ GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
+ " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
+ G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
+ GST_TIME_ARGS (seek_time), offset, demux->data_offset,
+ demux->packet_size, packet);
+ } else {
+ /* FIXME: For streams containing video, seek to an earlier position in
+ * the hope of hitting a keyframe and let the sinks throw away the stuff
+ * before the segment start. For audio-only this is unnecessary as every
+ * frame is 'key'. */
+ if (flush && (demux->accurate || (keyunit_sync && !next))
+ && demux->num_video_streams > 0) {
+ seek_time -= 5 * GST_SECOND;
+ if (seek_time < 0)
+ seek_time = 0;
+ }
+
+ packet = (guint) gst_util_uint64_scale (demux->num_packets,
+ seek_time, demux->play_time);
+
+ if (packet > demux->num_packets)
+ packet = demux->num_packets;
+ }
+ } else {
+ if (G_LIKELY (keyunit_sync)) {
+ GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
+ GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
+ segment.start = idx_time;
+ segment.position = idx_time;
+ segment.time = idx_time;
+ }
+ }
+
+ GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
+
+ GST_OBJECT_LOCK (demux);
+ demux->segment = segment;
+ demux->packet = packet;
+ demux->need_newsegment = TRUE;
+ demux->segment_seqnum = seqnum;
+ demux->speed_packets = speed_count;
+ gst_asf_demux_reset_stream_state_after_discont (demux);
+ GST_OBJECT_UNLOCK (demux);
+
+skip:
+ /* restart our task since it might have been stopped when we did the flush */
+ gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
+ demux, NULL);
+
+ /* streaming can continue now */
+ GST_PAD_STREAM_UNLOCK (demux->sinkpad);
+
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstASFDemux *demux;
+ gboolean ret;
+
+ demux = GST_ASF_DEMUX (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ GST_LOG_OBJECT (pad, "seek event");
+ ret = gst_asf_demux_handle_seek_event (demux, event);
+ gst_event_unref (event);
+ break;
+ case GST_EVENT_QOS:
+ case GST_EVENT_NAVIGATION:
+ /* just drop these two silently */
+ gst_event_unref (event);
+ ret = FALSE;
+ break;
+ default:
+ GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+}
+
+static inline guint32
+gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
+{
+ guint32 ret;
+
+ ret = gst_asf_identify_guid (guids, guid);
+
+ GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
+ gst_asf_get_guid_nick (guids, ret),
+ guid->v1, guid->v2, guid->v3, guid->v4);
+
+ return ret;
+}
+
+typedef struct
+{
+ AsfObjectID id;
+ guint64 size;
+} AsfObject;
+
+
+/* expect is true when the user is expeting an object,
+ * when false, it will give no warnings if the object
+ * is not identified
+ */
+static gboolean
+asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
+ guint data_len, AsfObject * object, gboolean expect)
+{
+ ASFGuid guid;
+
+ if (data_len < ASF_OBJECT_HEADER_SIZE)
+ return FALSE;
+
+ guid.v1 = GST_READ_UINT32_LE (data + 0);
+ guid.v2 = GST_READ_UINT32_LE (data + 4);
+ guid.v3 = GST_READ_UINT32_LE (data + 8);
+ guid.v4 = GST_READ_UINT32_LE (data + 12);
+
+ object->size = GST_READ_UINT64_LE (data + 16);
+
+ /* FIXME: make asf_demux_identify_object_guid() */
+ object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
+ if (object->id == ASF_OBJ_UNDEFINED && expect) {
+ GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
+ guid.v1, guid.v2, guid.v3, guid.v4);
+ }
+
+ return TRUE;
+}
+
+static void
+gst_asf_demux_release_old_pads (GstASFDemux * demux)
+{
+ GST_DEBUG_OBJECT (demux, "Releasing old pads");
+
+ while (demux->old_num_streams > 0) {
+ gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
+ gst_event_new_eos ());
+ gst_asf_demux_free_stream (demux,
+ &demux->old_stream[demux->old_num_streams - 1]);
+ --demux->old_num_streams;
+ }
+ memset (demux->old_stream, 0, sizeof (demux->old_stream));
+ demux->old_num_streams = 0;
+}
+
+static GstFlowReturn
+gst_asf_demux_chain_headers (GstASFDemux * demux)
+{
+ GstFlowReturn flow;
+ AsfObject obj;
+ guint8 *header_data, *data = NULL;
+ const guint8 *cdata = NULL;
+ guint64 header_size;
+
+ cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
+ if (cdata == NULL)
+ goto need_more_data;
+
+ asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+ if (obj.id != ASF_OBJ_HEADER)
+ goto wrong_type;
+
+ GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
+
+ /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
+ if (gst_adapter_available (demux->adapter) < obj.size + 50)
+ goto need_more_data;
+
+ data = gst_adapter_take (demux->adapter, obj.size + 50);
+
+ header_data = data;
+ header_size = obj.size;
+ flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
+ if (flow != GST_FLOW_OK)
+ goto parse_failed;
+
+ /* calculate where the packet data starts */
+ demux->data_offset = obj.size + 50;
+
+ /* now parse the beginning of the ASF_OBJ_DATA object */
+ if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
+ goto wrong_type;
+
+ if (demux->num_streams == 0)
+ goto no_streams;
+
+ g_free (data);
+ return GST_FLOW_OK;
+
+/* NON-FATAL */
+need_more_data:
+ {
+ GST_LOG_OBJECT (demux, "not enough data in adapter yet");
+ return GST_FLOW_OK;
+ }
+
+/* ERRORS */
+wrong_type:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
+ ("This doesn't seem to be an ASF file"));
+ g_free (data);
+ return GST_FLOW_ERROR;
+ }
+no_streams:
+parse_failed:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("header parsing failed, or no streams found, flow = %s",
+ gst_flow_get_name (flow)));
+ g_free (data);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static gboolean
+gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
+ GstBuffer ** p_buf, GstFlowReturn * p_flow)
+{
+ gsize buffer_size;
+ GstFlowReturn flow;
+
+ GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
+ offset, size);
+
+ flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
+
+ if (G_LIKELY (p_flow))
+ *p_flow = flow;
+
+ if (G_UNLIKELY (flow != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
+ "+%u", gst_flow_get_name (flow), offset, size);
+ *p_buf = NULL;
+ return FALSE;
+ }
+
+ g_assert (*p_buf != NULL);
+
+ buffer_size = gst_buffer_get_size (*p_buf);
+ if (G_UNLIKELY (buffer_size < size)) {
+ GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
+ "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
+ gst_buffer_unref (*p_buf);
+ if (G_LIKELY (p_flow))
+ *p_flow = GST_FLOW_EOS;
+ *p_buf = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gst_asf_demux_pull_indices (GstASFDemux * demux)
+{
+ GstBuffer *buf = NULL;
+ guint64 offset;
+ guint num_read = 0;
+
+ offset = demux->index_offset;
+
+ if (G_UNLIKELY (offset == 0)) {
+ GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
+ return;
+ }
+
+ while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
+ GstFlowReturn flow;
+ AsfObject obj;
+ GstMapInfo map;
+ guint8 *bufdata;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ g_assert (map.size >= 16 + 8);
+ asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+
+ /* check for sanity */
+ if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
+ GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
+ break;
+ }
+
+ if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
+ NULL)))
+ break;
+
+ GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
+ ", size %u", offset, (guint) obj.size);
+
+ offset += obj.size; /* increase before _process_object changes it */
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ g_assert (map.size >= obj.size);
+ bufdata = (guint8 *) map.data;
+ flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+
+ if (G_UNLIKELY (flow != GST_FLOW_OK))
+ break;
+
+ ++num_read;
+ }
+ GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
+}
+
+static gboolean
+gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
+{
+ AsfObject obj;
+
+ asf_demux_peek_object (demux, data, 50, &obj, TRUE);
+ if (obj.id != ASF_OBJ_DATA) {
+ GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
+ return FALSE;
+ }
+
+ demux->state = GST_ASF_DEMUX_STATE_DATA;
+
+ if (!demux->broadcast && obj.size > 50) {
+ demux->data_size = obj.size - 50;
+ /* CHECKME: for at least one file this is off by +158 bytes?! */
+ demux->index_offset = demux->data_offset + demux->data_size;
+ } else {
+ demux->data_size = 0;
+ demux->index_offset = 0;
+ }
+
+ demux->packet = 0;
+
+ if (!demux->broadcast) {
+ /* skip object header (24 bytes) and file GUID (16 bytes) */
+ demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
+ } else {
+ demux->num_packets = 0;
+ }
+
+ if (demux->num_packets == 0)
+ demux->seekable = FALSE;
+
+ /* fallback in the unlikely case that headers are inconsistent, can't hurt */
+ if (demux->data_size == 0 && demux->num_packets > 0) {
+ demux->data_size = demux->num_packets * demux->packet_size;
+ demux->index_offset = demux->data_offset + demux->data_size;
+ }
+
+ /* process pending stream objects and create pads for those */
+ gst_asf_demux_process_queued_extended_stream_objects (demux);
+
+ GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
+ "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
+ ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
+ demux->data_offset, demux->data_size, demux->index_offset);
+
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_pull_headers (GstASFDemux * demux)
+{
+ GstFlowReturn flow;
+ AsfObject obj;
+ GstBuffer *buf = NULL;
+ guint64 size;
+ GstMapInfo map;
+ guint8 *bufdata;
+
+ GST_LOG_OBJECT (demux, "reading headers");
+
+ /* pull HEADER object header, so we know its size */
+ if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
+ goto read_failed;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ g_assert (map.size >= 16 + 8);
+ asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+
+ if (obj.id != ASF_OBJ_HEADER)
+ goto wrong_type;
+
+ GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
+
+ /* pull HEADER object */
+ if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
+ NULL))
+ goto read_failed;
+
+ size = obj.size; /* don't want obj.size changed */
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ g_assert (map.size >= size);
+ bufdata = (guint8 *) map.data;
+ flow = gst_asf_demux_process_object (demux, &bufdata, &size);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+
+ if (flow != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
+ goto parse_failed;
+ }
+
+ /* calculate where the packet data starts */
+ demux->data_offset = demux->base_offset + obj.size + 50;
+
+ /* now pull beginning of DATA object before packet data */
+ if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
+ NULL))
+ goto read_failed;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ g_assert (map.size >= size);
+ bufdata = (guint8 *) map.data;
+ if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
+ goto wrong_type;
+
+ if (demux->num_streams == 0)
+ goto no_streams;
+
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+
+ return TRUE;
+
+/* ERRORS */
+wrong_type:
+ {
+ if (buf != NULL) {
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+ }
+ GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
+ ("This doesn't seem to be an ASF file"));
+ return FALSE;
+ }
+
+no_streams:
+read_failed:
+parse_failed:
+ {
+ if (buf)
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
+ return FALSE;
+ }
+}
+
+static gboolean
+all_streams_prerolled (GstASFDemux * demux)
+{
+ GstClockTime preroll_time;
+ guint i, num_no_data = 0;
+
+ /* Allow at least 500ms of preroll_time */
+ preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
+
+ /* returns TRUE as long as there isn't a stream which (a) has data queued
+ * and (b) the timestamp of last piece of data queued is < demux->preroll
+ * AND there is at least one other stream with data queued */
+ for (i = 0; i < demux->num_streams; ++i) {
+ AsfPayload *last_payload = NULL;
+ AsfStream *stream;
+ gint last_idx;
+
+ stream = &demux->stream[i];
+ if (G_UNLIKELY (stream->payloads->len == 0)) {
+ ++num_no_data;
+ GST_LOG_OBJECT (stream->pad, "no data queued");
+ continue;
+ }
+
+ /* find last payload with timestamp */
+ for (last_idx = stream->payloads->len - 1;
+ last_idx >= 0 && (last_payload == NULL
+ || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
+ last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
+ }
+
+ GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
+ GST_TIME_ARGS (preroll_time));
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
+ || last_payload->ts <= preroll_time)) {
+ GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
+ return FALSE;
+ }
+ }
+
+ if (G_UNLIKELY (num_no_data > 0))
+ return FALSE;
+
+ return TRUE;
+}
+
+#if 0
+static gboolean
+gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
+ AsfStream * stream)
+{
+ GSList *l;
+
+ for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
+ guint8 *mes;
+
+ /* check for each mutual exclusion group whether it affects this stream */
+ for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
+ if (*mes == stream->id) {
+ /* we are in this group; let's check if we've already activated streams
+ * that are in the same group (and hence mutually exclusive to this
+ * one) */
+ for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
+ guint i;
+
+ for (i = 0; i < demux->num_streams; ++i) {
+ if (demux->stream[i].id == *mes && demux->stream[i].active) {
+ GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
+ "to already active stream with ID %d", stream->id,
+ demux->stream[i].id);
+ return TRUE;
+ }
+ }
+ }
+ /* we can only be in this group once, let's break out and move on to
+ * the next mutual exclusion group */
+ break;
+ }
+ }
+ }
+
+ return FALSE;
+}
+#endif
+
+static void
+gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
+{
+ /* remember the first queued timestamp for the segment */
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
+ GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
+ GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->first_ts));
+ demux->segment_ts = payload_ts;
+ /* always note, but only determines segment when streaming */
+ if (demux->streaming)
+ gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
+ GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
+ GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
+ }
+}
+
+static gboolean
+gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
+{
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
+ GstClockTime first_ts = GST_CLOCK_TIME_NONE;
+ int i;
+
+ /* go trhough each stream, find smallest timestamp */
+ for (i = 0; i < demux->num_streams; ++i) {
+ AsfStream *stream;
+ int j;
+ GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
+ GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
+ stream = &demux->stream[i];
+
+ for (j = 0; j < stream->payloads->len; ++j) {
+ AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
+ if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+ (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
+ || stream_min_ts > payload->ts)) {
+ stream_min_ts = payload->ts;
+ }
+ if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+ payload->ts > stream_min_ts &&
+ (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
+ || stream_min_ts2 > payload->ts)) {
+ stream_min_ts2 = payload->ts;
+ }
+ }
+
+ /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
+ regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
+ which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
+ from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
+ and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
+
+ if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
+ return FALSE;
+
+ if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
+ stream_min_ts = stream_min_ts2;
+
+ /* if we don't have timestamp for this stream, wait for more data */
+ if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
+ return FALSE;
+
+ if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
+ (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
+ first_ts = stream_min_ts;
+ }
+
+ if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
+ first_ts = 0;
+
+ demux->first_ts = first_ts;
+
+ /* update packets queued before we knew first timestamp */
+ for (i = 0; i < demux->num_streams; ++i) {
+ AsfStream *stream;
+ int j;
+ stream = &demux->stream[i];
+
+ for (j = 0; j < stream->payloads->len; ++j) {
+ AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
+ if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
+ if (payload->ts > first_ts)
+ payload->ts -= first_ts;
+ else
+ payload->ts = 0;
+ }
+ }
+ }
+ }
+
+ gst_asf_demux_check_segment_ts (demux, 0);
+
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
+{
+ /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
+ and often set wrong, inspecting the data is the only way that seem to be working */
+ GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
+ GstCaps *caps = NULL;
+ int i;
+ GstAdapter *adapter = gst_adapter_new ();
+
+ for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
+ const guint8 *data;
+ AsfPayload *payload;
+ int len;
+
+ payload = &g_array_index (stream->payloads, AsfPayload, i);
+ gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
+ len = gst_adapter_available (adapter);
+ data = gst_adapter_map (adapter, len);
+
+ again:
+
+#define MIN_LENGTH 128
+
+ /* look for the sync points */
+ while (TRUE) {
+ if (len < MIN_LENGTH || /* give typefind something to work on */
+ (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
+ (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
+ break;
+ ++data;
+ --len;
+ }
+
+ gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
+ data, len, &prob));
+
+ if (prob < GST_TYPE_FIND_LIKELY) {
+ ++data;
+ --len;
+ if (len > MIN_LENGTH)
+ /* this wasn't it, look for another sync point */
+ goto again;
+ }
+
+ gst_adapter_unmap (adapter);
+ }
+
+ gst_object_unref (adapter);
+
+ if (caps) {
+ gst_caps_take (&stream->caps, caps);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
+{
+ guint i;
+
+ if (demux->activated_streams)
+ return TRUE;
+
+ if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
+ return FALSE;
+
+ if (!all_streams_prerolled (demux) && !force) {
+ GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
+ return FALSE;
+ }
+
+ for (i = 0; i < demux->num_streams; ++i) {
+ AsfStream *stream = &demux->stream[i];
+
+ if (stream->payloads->len > 0) {
+
+ if (stream->inspect_payload && /* dvr-ms required payload inspection */
+ !stream->active && /* do not inspect active streams (caps were already set) */
+ !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
+ stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
+ /* try to gather some more data */
+ return FALSE;
+ }
+ /* we don't check mutual exclusion stuff here; either we have data for
+ * a stream, then we active it, or we don't, then we'll ignore it */
+ GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
+ gst_asf_demux_activate_stream (demux, stream);
+ } else {
+ GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
+ }
+ }
+
+ gst_asf_demux_release_old_pads (demux);
+
+ demux->activated_streams = TRUE;
+ GST_LOG_OBJECT (demux, "signalling no more pads");
+ gst_element_no_more_pads (GST_ELEMENT (demux));
+ return TRUE;
+}
+
+/* returns the stream that has a complete payload with the lowest timestamp
+ * queued, or NULL (we push things by timestamp because during the internal
+ * prerolling we might accumulate more data then the external queues can take,
+ * so we'd lock up if we pushed all accumulated data for stream N in one go) */
+static AsfStream *
+gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
+{
+ AsfPayload *best_payload = NULL;
+ AsfStream *best_stream = NULL;
+ guint i;
+
+ for (i = 0; i < demux->num_streams; ++i) {
+ AsfStream *stream;
+ int j;
+
+ stream = &demux->stream[i];
+
+ /* Don't push any data until we have at least one payload that falls within
+ * the current segment. This way we can remove out-of-segment payloads that
+ * don't need to be decoded after a seek, sending only data from the
+ * keyframe directly before our segment start */
+ if (stream->payloads->len > 0) {
+ AsfPayload *payload = NULL;
+ gint last_idx;
+
+ /* find last payload with timestamp */
+ for (last_idx = stream->payloads->len - 1;
+ last_idx >= 0 && (payload == NULL
+ || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
+ payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
+ }
+
+ /* if this is first payload after seek we might need to update the segment */
+ if (GST_CLOCK_TIME_IS_VALID (payload->ts))
+ gst_asf_demux_check_segment_ts (demux, payload->ts);
+
+ if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+ (payload->ts < demux->segment.start))) {
+ if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
+ GST_DEBUG_OBJECT (stream->pad,
+ "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (payload->ts));
+ demux->segment.start = payload->ts;
+ demux->segment.time = payload->ts;
+ } else {
+ GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
+ GST_TIME_FORMAT " which is before our segment start %"
+ GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
+ GST_TIME_ARGS (demux->segment.start));
+ continue;
+ }
+ }
+
+ /* Now see if there's a complete payload queued for this stream */
+
+ payload = NULL;
+ /* find first complete payload with timestamp */
+ for (j = 0;
+ j < stream->payloads->len && (payload == NULL
+ || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
+ payload = &g_array_index (stream->payloads, AsfPayload, j);
+ }
+
+ if (!gst_asf_payload_is_complete (payload))
+ continue;
+
+ /* ... and whether its timestamp is lower than the current best */
+ if (best_stream == NULL || best_payload->ts > payload->ts) {
+ best_stream = stream;
+ best_payload = payload;
+ }
+ }
+ }
+
+ return best_stream;
+}
+
+static GstFlowReturn
+gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
+{
+ AsfStream *stream;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ if (G_UNLIKELY (!demux->activated_streams)) {
+ if (!gst_asf_demux_check_activate_streams (demux, force))
+ return GST_FLOW_OK;
+ /* streams are now activated */
+ }
+
+ while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
+ AsfPayload *payload;
+
+ /* wait until we had a chance to "lock on" some payload's timestamp */
+ if (G_UNLIKELY (demux->need_newsegment
+ && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
+ return GST_FLOW_OK;
+
+ payload = &g_array_index (stream->payloads, AsfPayload, 0);
+
+ /* do we need to send a newsegment event */
+ if ((G_UNLIKELY (demux->need_newsegment))) {
+ GstEvent *segment_event;
+
+ /* safe default if insufficient upstream info */
+ if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
+ demux->in_gap = 0;
+
+ if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
+ demux->segment.duration > 0) {
+ /* slight HACK; prevent clipping of last bit */
+ demux->segment.stop = demux->segment.duration + demux->in_gap;
+ }
+
+ /* FIXME : only if ACCURATE ! */
+ if (G_LIKELY (!demux->accurate
+ && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
+ GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (payload->ts));
+ demux->segment.start = payload->ts;
+ demux->segment.time = payload->ts;
+ }
+
+ GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
+ &demux->segment);
+
+ /* note: we fix up all timestamps to start from 0, so this should be ok */
+ segment_event = gst_event_new_segment (&demux->segment);
+ if (demux->segment_seqnum)
+ gst_event_set_seqnum (segment_event, demux->segment_seqnum);
+ gst_asf_demux_send_event_unlocked (demux, segment_event);
+
+ /* now post any global tags we may have found */
+ if (demux->taglist == NULL) {
+ demux->taglist = gst_tag_list_new_empty ();
+ gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
+ }
+
+ gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+ GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
+
+ GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
+ gst_asf_demux_send_event_unlocked (demux,
+ gst_event_new_tag (demux->taglist));
+ demux->taglist = NULL;
+
+ demux->need_newsegment = FALSE;
+ demux->segment_seqnum = 0;
+ demux->segment_running = TRUE;
+ }
+
+ /* Do we have tags pending for this stream? */
+ if (G_UNLIKELY (stream->pending_tags)) {
+ GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
+ gst_pad_push_event (stream->pad,
+ gst_event_new_tag (stream->pending_tags));
+ stream->pending_tags = NULL;
+ }
+
+ /* We have the whole packet now so we should push the packet to
+ * the src pad now. First though we should check if we need to do
+ * descrambling */
+ if (G_UNLIKELY (stream->span > 1)) {
+ gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
+ }
+
+ payload->buf = gst_buffer_make_writable (payload->buf);
+
+ if (G_LIKELY (!payload->keyframe)) {
+ GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ if (G_UNLIKELY (stream->discont)) {
+ GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
+ GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+
+ if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
+ (payload->par_x != stream->par_x) &&
+ (payload->par_y != stream->par_y))) {
+ GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
+ stream->par_x, stream->par_y, payload->par_x, payload->par_y);
+ stream->par_x = payload->par_x;
+ stream->par_y = payload->par_y;
+ stream->caps = gst_caps_make_writable (stream->caps);
+ gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
+ GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
+ gst_pad_set_caps (stream->pad, stream->caps);
+ }
+
+ if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
+ GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
+ payload->interlaced);
+ stream->interlaced = payload->interlaced;
+ stream->caps = gst_caps_make_writable (stream->caps);
+ gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
+ (stream->interlaced ? "mixed" : "progressive"), NULL);
+ gst_pad_set_caps (stream->pad, stream->caps);
+ }
+
+ /* (sort of) interpolate timestamps using upstream "frame of reference",
+ * typically useful for live src, but might (unavoidably) mess with
+ * position reporting if a live src is playing not so live content
+ * (e.g. rtspsrc taking some time to fall back to tcp) */
+ GST_BUFFER_PTS (payload->buf) = payload->ts;
+ if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
+ GST_BUFFER_PTS (payload->buf) += demux->in_gap;
+ }
+ if (payload->duration == GST_CLOCK_TIME_NONE
+ && stream->ext_props.avg_time_per_frame != 0)
+ GST_BUFFER_DURATION (payload->buf) =
+ stream->ext_props.avg_time_per_frame * 100;
+ else
+ GST_BUFFER_DURATION (payload->buf) = payload->duration;
+
+ /* FIXME: we should really set durations on buffers if we can */
+
+ GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
+ ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
+ gst_buffer_get_size (payload->buf));
+
+ if (stream->active) {
+ ret = gst_pad_push (stream->pad, payload->buf);
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
+ } else {
+ gst_buffer_unref (payload->buf);
+ ret = GST_FLOW_OK;
+ }
+ payload->buf = NULL;
+ g_array_remove_index (stream->payloads, 0);
+
+ /* Break out as soon as we have an issue */
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
+{
+ AsfObject obj;
+ GstMapInfo map;
+ g_assert (buf != NULL);
+
+ GST_LOG_OBJECT (demux, "Checking if buffer is a header");
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ /* we return false on buffer too small */
+ if (map.size < ASF_OBJECT_HEADER_SIZE) {
+ gst_buffer_unmap (buf, &map);
+ return FALSE;
+ }
+
+ /* check if it is a header */
+ asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+ gst_buffer_unmap (buf, &map);
+ if (obj.id == ASF_OBJ_HEADER) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+gst_asf_demux_check_chained_asf (GstASFDemux * demux)
+{
+ guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *buf = NULL;
+ gboolean header = FALSE;
+
+ /* TODO maybe we should skip index objects after the data and look
+ * further for a new header */
+ if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
+ g_assert (buf != NULL);
+ /* check if it is a header */
+ if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
+ GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
+ demux->base_offset = off;
+ header = TRUE;
+ }
+
+ gst_buffer_unref (buf);
+ }
+
+ return header;
+}
+
+static void
+gst_asf_demux_loop (GstASFDemux * demux)
+{
+ GstFlowReturn flow = GST_FLOW_OK;
+ GstBuffer *buf = NULL;
+ guint64 off;
+ gboolean sent_eos = FALSE;
+
+ if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
+ if (!gst_asf_demux_pull_headers (demux)) {
+ flow = GST_FLOW_ERROR;
+ goto pause;
+ }
+
+ gst_asf_demux_pull_indices (demux);
+ }
+
+ g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
+
+ if (G_UNLIKELY (demux->num_packets != 0
+ && demux->packet >= demux->num_packets))
+ goto eos;
+
+ GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
+ (guint) demux->num_packets);
+
+ off = demux->data_offset + (demux->packet * demux->packet_size);
+
+ if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
+ demux->packet_size * demux->speed_packets, &buf, &flow))) {
+ GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
+ if (flow == GST_FLOW_EOS)
+ goto eos;
+ else if (flow == GST_FLOW_FLUSHING) {
+ GST_DEBUG_OBJECT (demux, "Not fatal");
+ goto pause;
+ } else
+ goto read_failed;
+ }
+
+ if (G_LIKELY (demux->speed_packets == 1)) {
+ GstAsfDemuxParsePacketError err;
+ err = gst_asf_demux_parse_packet (demux, buf);
+ if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
+ /* when we don't know when the data object ends, we should check
+ * for a chained asf */
+ if (demux->num_packets == 0) {
+ if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
+ GST_INFO_OBJECT (demux, "Chained asf found");
+ demux->base_offset = off;
+ gst_asf_demux_reset (demux, TRUE);
+ gst_buffer_unref (buf);
+ return;
+ }
+ }
+ /* FIXME: We should tally up fatal errors and error out only
+ * after a few broken packets in a row? */
+
+ GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
+ gst_buffer_unref (buf);
+ ++demux->packet;
+ return;
+ }
+
+ flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
+
+ ++demux->packet;
+
+ } else {
+ guint n;
+ for (n = 0; n < demux->speed_packets; n++) {
+ GstBuffer *sub;
+ GstAsfDemuxParsePacketError err;
+
+ sub =
+ gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
+ n * demux->packet_size, demux->packet_size);
+ err = gst_asf_demux_parse_packet (demux, sub);
+ if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
+ /* when we don't know when the data object ends, we should check
+ * for a chained asf */
+ if (demux->num_packets == 0) {
+ if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
+ GST_INFO_OBJECT (demux, "Chained asf found");
+ demux->base_offset = off + n * demux->packet_size;
+ gst_asf_demux_reset (demux, TRUE);
+ gst_buffer_unref (sub);
+ gst_buffer_unref (buf);
+ return;
+ }
+ }
+ /* FIXME: We should tally up fatal errors and error out only
+ * after a few broken packets in a row? */
+
+ GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
+ flow = GST_FLOW_OK;
+ }
+
+ gst_buffer_unref (sub);
+
+ if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
+ flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
+
+ ++demux->packet;
+
+ }
+
+ /* reset speed pull */
+ demux->speed_packets = 1;
+ }
+
+ gst_buffer_unref (buf);
+
+ if (G_UNLIKELY (demux->num_packets > 0
+ && demux->packet >= demux->num_packets)) {
+ GST_LOG_OBJECT (demux, "reached EOS");
+ goto eos;
+ }
+
+ if (G_UNLIKELY (flow != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
+ goto pause;
+ }
+
+ /* check if we're at the end of the configured segment */
+ /* FIXME: check if segment end reached etc. */
+
+ return;
+
+eos:
+ {
+ /* if we haven't activated our streams yet, this might be because we have
+ * less data queued than required for preroll; force stream activation and
+ * send any pending payloads before sending EOS */
+ if (!demux->activated_streams)
+ gst_asf_demux_push_complete_payloads (demux, TRUE);
+
+ /* we want to push an eos or post a segment-done in any case */
+ if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gint64 stop;
+
+ /* for segment playback we need to post when (in stream time)
+ * we stopped, this is either stop (when set) or the duration. */
+ if ((stop = demux->segment.stop) == -1)
+ stop = demux->segment.duration;
+
+ GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
+ stop));
+ gst_asf_demux_send_event_unlocked (demux,
+ gst_event_new_segment_done (GST_FORMAT_TIME, stop));
+ } else if (flow != GST_FLOW_EOS) {
+ /* check if we have a chained asf, in case, we don't eos yet */
+ if (gst_asf_demux_check_chained_asf (demux)) {
+ GST_INFO_OBJECT (demux, "Chained ASF starting");
+ gst_asf_demux_reset (demux, TRUE);
+ return;
+ }
+ }
+ /* normal playback, send EOS to all linked pads */
+ GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
+ gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
+ sent_eos = TRUE;
+ /* ... and fall through to pause */
+ }
+pause:
+ {
+ GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
+ gst_flow_get_name (flow));
+ demux->segment_running = FALSE;
+ gst_pad_pause_task (demux->sinkpad);
+
+ /* For the error cases (not EOS) */
+ if (!sent_eos) {
+ if (flow == GST_FLOW_EOS)
+ gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
+ else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
+ /* Post an error. Hopefully something else already has, but if not... */
+ GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+ (_("Internal data stream error.")),
+ ("streaming stopped, reason %s", gst_flow_get_name (flow)));
+ }
+ }
+ return;
+ }
+
+/* ERRORS */
+read_failed:
+ {
+ GST_DEBUG_OBJECT (demux, "Read failed, doh");
+ gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
+ flow = GST_FLOW_EOS;
+ goto pause;
+ }
+#if 0
+ /* See FIXMEs above */
+parse_error:
+ {
+ gst_buffer_unref (buf);
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("Error parsing ASF packet %u", (guint) demux->packet));
+ gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
+ flow = GST_FLOW_ERROR;
+ goto pause;
+ }
+#endif
+}
+
+#define GST_ASF_DEMUX_CHECK_HEADER_YES 0
+#define GST_ASF_DEMUX_CHECK_HEADER_NO 1
+#define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
+
+static gint
+gst_asf_demux_check_header (GstASFDemux * demux)
+{
+ AsfObject obj;
+ guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
+ ASF_OBJECT_HEADER_SIZE);
+ if (cdata == NULL) /* need more data */
+ return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
+
+ asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
+ if (obj.id != ASF_OBJ_HEADER) {
+ return GST_ASF_DEMUX_CHECK_HEADER_NO;
+ } else {
+ return GST_ASF_DEMUX_CHECK_HEADER_YES;
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstASFDemux *demux;
+
+ demux = GST_ASF_DEMUX (parent);
+
+ GST_LOG_OBJECT (demux,
+ "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
+ GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
+ GST_DEBUG_OBJECT (demux, "received DISCONT");
+ gst_asf_demux_mark_discont (demux);
+ }
+
+ if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
+ GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
+ demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
+ GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
+ ", interpolation gap: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
+ }
+
+ gst_adapter_push (demux->adapter, buf);
+
+ switch (demux->state) {
+ case GST_ASF_DEMUX_STATE_INDEX:{
+ gint result = gst_asf_demux_check_header (demux);
+ if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
+ break;
+
+ if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
+ /* we don't care about this, probably an index */
+ /* TODO maybe would be smarter to skip all the indices
+ * until we got a new header or EOS to decide */
+ GST_LOG_OBJECT (demux, "Received index object, its EOS");
+ goto eos;
+ } else {
+ GST_INFO_OBJECT (demux, "Chained asf starting");
+ /* cleanup and get ready for a chained asf */
+ gst_asf_demux_reset (demux, TRUE);
+ /* fall through */
+ }
+ }
+ case GST_ASF_DEMUX_STATE_HEADER:{
+ ret = gst_asf_demux_chain_headers (demux);
+ if (demux->state != GST_ASF_DEMUX_STATE_DATA)
+ break;
+ /* otherwise fall through */
+ }
+ case GST_ASF_DEMUX_STATE_DATA:
+ {
+ guint64 data_size;
+
+ data_size = demux->packet_size;
+
+ while (gst_adapter_available (demux->adapter) >= data_size) {
+ GstBuffer *buf;
+ GstAsfDemuxParsePacketError err;
+
+ /* we don't know the length of the stream
+ * check for a chained asf everytime */
+ if (demux->num_packets == 0) {
+ gint result = gst_asf_demux_check_header (demux);
+
+ if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
+ GST_INFO_OBJECT (demux, "Chained asf starting");
+ /* cleanup and get ready for a chained asf */
+ gst_asf_demux_reset (demux, TRUE);
+ break;
+ }
+ } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
+ && demux->packet >= demux->num_packets)) {
+ /* do not overshoot data section when streaming */
+ break;
+ }
+
+ buf = gst_adapter_take_buffer (demux->adapter, data_size);
+
+ /* FIXME: We should tally up fatal errors and error out only
+ * after a few broken packets in a row? */
+ err = gst_asf_demux_parse_packet (demux, buf);
+
+ gst_buffer_unref (buf);
+
+ if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
+ ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
+ else
+ GST_WARNING_OBJECT (demux, "Parse error");
+
+ if (demux->packet >= 0)
+ ++demux->packet;
+ }
+ if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
+ && demux->packet >= demux->num_packets)) {
+ demux->state = GST_ASF_DEMUX_STATE_INDEX;
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+done:
+ if (ret != GST_FLOW_OK)
+ GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
+
+ return ret;
+
+eos:
+ {
+ GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
+ ret = GST_FLOW_EOS;
+ goto done;
+ }
+}
+
+static inline gboolean
+gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
+{
+ if (*p_size < num_bytes)
+ return FALSE;
+
+ *p_data += num_bytes;
+ *p_size -= num_bytes;
+ return TRUE;
+}
+
+static inline guint8
+gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
+{
+ guint8 ret;
+
+ g_assert (*p_size >= 1);
+ ret = GST_READ_UINT8 (*p_data);
+ *p_data += sizeof (guint8);
+ *p_size -= sizeof (guint8);
+ return ret;
+}
+
+static inline guint16
+gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
+{
+ guint16 ret;
+
+ g_assert (*p_size >= 2);
+ ret = GST_READ_UINT16_LE (*p_data);
+ *p_data += sizeof (guint16);
+ *p_size -= sizeof (guint16);
+ return ret;
+}
+
+static inline guint32
+gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
+{
+ guint32 ret;
+
+ g_assert (*p_size >= 4);
+ ret = GST_READ_UINT32_LE (*p_data);
+ *p_data += sizeof (guint32);
+ *p_size -= sizeof (guint32);
+ return ret;
+}
+
+static inline guint64
+gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
+{
+ guint64 ret;
+
+ g_assert (*p_size >= 8);
+ ret = GST_READ_UINT64_LE (*p_data);
+ *p_data += sizeof (guint64);
+ *p_size -= sizeof (guint64);
+ return ret;
+}
+
+static gboolean
+gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
+ guint8 ** p_data, guint64 * p_size)
+{
+ *p_buf = NULL;
+
+ if (*p_size < num_bytes_to_read)
+ return FALSE;
+
+ *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
+ gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
+
+ *p_data += num_bytes_to_read;
+ *p_size -= num_bytes_to_read;
+
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
+ guint8 ** p_data, guint64 * p_size)
+{
+ *p_buf = NULL;
+
+ if (*p_size < num_bytes_to_read)
+ return FALSE;
+
+ *p_buf = g_memdup (*p_data, num_bytes_to_read);
+ *p_data += num_bytes_to_read;
+ *p_size -= num_bytes_to_read;
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
+ guint8 ** p_data, guint64 * p_size)
+{
+ guint16 s_length;
+ guint8 *s;
+
+ *p_str = NULL;
+
+ if (*p_size < 2)
+ return FALSE;
+
+ s_length = gst_asf_demux_get_uint16 (p_data, p_size);
+
+ if (p_strlen)
+ *p_strlen = s_length;
+
+ if (s_length == 0) {
+ GST_WARNING ("zero-length string");
+ *p_str = g_strdup ("");
+ return TRUE;
+ }
+
+ if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
+ return FALSE;
+
+ g_assert (s != NULL);
+
+ /* just because They don't exist doesn't
+ * mean They are not out to get you ... */
+ if (s[s_length - 1] != '\0') {
+ s = g_realloc (s, s_length + 1);
+ s[s_length] = '\0';
+ }
+
+ *p_str = (gchar *) s;
+ return TRUE;
+}
+
+
+static void
+gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
+{
+ g_assert (*p_size >= 4 * sizeof (guint32));
+
+ guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
+ guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
+ guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
+ guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
+}
+
+static gboolean
+gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
+ guint64 * p_size)
+{
+ if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
+ return FALSE;
+
+ /* WAVEFORMATEX Structure */
+ audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
+ audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
+ audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
+ audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
+ audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
+ audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
+ /* Codec specific data size */
+ audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
+ guint64 * p_size)
+{
+ if (*p_size < (4 + 4 + 1 + 2))
+ return FALSE;
+
+ video->width = gst_asf_demux_get_uint32 (p_data, p_size);
+ video->height = gst_asf_demux_get_uint32 (p_data, p_size);
+ video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
+ video->size = gst_asf_demux_get_uint16 (p_data, p_size);
+ return TRUE;
+}
+
+static gboolean
+gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
+ guint8 ** p_data, guint64 * p_size)
+{
+ if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
+ return FALSE;
+
+ fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
+ fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
+ fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
+ fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
+ return TRUE;
+}
+
+AsfStream *
+gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
+{
+ guint i;
+
+ for (i = 0; i < demux->num_streams; i++) {
+ if (demux->stream[i].id == id)
+ return &demux->stream[i];
+ }
+
+ if (gst_asf_demux_is_unknown_stream (demux, id))
+ GST_WARNING ("Segment found for undefined stream: (%d)", id);
+ return NULL;
+}
+
+static AsfStream *
+gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
+ GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
+{
+ AsfStream *stream;
+
+ gst_pad_use_fixed_caps (src_pad);
+ gst_pad_set_caps (src_pad, caps);
+
+ gst_pad_set_event_function (src_pad,
+ GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
+ gst_pad_set_query_function (src_pad,
+ GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
+
+ stream = &demux->stream[demux->num_streams];
+ stream->caps = caps;
+ stream->pad = src_pad;
+ stream->id = id;
+ stream->fps_known = !is_video; /* bit hacky for audio */
+ stream->is_video = is_video;
+ stream->pending_tags = tags;
+ stream->discont = TRUE;
+ if (is_video) {
+ GstStructure *st;
+ gint par_x, par_y;
+ st = gst_caps_get_structure (caps, 0);
+ if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
+ par_x > 0 && par_y > 0) {
+ GST_DEBUG ("PAR %d/%d", par_x, par_y);
+ stream->par_x = par_x;
+ stream->par_y = par_y;
+ }
+ }
+
+ stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
+
+ GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
+ GST_PAD_NAME (src_pad), demux->num_streams, caps);
+
+ ++demux->num_streams;
+
+ stream->active = FALSE;
+
+ return stream;
+}
+
+static AsfStream *
+gst_asf_demux_add_audio_stream (GstASFDemux * demux,
+ asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
+{
+ GstTagList *tags = NULL;
+ GstBuffer *extradata = NULL;
+ GstPad *src_pad;
+ GstCaps *caps;
+ guint16 size_left = 0;
+ gchar *codec_name = NULL;
+ gchar *name = NULL;
+
+ size_left = audio->size;
+
+ /* Create the audio pad */
+ name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
+
+ src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
+ g_free (name);
+
+ /* Swallow up any left over data and set up the
+ * standard properties from the header info */
+ if (size_left) {
+ GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
+ "codec specific data", size_left);
+
+ g_assert (size_left <= *p_size);
+ gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
+ }
+
+ /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
+ * additional two bytes indicating extradata. */
+ /* FIXME: Handle the channel reorder map here */
+ caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
+ (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
+
+ if (caps == NULL) {
+ caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
+ G_TYPE_INT, (gint) audio->codec_tag, NULL);
+ }
+
+ /* Informing about that audio format we just added */
+ if (codec_name) {
+ tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
+ g_free (codec_name);
+ }
+
+ if (extradata)
+ gst_buffer_unref (extradata);
+
+ GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
+ GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
+ audio->codec_tag, tags);
+
+ ++demux->num_audio_streams;
+
+ return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
+}
+
+static AsfStream *
+gst_asf_demux_add_video_stream (GstASFDemux * demux,
+ asf_stream_video_format * video, guint16 id,
+ guint8 ** p_data, guint64 * p_size)
+{
+ GstTagList *tags = NULL;
+ GstStructure *caps_s;
+ GstBuffer *extradata = NULL;
+ GstPad *src_pad;
+ GstCaps *caps;
+ gchar *str;
+ gchar *name = NULL;
+ gchar *codec_name = NULL;
+ gint size_left = video->size - 40;
+
+ /* Create the video pad */
+ name = g_strdup_printf ("video_%u", demux->num_video_streams);
+ src_pad = gst_pad_new_from_static_template (&video_src_template, name);
+ g_free (name);
+
+ /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
+ if (size_left) {
+ GST_LOG ("Video header has %d bytes of codec specific data", size_left);
+ g_assert (size_left <= *p_size);
+ gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
+ }
+
+ GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
+
+ /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
+ caps = gst_riff_create_video_caps (video->tag, NULL,
+ (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
+
+ if (caps == NULL) {
+ caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
+ G_TYPE_UINT, video->tag, NULL);
+ } else {
+ GstStructure *s;
+ gint ax, ay;
+
+ s = gst_asf_demux_get_metadata_for_stream (demux, id);
+ if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
+ gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
+ gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ ax, ay, NULL);
+
+ } else {
+ guint ax, ay;
+ /* retry with the global metadata */
+ GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
+ demux->global_metadata);
+ s = demux->global_metadata;
+ if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
+ gst_structure_get_uint (s, "AspectRatioY", &ay)) {
+ GST_DEBUG ("ax:%d, ay:%d", ax, ay);
+ if (ax > 0 && ay > 0)
+ gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ ax, ay, NULL);
+ }
+ }
+ s = gst_caps_get_structure (caps, 0);
+ gst_structure_remove_field (s, "framerate");
+ }
+
+ caps_s = gst_caps_get_structure (caps, 0);
+
+ /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
+ if (gst_structure_has_name (caps_s, "video/x-wmv")) {
+ str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
+ gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
+ g_free (str);
+ }
+
+ if (codec_name) {
+ tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
+ g_free (codec_name);
+ }
+
+ if (extradata)
+ gst_buffer_unref (extradata);
+
+ GST_INFO ("Adding video stream #%u, id %u, codec %"
+ GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
+ GST_FOURCC_ARGS (video->tag), video->tag);
+
+ ++demux->num_video_streams;
+
+ return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
+}
+
+static void
+gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
+{
+ if (!stream->active) {
+ GstEvent *event;
+ gchar *stream_id;
+
+ GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
+ GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
+ gst_pad_set_active (stream->pad, TRUE);
+
+ stream_id =
+ gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
+ "%03u", stream->id);
+
+ event =
+ gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
+ if (event) {
+ if (gst_event_parse_group_id (event, &demux->group_id))
+ demux->have_group_id = TRUE;
+ else
+ demux->have_group_id = FALSE;
+ gst_event_unref (event);
+ } else if (!demux->have_group_id) {
+ demux->have_group_id = TRUE;
+ demux->group_id = gst_util_group_id_next ();
+ }
+
+ event = gst_event_new_stream_start (stream_id);
+ if (demux->have_group_id)
+ gst_event_set_group_id (event, demux->group_id);
+
+ gst_pad_push_event (stream->pad, event);
+ g_free (stream_id);
+ gst_pad_set_caps (stream->pad, stream->caps);
+
+ gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
+ gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
+ stream->active = TRUE;
+ }
+}
+
+static AsfStream *
+gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ AsfCorrectionType correction_type;
+ AsfStreamType stream_type;
+ GstClockTime time_offset;
+ gboolean is_encrypted G_GNUC_UNUSED;
+ guint16 stream_id;
+ guint16 flags;
+ ASFGuid guid;
+ guint stream_specific_size;
+ guint type_specific_size G_GNUC_UNUSED;
+ guint unknown G_GNUC_UNUSED;
+ gboolean inspect_payload = FALSE;
+ AsfStream *stream = NULL;
+
+ /* Get the rest of the header's header */
+ if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
+ goto not_enough_data;
+
+ gst_asf_demux_get_guid (&guid, &data, &size);
+ stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
+
+ gst_asf_demux_get_guid (&guid, &data, &size);
+ correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
+
+ time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
+
+ type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
+ stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
+
+ flags = gst_asf_demux_get_uint16 (&data, &size);
+ stream_id = flags & 0x7f;
+ is_encrypted = ! !((flags & 0x8000) << 15);
+ unknown = gst_asf_demux_get_uint32 (&data, &size);
+
+ GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
+ stream_id, GST_TIME_ARGS (time_offset));
+
+ /* dvr-ms has audio stream declared in stream specific data */
+ if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
+ AsfExtStreamType ext_stream_type;
+ gst_asf_demux_get_guid (&guid, &data, &size);
+ ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
+
+ if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
+ inspect_payload = TRUE;
+
+ gst_asf_demux_get_guid (&guid, &data, &size);
+ gst_asf_demux_get_uint32 (&data, &size);
+ gst_asf_demux_get_uint32 (&data, &size);
+ gst_asf_demux_get_uint32 (&data, &size);
+ gst_asf_demux_get_guid (&guid, &data, &size);
+ gst_asf_demux_get_uint32 (&data, &size);
+ stream_type = ASF_STREAM_AUDIO;
+ }
+ }
+
+ switch (stream_type) {
+ case ASF_STREAM_AUDIO:{
+ asf_stream_audio audio_object;
+
+ if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
+ goto not_enough_data;
+
+ GST_INFO ("Object is an audio stream with %u bytes of additional data",
+ audio_object.size);
+
+ stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
+ &data, &size);
+
+ switch (correction_type) {
+ case ASF_CORRECTION_ON:{
+ guint span, packet_size, chunk_size, data_size, silence_data;
+
+ GST_INFO ("Using error correction");
+
+ if (size < (1 + 2 + 2 + 2 + 1))
+ goto not_enough_data;
+
+ span = gst_asf_demux_get_uint8 (&data, &size);
+ packet_size = gst_asf_demux_get_uint16 (&data, &size);
+ chunk_size = gst_asf_demux_get_uint16 (&data, &size);
+ data_size = gst_asf_demux_get_uint16 (&data, &size);
+ silence_data = gst_asf_demux_get_uint8 (&data, &size);
+
+ stream->span = span;
+
+ GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
+ packet_size, chunk_size, data_size, span, silence_data);
+
+ if (stream->span > 1) {
+ if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
+ /* Disable descrambling */
+ stream->span = 0;
+ } else {
+ /* FIXME: this else branch was added for
+ * weird_al_yankovic - the saga begins.asf */
+ stream->ds_packet_size = packet_size;
+ stream->ds_chunk_size = chunk_size;
+ }
+ } else {
+ /* Descambling is enabled */
+ stream->ds_packet_size = packet_size;
+ stream->ds_chunk_size = chunk_size;
+ }
+#if 0
+ /* Now skip the rest of the silence data */
+ if (data_size > 1)
+ gst_bytestream_flush (demux->bs, data_size - 1);
+#else
+ /* FIXME: CHECKME. And why -1? */
+ if (data_size > 1) {
+ if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
+ goto not_enough_data;
+ }
+ }
+#endif
+ break;
+ }
+ case ASF_CORRECTION_OFF:{
+ GST_INFO ("Error correction off");
+ if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
+ goto not_enough_data;
+ break;
+ }
+ default:
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("Audio stream using unknown error correction"));
+ return NULL;
+ }
+
+ break;
+ }
+
+ case ASF_STREAM_VIDEO:{
+ asf_stream_video_format video_format_object;
+ asf_stream_video video_object;
+ guint16 vsize;
+
+ if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
+ goto not_enough_data;
+
+ vsize = video_object.size - 40; /* Byte order gets offset by single byte */
+
+ GST_INFO ("object is a video stream with %u bytes of "
+ "additional data", vsize);
+
+ if (!gst_asf_demux_get_stream_video_format (&video_format_object,
+ &data, &size)) {
+ goto not_enough_data;
+ }
+
+ stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
+ stream_id, &data, &size);
+
+ break;
+ }
+
+ default:
+ GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
+ stream_id);
+ demux->other_streams =
+ g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
+ break;
+ }
+
+ if (stream)
+ stream->inspect_payload = inspect_payload;
+ return stream;
+
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
+ /* we'll error out later if we found no streams */
+ return NULL;
+ }
+}
+
+static const gchar *
+gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
+{
+ const struct
+ {
+ const gchar *asf_name;
+ const gchar *gst_name;
+ } tags[] = {
+ {
+ "WM/Genre", GST_TAG_GENRE}, {
+ "WM/AlbumTitle", GST_TAG_ALBUM}, {
+ "WM/AlbumArtist", GST_TAG_ARTIST}, {
+ "WM/Picture", GST_TAG_IMAGE}, {
+ "WM/Track", GST_TAG_TRACK_NUMBER}, {
+ "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
+ "WM/Year", GST_TAG_DATE_TIME}
+ /* { "WM/Composer", GST_TAG_COMPOSER } */
+ };
+ gsize out;
+ guint i;
+
+ if (name_utf8 == NULL) {
+ GST_WARNING ("Failed to convert name to UTF8, skipping");
+ return NULL;
+ }
+
+ out = strlen (name_utf8);
+
+ for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
+ if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
+ GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
+ return tags[i].gst_name;
+ }
+ }
+
+ return NULL;
+}
+
+/* gst_asf_demux_add_global_tags() takes ownership of taglist! */
+static void
+gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
+{
+ GstTagList *t;
+
+ GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
+
+ if (taglist == NULL)
+ return;
+
+ if (gst_tag_list_is_empty (taglist)) {
+ gst_tag_list_unref (taglist);
+ return;
+ }
+
+ t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
+ gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
+ if (demux->taglist)
+ gst_tag_list_unref (demux->taglist);
+ gst_tag_list_unref (taglist);
+ demux->taglist = t;
+ GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
+}
+
+#define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
+#define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
+#define ASF_DEMUX_DATA_TYPE_DWORD 3
+
+static void
+asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
+ guint tag_data_len)
+{
+ GstByteReader r;
+ const guint8 *img_data = NULL;
+ guint32 img_data_len = 0;
+ guint8 pic_type = 0;
+
+ gst_byte_reader_init (&r, tag_data, tag_data_len);
+
+ /* skip mime type string (we don't trust it and do our own typefinding),
+ * and also skip the description string, since we don't use it */
+ if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
+ !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
+ !gst_byte_reader_skip_string_utf16 (&r) ||
+ !gst_byte_reader_skip_string_utf16 (&r) ||
+ !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
+ goto not_enough_data;
+ }
+
+
+ if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
+ GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
+
+ return;
+
+not_enough_data:
+ {
+ GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
+ GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
+ return;
+ }
+}
+
+/* Extended Content Description Object */
+static GstFlowReturn
+gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ /* Other known (and unused) 'text/unicode' metadata available :
+ *
+ * WM/Lyrics =
+ * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
+ * WMFSDKVersion = 9.00.00.2980
+ * WMFSDKNeeded = 0.0.0.0000
+ * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
+ * WM/Publisher = 4AD
+ * WM/Provider = AMG
+ * WM/ProviderRating = 8
+ * WM/ProviderStyle = Rock (similar to WM/Genre)
+ * WM/GenreID (similar to WM/Genre)
+ * WM/TrackNumber (same as WM/Track but as a string)
+ *
+ * Other known (and unused) 'non-text' metadata available :
+ *
+ * WM/EncodingTime
+ * WM/MCDI
+ * IsVBR
+ *
+ * We might want to read WM/TrackNumber and use atoi() if we don't have
+ * WM/Track
+ */
+
+ GstTagList *taglist;
+ guint16 blockcount, i;
+
+ GST_INFO_OBJECT (demux, "object is an extended content description");
+
+ taglist = gst_tag_list_new_empty ();
+
+ /* Content Descriptor Count */
+ if (size < 2)
+ goto not_enough_data;
+
+ blockcount = gst_asf_demux_get_uint16 (&data, &size);
+
+ for (i = 1; i <= blockcount; ++i) {
+ const gchar *gst_tag_name;
+ guint16 datatype;
+ guint16 value_len;
+ guint16 name_len;
+ GValue tag_value = { 0, };
+ gsize in, out;
+ gchar *name;
+ gchar *name_utf8 = NULL;
+ gchar *value;
+
+ /* Descriptor */
+ if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
+ goto not_enough_data;
+
+ if (size < 2) {
+ g_free (name);
+ goto not_enough_data;
+ }
+ /* Descriptor Value Data Type */
+ datatype = gst_asf_demux_get_uint16 (&data, &size);
+
+ /* Descriptor Value (not really a string, but same thing reading-wise) */
+ if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
+ g_free (name);
+ goto not_enough_data;
+ }
+
+ name_utf8 =
+ g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
+
+ if (name_utf8 != NULL) {
+ GST_DEBUG ("Found tag/metadata %s", name_utf8);
+
+ gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
+ GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
+
+ switch (datatype) {
+ case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
+ gchar *value_utf8;
+
+ value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
+ &in, &out, NULL);
+
+ /* get rid of tags with empty value */
+ if (value_utf8 != NULL && *value_utf8 != '\0') {
+ GST_DEBUG ("string value %s", value_utf8);
+
+ value_utf8[out] = '\0';
+
+ if (gst_tag_name != NULL) {
+ if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
+ guint year = atoi (value_utf8);
+
+ if (year > 0) {
+ g_value_init (&tag_value, GST_TYPE_DATE_TIME);
+ g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
+ }
+ } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
+ guint id3v1_genre_id;
+ const gchar *genre_str;
+
+ if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
+ ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
+ GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
+ g_free (value_utf8);
+ value_utf8 = g_strdup (genre_str);
+ }
+ } else {
+ GType tag_type;
+
+ /* convert tag from string to other type if required */
+ tag_type = gst_tag_get_type (gst_tag_name);
+ g_value_init (&tag_value, tag_type);
+ if (!gst_value_deserialize (&tag_value, value_utf8)) {
+ GValue from_val = { 0, };
+
+ g_value_init (&from_val, G_TYPE_STRING);
+ g_value_set_string (&from_val, value_utf8);
+ if (!g_value_transform (&from_val, &tag_value)) {
+ GST_WARNING_OBJECT (demux,
+ "Could not transform string tag to " "%s tag type %s",
+ gst_tag_name, g_type_name (tag_type));
+ g_value_unset (&tag_value);
+ }
+ g_value_unset (&from_val);
+ }
+ }
+ } else {
+ /* metadata ! */
+ GST_DEBUG ("Setting metadata");
+ g_value_init (&tag_value, G_TYPE_STRING);
+ g_value_set_string (&tag_value, value_utf8);
+ }
+ } else if (value_utf8 == NULL) {
+ GST_WARNING ("Failed to convert string value to UTF8, skipping");
+ } else {
+ GST_DEBUG ("Skipping empty string value for %s",
+ GST_STR_NULL (gst_tag_name));
+ }
+ g_free (value_utf8);
+ break;
+ }
+ case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
+ if (gst_tag_name) {
+ if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
+ GST_FIXME ("Unhandled byte array tag %s",
+ GST_STR_NULL (gst_tag_name));
+ break;
+ } else {
+ asf_demux_parse_picture_tag (taglist, (guint8 *) value,
+ value_len);
+ }
+ }
+ break;
+ }
+ case ASF_DEMUX_DATA_TYPE_DWORD:{
+ guint uint_val = GST_READ_UINT32_LE (value);
+
+ /* this is the track number */
+ g_value_init (&tag_value, G_TYPE_UINT);
+
+ /* WM/Track counts from 0 */
+ if (!strcmp (name_utf8, "WM/Track"))
+ ++uint_val;
+
+ g_value_set_uint (&tag_value, uint_val);
+ break;
+ }
+ default:{
+ GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
+ break;
+ }
+ }
+
+ if (G_IS_VALUE (&tag_value)) {
+ if (gst_tag_name) {
+ GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
+
+ /* WM/TrackNumber is more reliable than WM/Track, since the latter
+ * is supposed to have a 0 base but is often wrongly written to start
+ * from 1 as well, so prefer WM/TrackNumber when we have it: either
+ * replace the value added earlier from WM/Track or put it first in
+ * the list, so that it will get picked up by _get_uint() */
+ if (strcmp (name_utf8, "WM/TrackNumber") == 0)
+ merge_mode = GST_TAG_MERGE_REPLACE;
+
+ gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
+ &tag_value, NULL);
+ } else {
+ GST_DEBUG ("Setting global metadata %s", name_utf8);
+ gst_structure_set_value (demux->global_metadata, name_utf8,
+ &tag_value);
+ }
+
+ g_value_unset (&tag_value);
+ }
+ }
+
+ g_free (name);
+ g_free (value);
+ g_free (name_utf8);
+ }
+
+ gst_asf_demux_add_global_tags (demux, taglist);
+
+ return GST_FLOW_OK;
+
+ /* Errors */
+not_enough_data:
+ {
+ GST_WARNING ("Unexpected end of data parsing ext content desc object");
+ gst_tag_list_unref (taglist);
+ return GST_FLOW_OK; /* not really fatal */
+ }
+}
+
+static GstStructure *
+gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
+{
+ gchar sname[32];
+ guint i;
+
+ g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
+
+ for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
+ GstStructure *s;
+
+ s = gst_caps_get_structure (demux->metadata, i);
+ if (gst_structure_has_name (s, sname))
+ return s;
+ }
+
+ gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
+
+ /* try lookup again; demux->metadata took ownership of the structure, so we
+ * can't really make any assumptions about what happened to it, so we can't
+ * just return it directly after appending it */
+ return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
+}
+
+static GstFlowReturn
+gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ guint16 blockcount, i;
+
+ GST_INFO_OBJECT (demux, "object is a metadata object");
+
+ /* Content Descriptor Count */
+ if (size < 2)
+ goto not_enough_data;
+
+ blockcount = gst_asf_demux_get_uint16 (&data, &size);
+
+ for (i = 0; i < blockcount; ++i) {
+ GstStructure *s;
+ guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
+ guint32 data_len, ival;
+ gchar *name_utf8;
+
+ if (size < (2 + 2 + 2 + 2 + 4))
+ goto not_enough_data;
+
+ lang_idx = gst_asf_demux_get_uint16 (&data, &size);
+ stream_num = gst_asf_demux_get_uint16 (&data, &size);
+ name_len = gst_asf_demux_get_uint16 (&data, &size);
+ data_type = gst_asf_demux_get_uint16 (&data, &size);
+ data_len = gst_asf_demux_get_uint32 (&data, &size);
+
+ if (size < name_len + data_len)
+ goto not_enough_data;
+
+ /* convert name to UTF-8 */
+ name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
+ NULL, NULL, NULL);
+ gst_asf_demux_skip_bytes (name_len, &data, &size);
+
+ if (name_utf8 == NULL) {
+ GST_WARNING ("Failed to convert value name to UTF8, skipping");
+ gst_asf_demux_skip_bytes (data_len, &data, &size);
+ continue;
+ }
+
+ if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
+ gst_asf_demux_skip_bytes (data_len, &data, &size);
+ g_free (name_utf8);
+ continue;
+ }
+
+ /* read DWORD */
+ if (size < 4) {
+ g_free (name_utf8);
+ goto not_enough_data;
+ }
+
+ ival = gst_asf_demux_get_uint32 (&data, &size);
+
+ /* skip anything else there may be, just in case */
+ gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
+
+ s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
+ gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
+ g_free (name_utf8);
+ }
+
+ GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
+ return GST_FLOW_OK;
+
+ /* Errors */
+not_enough_data:
+ {
+ GST_WARNING ("Unexpected end of data parsing metadata object");
+ return GST_FLOW_OK; /* not really fatal */
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint32 i, num_objects;
+ guint8 unknown G_GNUC_UNUSED;
+
+ /* Get the rest of the header's header */
+ if (size < (4 + 1 + 1))
+ goto not_enough_data;
+
+ num_objects = gst_asf_demux_get_uint32 (&data, &size);
+ unknown = gst_asf_demux_get_uint8 (&data, &size);
+ unknown = gst_asf_demux_get_uint8 (&data, &size);
+
+ GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
+
+ /* Loop through the header's objects, processing those */
+ for (i = 0; i < num_objects; ++i) {
+ GST_INFO_OBJECT (demux, "reading header part %u", i);
+ ret = gst_asf_demux_process_object (demux, &data, &size);
+ if (ret != GST_FLOW_OK) {
+ GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
+ break;
+ }
+ }
+
+ return ret;
+
+not_enough_data:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("short read parsing HEADER object"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
+{
+ guint64 creation_time G_GNUC_UNUSED;
+ guint64 file_size G_GNUC_UNUSED;
+ guint64 send_time G_GNUC_UNUSED;
+ guint64 packets_count, play_time, preroll;
+ guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
+
+ if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
+ goto not_enough_data;
+
+ gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
+ file_size = gst_asf_demux_get_uint64 (&data, &size);
+ creation_time = gst_asf_demux_get_uint64 (&data, &size);
+ packets_count = gst_asf_demux_get_uint64 (&data, &size);
+ play_time = gst_asf_demux_get_uint64 (&data, &size);
+ send_time = gst_asf_demux_get_uint64 (&data, &size);
+ preroll = gst_asf_demux_get_uint64 (&data, &size);
+ flags = gst_asf_demux_get_uint32 (&data, &size);
+ min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
+ max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
+ min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
+
+ demux->broadcast = ! !(flags & 0x01);
+ demux->seekable = ! !(flags & 0x02);
+
+ GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
+ GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
+ GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
+
+ if (demux->broadcast) {
+ /* these fields are invalid if the broadcast flag is set */
+ play_time = 0;
+ file_size = 0;
+ }
+
+ if (min_pktsize != max_pktsize)
+ goto non_fixed_packet_size;
+
+ demux->packet_size = max_pktsize;
+
+ /* FIXME: do we need send_time as well? what is it? */
+ if ((play_time * 100) >= (preroll * GST_MSECOND))
+ demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
+ else
+ demux->play_time = 0;
+
+ demux->preroll = preroll * GST_MSECOND;
+
+ /* initial latency */
+ demux->latency = demux->preroll;
+
+ if (demux->play_time == 0)
+ demux->seekable = FALSE;
+
+ GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->play_time));
+ GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->preroll));
+
+ if (demux->play_time > 0) {
+ demux->segment.duration = demux->play_time;
+ }
+
+ GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
+ packets_count);
+ GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
+
+ return GST_FLOW_OK;
+
+/* ERRORS */
+non_fixed_packet_size:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("packet size must be fixed"));
+ return GST_FLOW_ERROR;
+ }
+not_enough_data:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("short read parsing FILE object"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+/* Content Description Object */
+static GstFlowReturn
+gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
+{
+ struct
+ {
+ const gchar *gst_tag;
+ guint16 val_length;
+ gchar *val_utf8;
+ } tags[5] = {
+ {
+ GST_TAG_TITLE, 0, NULL}, {
+ GST_TAG_ARTIST, 0, NULL}, {
+ GST_TAG_COPYRIGHT, 0, NULL}, {
+ GST_TAG_DESCRIPTION, 0, NULL}, {
+ GST_TAG_COMMENT, 0, NULL}
+ };
+ GstTagList *taglist;
+ GValue value = { 0 };
+ gsize in, out;
+ gint i = -1;
+
+ GST_INFO_OBJECT (demux, "object is a comment");
+
+ if (size < (2 + 2 + 2 + 2 + 2))
+ goto not_enough_data;
+
+ tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
+ tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
+ tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
+ tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
+ tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
+
+ GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
+ "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
+ tags[2].val_length, tags[3].val_length, tags[4].val_length);
+
+ for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
+ if (size < tags[i].val_length)
+ goto not_enough_data;
+
+ /* might be just '/0', '/0'... */
+ if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
+ /* convert to UTF-8 */
+ tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
+ "UTF-8", "UTF-16LE", &in, &out, NULL);
+ }
+ gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
+ }
+
+ /* parse metadata into taglist */
+ taglist = gst_tag_list_new_empty ();
+ g_value_init (&value, G_TYPE_STRING);
+ for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
+ if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
+ g_value_set_string (&value, tags[i].val_utf8);
+ gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
+ tags[i].gst_tag, &value, NULL);
+ }
+ }
+ g_value_unset (&value);
+
+ gst_asf_demux_add_global_tags (demux, taglist);
+
+ for (i = 0; i < G_N_ELEMENTS (tags); ++i)
+ g_free (tags[i].val_utf8);
+
+ return GST_FLOW_OK;
+
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
+ "comment tag section %d, skipping comment object", i);
+ for (i = 0; i < G_N_ELEMENTS (tags); i++)
+ g_free (tags[i].val_utf8);
+ return GST_FLOW_OK; /* not really fatal */
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ guint16 num_streams, i;
+ AsfStream *stream;
+
+ if (size < 2)
+ goto not_enough_data;
+
+ num_streams = gst_asf_demux_get_uint16 (&data, &size);
+
+ GST_INFO ("object is a bitrate properties object with %u streams",
+ num_streams);
+
+ if (size < (num_streams * (2 + 4)))
+ goto not_enough_data;
+
+ for (i = 0; i < num_streams; ++i) {
+ guint32 bitrate;
+ guint16 stream_id;
+
+ stream_id = gst_asf_demux_get_uint16 (&data, &size);
+ bitrate = gst_asf_demux_get_uint32 (&data, &size);
+
+ if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
+ GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
+ stream = gst_asf_demux_get_stream (demux, stream_id);
+ if (stream) {
+ if (stream->pending_tags == NULL) {
+ stream->pending_tags =
+ gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
+ }
+ } else {
+ GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
+ }
+ } else {
+ GST_WARNING ("stream id %u is too large", stream_id);
+ }
+ }
+
+ return GST_FLOW_OK;
+
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
+ return GST_FLOW_OK; /* not really fatal */
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint64 hdr_size;
+
+ /* Get the rest of the header's header */
+ if (size < (16 + 2 + 4))
+ goto not_enough_data;
+
+ /* skip GUID and two other bytes */
+ gst_asf_demux_skip_bytes (16 + 2, &data, &size);
+ hdr_size = gst_asf_demux_get_uint32 (&data, &size);
+
+ GST_INFO ("extended header object with a size of %u bytes", (guint) size);
+
+ /* FIXME: does data_size include the rest of the header that we have read? */
+ if (hdr_size > size)
+ goto not_enough_data;
+
+ while (hdr_size > 0) {
+ ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
+ if (ret != GST_FLOW_OK)
+ break;
+ }
+
+ return ret;
+
+not_enough_data:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("short read parsing extended header object"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ guint i;
+
+ if (size < 2)
+ goto not_enough_data;
+
+ if (demux->languages) {
+ GST_WARNING ("More than one LANGUAGE_LIST object in stream");
+ g_strfreev (demux->languages);
+ demux->languages = NULL;
+ demux->num_languages = 0;
+ }
+
+ demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
+ GST_LOG ("%u languages:", demux->num_languages);
+
+ demux->languages = g_new0 (gchar *, demux->num_languages + 1);
+ for (i = 0; i < demux->num_languages; ++i) {
+ guint8 len, *lang_data = NULL;
+
+ if (size < 1)
+ goto not_enough_data;
+ len = gst_asf_demux_get_uint8 (&data, &size);
+ if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
+ gchar *utf8;
+
+ utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
+ NULL, NULL);
+
+ /* truncate "en-us" etc. to just "en" */
+ if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
+ utf8[2] = '\0';
+ }
+ GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
+ demux->languages[i] = utf8;
+ g_free (lang_data);
+ } else {
+ goto not_enough_data;
+ }
+ }
+
+ return GST_FLOW_OK;
+
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "short read parsing language list object!");
+ g_free (demux->languages);
+ demux->languages = NULL;
+ return GST_FLOW_OK; /* not fatal */
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ GstClockTime interval;
+ guint32 count, i;
+
+ if (size < (16 + 8 + 4 + 4))
+ goto not_enough_data;
+
+ /* skip file id */
+ gst_asf_demux_skip_bytes (16, &data, &size);
+ interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
+ gst_asf_demux_skip_bytes (4, &data, &size);
+ count = gst_asf_demux_get_uint32 (&data, &size);
+ if (count > 0) {
+ demux->sidx_interval = interval;
+ demux->sidx_num_entries = count;
+ g_free (demux->sidx_entries);
+ demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
+
+ for (i = 0; i < count; ++i) {
+ if (G_UNLIKELY (size < 6)) {
+ /* adjust for broken files, to avoid having entries at the end
+ * of the parsed index that point to time=0. Resulting in seeking to
+ * the end of the file leading back to the beginning */
+ demux->sidx_num_entries -= (count - i);
+ break;
+ }
+ demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
+ demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
+ GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
+ GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
+ demux->sidx_entries[i].count);
+ }
+ } else {
+ GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
+ }
+
+ return GST_FLOW_OK;
+
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
+ return GST_FLOW_OK; /* not fatal */
+ }
+}
+
+static GstFlowReturn
+gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
+ guint8 * data, guint64 size)
+{
+ ASFGuid guid;
+ guint16 num, i;
+ guint8 *mes;
+
+ if (size < 16 + 2 + (2 * 2))
+ goto not_enough_data;
+
+ gst_asf_demux_get_guid (&guid, &data, &size);
+ num = gst_asf_demux_get_uint16 (&data, &size);
+
+ if (num < 2) {
+ GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
+ return GST_FLOW_OK;
+ }
+
+ if (size < (num * sizeof (guint16)))
+ goto not_enough_data;
+
+ /* read mutually exclusive stream numbers */
+ mes = g_new (guint8, num + 1);
+ for (i = 0; i < num; ++i) {
+ mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
+ GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
+ }
+
+ /* add terminator so we can easily get the count or know when to stop */
+ mes[i] = (guint8) - 1;
+
+ demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
+
+ return GST_FLOW_OK;
+
+ /* Errors */
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
+ return GST_FLOW_OK; /* not absolutely fatal */
+ }
+}
+
+gboolean
+gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
+{
+ return g_slist_find (demux->other_streams,
+ GINT_TO_POINTER (stream_num)) == NULL;
+}
+
+static GstFlowReturn
+gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
+ guint64 size)
+{
+ AsfStreamExtProps esp;
+ AsfStream *stream = NULL;
+ AsfObject stream_obj;
+ guint16 stream_name_count;
+ guint16 num_payload_ext;
+ guint64 len;
+ guint8 *stream_obj_data = NULL;
+ guint8 *data_start;
+ guint obj_size;
+ guint i, stream_num;
+
+ data_start = data;
+ obj_size = (guint) size;
+
+ if (size < 64)
+ goto not_enough_data;
+
+ esp.valid = TRUE;
+ esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
+ esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
+ esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
+ esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
+ esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
+ esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
+ esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
+ esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
+ esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
+ esp.flags = gst_asf_demux_get_uint32 (&data, &size);
+ stream_num = gst_asf_demux_get_uint16 (&data, &size);
+ esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
+ esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
+ stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
+ num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
+
+ GST_INFO ("start_time = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (esp.start_time));
+ GST_INFO ("end_time = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (esp.end_time));
+ GST_INFO ("flags = %08x", esp.flags);
+ GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (esp.avg_time_per_frame * 100));
+ GST_INFO ("stream number = %u", stream_num);
+ GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
+ (esp.lang_idx < demux->num_languages) ?
+ GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
+ GST_INFO ("stream name count = %u", stream_name_count);
+
+ /* read stream names */
+ for (i = 0; i < stream_name_count; ++i) {
+ guint16 stream_lang_idx G_GNUC_UNUSED;
+ gchar *stream_name = NULL;
+
+ if (size < 2)
+ goto not_enough_data;
+ stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
+ if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
+ goto not_enough_data;
+ GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
+ g_free (stream_name); /* TODO: store names in struct */
+ }
+
+ /* read payload extension systems stuff */
+ GST_LOG ("payload extension systems count = %u", num_payload_ext);
+
+ if (num_payload_ext > 0)
+ esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
+ else
+ esp.payload_extensions = NULL;
+
+ for (i = 0; i < num_payload_ext; ++i) {
+ AsfPayloadExtension ext;
+ ASFGuid ext_guid;
+ guint32 sys_info_len;
+
+ if (size < 16 + 2 + 4)
+ goto not_enough_data;
+
+ gst_asf_demux_get_guid (&ext_guid, &data, &size);
+ ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
+ ext.len = gst_asf_demux_get_uint16 (&data, &size);
+
+ sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
+ GST_LOG ("payload systems info len = %u", sys_info_len);
+ if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
+ goto not_enough_data;
+
+ esp.payload_extensions[i] = ext;
+ }
+
+ GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
+
+ /* there might be an optional STREAM_INFO object here now; if not, we
+ * should have parsed the corresponding stream info object already (since
+ * we are parsing the extended stream properties objects delayed) */
+ if (size == 0) {
+ stream = gst_asf_demux_get_stream (demux, stream_num);
+ goto done;
+ }
+
+ /* get size of the stream object */
+ if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
+ goto not_enough_data;
+
+ if (stream_obj.id != ASF_OBJ_STREAM)
+ goto expected_stream_object;
+
+ if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
+ stream_obj.size > (10 * 1024 * 1024))
+ goto not_enough_data;
+
+ gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
+
+ /* process this stream object later after all the other 'normal' ones
+ * have been processed (since the others are more important/non-hidden) */
+ len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
+ if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
+ goto not_enough_data;
+
+ /* parse stream object */
+ stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
+ g_free (stream_obj_data);
+
+done:
+
+ if (stream) {
+ stream->ext_props = esp;
+
+ /* try to set the framerate */
+ if (stream->is_video && stream->caps) {
+ GValue framerate = { 0 };
+ GstStructure *s;
+ gint num, denom;
+
+ g_value_init (&framerate, GST_TYPE_FRACTION);
+
+ num = GST_SECOND / 100;
+ denom = esp.avg_time_per_frame;
+ if (denom == 0) {
+ /* avoid division by 0, assume 25/1 framerate */
+ denom = GST_SECOND / 2500;
+ }
+
+ gst_value_set_fraction (&framerate, num, denom);
+
+ stream->caps = gst_caps_make_writable (stream->caps);
+ s = gst_caps_get_structure (stream->caps, 0);
+ gst_structure_set_value (s, "framerate", &framerate);
+ g_value_unset (&framerate);
+ GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
+ num, denom, ((gdouble) num) / denom);
+ }
+
+ /* add language info now if we have it */
+ if (stream->ext_props.lang_idx < demux->num_languages) {
+ if (stream->pending_tags == NULL)
+ stream->pending_tags = gst_tag_list_new_empty ();
+ GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
+ demux->languages[stream->ext_props.lang_idx]);
+ gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
+ GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
+ NULL);
+ }
+ } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
+ GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
+ }
+
+ return GST_FLOW_OK;
+
+ /* Errors */
+not_enough_data:
+ {
+ GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
+ return GST_FLOW_OK; /* not absolutely fatal */
+ }
+expected_stream_object:
+ {
+ GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
+ "object: expected embedded stream object, but got %s object instead!",
+ gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
+ return GST_FLOW_OK; /* not absolutely fatal */
+ }
+}
+
+static const gchar *
+gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
+{
+ const gchar *nick;
+
+ nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
+ if (g_str_has_prefix (nick, "ASF_OBJ_"))
+ nick += strlen ("ASF_OBJ_");
+
+ if (demux->objpath == NULL) {
+ demux->objpath = g_strdup (nick);
+ } else {
+ gchar *newpath;
+
+ newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
+ g_free (demux->objpath);
+ demux->objpath = newpath;
+ }
+
+ return (const gchar *) demux->objpath;
+}
+
+static void
+gst_asf_demux_pop_obj (GstASFDemux * demux)
+{
+ gchar *s;
+
+ if ((s = g_strrstr (demux->objpath, "/"))) {
+ *s = '\0';
+ } else {
+ g_free (demux->objpath);
+ demux->objpath = NULL;
+ }
+}
+
+static void
+gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
+{
+ GSList *l;
+ guint i;
+
+ /* Parse the queued extended stream property objects and add the info
+ * to the existing streams or add the new embedded streams, but without
+ * activating them yet */
+ GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
+ g_slist_length (demux->ext_stream_props));
+
+ for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
+ GstBuffer *buf = GST_BUFFER (l->data);
+ GstMapInfo map;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
+ gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+ }
+ g_slist_free (demux->ext_stream_props);
+ demux->ext_stream_props = NULL;
+}
+
+#if 0
+static void
+gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
+{
+ guint i, j;
+
+ for (i = 0; i < demux->num_streams; ++i) {
+ AsfStream *stream;
+ gboolean is_hidden;
+ GSList *x;
+
+ stream = &demux->stream[i];
+
+ GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
+
+ if (stream->active) {
+ GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
+ continue;
+ }
+
+ is_hidden = FALSE;
+ for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
+ guint8 *mes;
+
+ /* check for each mutual exclusion whether it affects this stream */
+ for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
+ if (*mes == stream->id) {
+ /* if yes, check if we've already added streams that are mutually
+ * exclusive with the stream we're about to add */
+ for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
+ for (j = 0; j < demux->num_streams; ++j) {
+ /* if the broadcast flag is set, assume the hidden streams aren't
+ * actually streamed and hide them (or playbin won't work right),
+ * otherwise assume their data is available */
+ if (demux->stream[j].id == *mes && demux->broadcast) {
+ is_hidden = TRUE;
+ GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
+ "mutually exclusive with already existing stream ID %d, "
+ "hiding stream", stream->id, demux->stream[j].id);
+ goto next;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ next:
+
+ /* FIXME: we should do stream activation based on preroll data in
+ * streaming mode too */
+ if (demux->streaming && !is_hidden)
+ gst_asf_demux_activate_stream (demux, stream);
+ }
+}
+#endif
+
+static GstFlowReturn
+gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
+ guint64 * p_size)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ AsfObject obj;
+ guint64 obj_data_size;
+
+ if (*p_size < ASF_OBJECT_HEADER_SIZE)
+ return ASF_FLOW_NEED_MORE_DATA;
+
+ asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+ gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
+
+ obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
+
+ if (*p_size < obj_data_size)
+ return ASF_FLOW_NEED_MORE_DATA;
+
+ gst_asf_demux_push_obj (demux, obj.id);
+
+ GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
+
+ switch (obj.id) {
+ case ASF_OBJ_STREAM:
+ gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
+ ret = GST_FLOW_OK;
+ break;
+ case ASF_OBJ_FILE:
+ ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_HEADER:
+ ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_COMMENT:
+ ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_HEAD1:
+ ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_BITRATE_PROPS:
+ ret =
+ gst_asf_demux_process_bitrate_props_object (demux, *p_data,
+ obj_data_size);
+ break;
+ case ASF_OBJ_EXT_CONTENT_DESC:
+ ret =
+ gst_asf_demux_process_ext_content_desc (demux, *p_data,
+ obj_data_size);
+ break;
+ case ASF_OBJ_METADATA_OBJECT:
+ ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_EXTENDED_STREAM_PROPS:{
+ GstBuffer *buf;
+
+ /* process these later, we might not have parsed the corresponding
+ * stream object yet */
+ GST_LOG ("%s: queued for later parsing", demux->objpath);
+ buf = gst_buffer_new_and_alloc (obj_data_size);
+ gst_buffer_fill (buf, 0, *p_data, obj_data_size);
+ demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
+ ret = GST_FLOW_OK;
+ break;
+ }
+ case ASF_OBJ_LANGUAGE_LIST:
+ ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
+ ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
+ obj_data_size);
+ break;
+ case ASF_OBJ_SIMPLE_INDEX:
+ ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
+ break;
+ case ASF_OBJ_CONTENT_ENCRYPTION:
+ case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
+ case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
+ case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
+ goto error_encrypted;
+ case ASF_OBJ_CONCEAL_NONE:
+ case ASF_OBJ_HEAD2:
+ case ASF_OBJ_UNDEFINED:
+ case ASF_OBJ_CODEC_COMMENT:
+ case ASF_OBJ_INDEX:
+ case ASF_OBJ_PADDING:
+ case ASF_OBJ_BITRATE_MUTEX:
+ case ASF_OBJ_COMPATIBILITY:
+ case ASF_OBJ_INDEX_PLACEHOLDER:
+ case ASF_OBJ_INDEX_PARAMETERS:
+ case ASF_OBJ_STREAM_PRIORITIZATION:
+ case ASF_OBJ_SCRIPT_COMMAND:
+ case ASF_OBJ_METADATA_LIBRARY_OBJECT:
+ default:
+ /* Unknown/unhandled object, skip it and hope for the best */
+ GST_INFO ("%s: skipping object", demux->objpath);
+ ret = GST_FLOW_OK;
+ break;
+ }
+
+ /* this can't fail, we checked the number of bytes available before */
+ gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
+
+ GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
+
+ gst_asf_demux_pop_obj (demux);
+
+ return ret;
+
+/* ERRORS */
+error_encrypted:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static void
+gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
+ GstBuffer ** p_buffer)
+{
+ GstBuffer *descrambled_buffer;
+ GstBuffer *scrambled_buffer;
+ GstBuffer *sub_buffer;
+ guint offset;
+ guint off;
+ guint row;
+ guint col;
+ guint idx;
+
+ /* descrambled_buffer is initialised in the first iteration */
+ descrambled_buffer = NULL;
+ scrambled_buffer = *p_buffer;
+
+ if (gst_buffer_get_size (scrambled_buffer) <
+ stream->ds_packet_size * stream->span)
+ return;
+
+ for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
+ offset += stream->ds_chunk_size) {
+ off = offset / stream->ds_chunk_size;
+ row = off / stream->span;
+ col = off % stream->span;
+ idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
+ GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
+ col, off, stream->ds_chunk_size);
+ GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
+ ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
+ stream->span, stream->ds_packet_size);
+ GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (scrambled_buffer));
+ sub_buffer =
+ gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
+ idx * stream->ds_chunk_size, stream->ds_chunk_size);
+ if (!offset) {
+ descrambled_buffer = sub_buffer;
+ } else {
+ descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
+ }
+ }
+
+ GST_BUFFER_TIMESTAMP (descrambled_buffer) =
+ GST_BUFFER_TIMESTAMP (scrambled_buffer);
+ GST_BUFFER_DURATION (descrambled_buffer) =
+ GST_BUFFER_DURATION (scrambled_buffer);
+ GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
+ GST_BUFFER_OFFSET_END (descrambled_buffer) =
+ GST_BUFFER_OFFSET_END (scrambled_buffer);
+
+ /* FIXME/CHECK: do we need to transfer buffer flags here too? */
+
+ gst_buffer_unref (scrambled_buffer);
+ *p_buffer = descrambled_buffer;
+}
+
+static gboolean
+gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
+{
+ GstASFDemux *demux = GST_ASF_DEMUX (element);
+ gint i;
+
+ GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
+
+ for (i = 0; i < demux->num_streams; ++i) {
+ gst_event_ref (event);
+ if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
+ GST_OBJECT_CAST (element), event)) {
+ gst_event_unref (event);
+ return TRUE;
+ }
+ }
+
+ gst_event_unref (event);
+ return FALSE;
+}
+
+/* takes ownership of the passed event */
+static gboolean
+gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
+{
+ gboolean ret = TRUE;
+ gint i;
+
+ GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
+ GST_EVENT_TYPE_NAME (event));
+
+ for (i = 0; i < demux->num_streams; ++i) {
+ gst_event_ref (event);
+ ret &= gst_pad_push_event (demux->stream[i].pad, event);
+ }
+ gst_event_unref (event);
+ return ret;
+}
+
+static gboolean
+gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
+ GstQuery * query)
+{
+ GstASFDemux *demux;
+ gboolean res = FALSE;
+
+ demux = GST_ASF_DEMUX (parent);
+
+ GST_DEBUG ("handling %s query",
+ gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_DURATION:
+ {
+ GstFormat format;
+
+ gst_query_parse_duration (query, &format, NULL);
+
+ if (format != GST_FORMAT_TIME) {
+ GST_LOG ("only support duration queries in TIME format");
+ break;
+ }
+
+ res = gst_pad_query_default (pad, parent, query);
+ if (!res) {
+ GST_OBJECT_LOCK (demux);
+
+ if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
+ GST_LOG ("returning duration: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->segment.duration));
+
+ gst_query_set_duration (query, GST_FORMAT_TIME,
+ demux->segment.duration);
+
+ res = TRUE;
+ } else {
+ GST_LOG ("duration not known yet");
+ }
+
+ GST_OBJECT_UNLOCK (demux);
+ }
+ break;
+ }
+
+ case GST_QUERY_POSITION:{
+ GstFormat format;
+
+ gst_query_parse_position (query, &format, NULL);
+
+ if (format != GST_FORMAT_TIME) {
+ GST_LOG ("only support position queries in TIME format");
+ break;
+ }
+
+ GST_OBJECT_LOCK (demux);
+
+ if (demux->segment.position != GST_CLOCK_TIME_NONE) {
+ GST_LOG ("returning position: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->segment.position));
+
+ gst_query_set_position (query, GST_FORMAT_TIME,
+ demux->segment.position);
+
+ res = TRUE;
+ } else {
+ GST_LOG ("position not known yet");
+ }
+
+ GST_OBJECT_UNLOCK (demux);
+ break;
+ }
+
+ case GST_QUERY_SEEKING:{
+ GstFormat format;
+
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+ if (format == GST_FORMAT_TIME) {
+ gint64 duration;
+
+ GST_OBJECT_LOCK (demux);
+ duration = demux->segment.duration;
+ GST_OBJECT_UNLOCK (demux);
+
+ if (!demux->streaming || !demux->seekable) {
+ gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
+ duration);
+ res = TRUE;
+ } else {
+ GstFormat fmt;
+ gboolean seekable;
+
+ /* try downstream first in TIME */
+ res = gst_pad_query_default (pad, parent, query);
+
+ gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
+ GST_LOG_OBJECT (demux, "upstream %s seekable %d",
+ GST_STR_NULL (gst_format_get_name (fmt)), seekable);
+ /* if no luck, maybe in BYTES */
+ if (!seekable || fmt != GST_FORMAT_TIME) {
+ GstQuery *q;
+
+ q = gst_query_new_seeking (GST_FORMAT_BYTES);
+ if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
+ gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
+ GST_LOG_OBJECT (demux, "upstream %s seekable %d",
+ GST_STR_NULL (gst_format_get_name (fmt)), seekable);
+ if (fmt != GST_FORMAT_BYTES)
+ seekable = FALSE;
+ }
+ gst_query_unref (q);
+ gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
+ duration);
+ res = TRUE;
+ }
+ }
+ } else
+ GST_LOG_OBJECT (demux, "only support seeking in TIME format");
+ break;
+ }
+
+ case GST_QUERY_LATENCY:
+ {
+ gboolean live;
+ GstClockTime min, max;
+
+ /* preroll delay does not matter in non-live pipeline,
+ * but we might end up in a live (rtsp) one ... */
+
+ /* first forward */
+ res = gst_pad_query_default (pad, parent, query);
+ if (!res)
+ break;
+
+ gst_query_parse_latency (query, &live, &min, &max);
+
+ GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
+ GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
+ GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+ GST_OBJECT_LOCK (demux);
+ if (min != -1)
+ min += demux->latency;
+ if (max != -1)
+ max += demux->latency;
+ GST_OBJECT_UNLOCK (demux);
+
+ gst_query_set_latency (query, live, min, max);
+ break;
+ }
+ case GST_QUERY_SEGMENT:
+ {
+ GstFormat format;
+ gint64 start, stop;
+
+ format = demux->segment.format;
+
+ start =
+ gst_segment_to_stream_time (&demux->segment, format,
+ demux->segment.start);
+ if ((stop = demux->segment.stop) == -1)
+ stop = demux->segment.duration;
+ else
+ stop = gst_segment_to_stream_time (&demux->segment, format, stop);
+
+ gst_query_set_segment (query, demux->segment.rate, format, start, stop);
+ res = TRUE;
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, parent, query);
+ break;
+ }
+
+ return res;
+}
+
+static GstStateChangeReturn
+gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstASFDemux *demux = GST_ASF_DEMUX (element);
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:{
+ gst_segment_init (&demux->segment, GST_FORMAT_TIME);
+ demux->need_newsegment = TRUE;
+ demux->segment_running = FALSE;
+ demux->accurate = FALSE;
+ demux->adapter = gst_adapter_new ();
+ demux->metadata = gst_caps_new_empty ();
+ demux->global_metadata = gst_structure_new_empty ("metadata");
+ demux->data_size = 0;
+ demux->data_offset = 0;
+ demux->index_offset = 0;
+ demux->base_offset = 0;
+ demux->flowcombiner = gst_flow_combiner_new ();
+ break;
+ }
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_asf_demux_reset (demux, FALSE);
+ break;
+
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_asf_demux_reset (demux, FALSE);
+ gst_flow_combiner_free (demux->flowcombiner);
+ demux->flowcombiner = NULL;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h
new file mode 100644
index 0000000..46e1e13
--- /dev/null
+++ b/gst/asfdemux/gstasfdemux.h
@@ -0,0 +1,223 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __ASF_DEMUX_H__
+#define __ASF_DEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
+
+#include "asfheaders.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ASF_DEMUX \
+ (gst_asf_demux_get_type())
+#define GST_ASF_DEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASF_DEMUX,GstASFDemux))
+#define GST_ASF_DEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASF_DEMUX,GstASFDemuxClass))
+#define GST_IS_ASF_DEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASF_DEMUX))
+#define GST_IS_ASF_DEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASF_DEMUX))
+
+GST_DEBUG_CATEGORY_EXTERN (asfdemux_dbg);
+#define GST_CAT_DEFAULT asfdemux_dbg
+
+typedef struct _GstASFDemux GstASFDemux;
+typedef struct _GstASFDemuxClass GstASFDemuxClass;
+
+typedef struct {
+ guint32 packet;
+ guint16 count;
+} AsfSimpleIndexEntry;
+
+typedef struct {
+ AsfPayloadExtensionID id : 16; /* extension ID; the :16 makes sure the
+ * struct gets packed into 4 bytes */
+ guint16 len; /* save this so we can skip unknown IDs */
+} AsfPayloadExtension;
+
+typedef struct
+{
+ gboolean valid; /* TRUE if structure is valid/filled */
+
+ GstClockTime start_time;
+ GstClockTime end_time;
+ GstClockTime avg_time_per_frame;
+ guint32 data_bitrate;
+ guint32 buffer_size;
+ guint32 intial_buf_fullness;
+ guint32 data_bitrate2;
+ guint32 buffer_size2;
+ guint32 intial_buf_fullness2;
+ guint32 max_obj_size;
+ guint32 flags;
+ guint16 lang_idx;
+
+ /* may be NULL if there are no extensions; otherwise, terminated by
+ * an AsfPayloadExtension record with len 0 */
+ AsfPayloadExtension *payload_extensions;
+
+ /* missing: stream names */
+} AsfStreamExtProps;
+
+typedef struct
+{
+ AsfStreamType type;
+
+ gboolean active; /* if the stream has been activated (pad added) */
+
+ GstPad *pad;
+ guint16 id;
+
+ /* video-only */
+ gboolean is_video;
+ gboolean fps_known;
+
+ GstCaps *caps;
+
+ GstTagList *pending_tags;
+
+ gboolean discont;
+
+ /* Descrambler settings */
+ guint8 span;
+ guint16 ds_packet_size;
+ guint16 ds_chunk_size;
+ guint16 ds_data_size;
+
+ /* for new parsing code */
+ GArray *payloads; /* pending payloads */
+
+ /* Video stream PAR & interlacing */
+ guint8 par_x;
+ guint8 par_y;
+ gboolean interlaced;
+
+ /* extended stream properties (optional) */
+ AsfStreamExtProps ext_props;
+
+ gboolean inspect_payload;
+} AsfStream;
+
+typedef enum {
+ GST_ASF_DEMUX_STATE_HEADER,
+ GST_ASF_DEMUX_STATE_DATA,
+ GST_ASF_DEMUX_STATE_INDEX
+} GstASFDemuxState;
+
+#define GST_ASF_DEMUX_NUM_VIDEO_PADS 16
+#define GST_ASF_DEMUX_NUM_AUDIO_PADS 32
+#define GST_ASF_DEMUX_NUM_STREAMS 32
+#define GST_ASF_DEMUX_NUM_STREAM_IDS 127
+
+struct _GstASFDemux {
+ GstElement element;
+
+ GstPad *sinkpad;
+
+ gboolean have_group_id;
+ guint group_id;
+
+ GstAdapter *adapter;
+ GstTagList *taglist;
+ GstASFDemuxState state;
+
+ /* byte offset where the asf starts, which might not be zero on chained
+ * asfs, index_offset and data_offset already are 'offseted' by base_offset */
+ guint64 base_offset;
+
+ guint64 index_offset; /* byte offset where index might be, or 0 */
+ guint64 data_offset; /* byte offset where packets start */
+ guint64 data_size; /* total size of packet data in bytes, or 0 */
+ guint64 num_packets; /* total number of data packets, or 0 */
+ gint64 packet; /* current packet */
+ guint speed_packets; /* Known number of packets to get in one go*/
+
+ gchar **languages;
+ guint num_languages;
+
+ GstCaps *metadata; /* metadata, for delayed parsing; one
+ * structure ('stream-N') per stream */
+ GstStructure *global_metadata; /* metadata which isn't specific to one stream */
+ GSList *ext_stream_props; /* for delayed processing (buffers) */
+ GSList *mut_ex_streams; /* mutually exclusive streams */
+
+ guint32 num_audio_streams;
+ guint32 num_video_streams;
+ guint32 num_streams;
+ AsfStream stream[GST_ASF_DEMUX_NUM_STREAMS];
+ gboolean activated_streams;
+ GstFlowCombiner *flowcombiner;
+
+ /* for chained asf handling, we need to hold the old asf streams until
+ * we detect the new ones */
+ AsfStream old_stream[GST_ASF_DEMUX_NUM_STREAMS];
+ gboolean old_num_streams;
+
+ GstClockTime first_ts; /* smallest timestamp found */
+
+ guint32 packet_size;
+ guint64 play_time;
+
+ guint64 preroll;
+
+ gboolean seekable;
+ gboolean broadcast;
+
+ GstSegment segment; /* configured play segment */
+ gboolean accurate;
+
+ gboolean need_newsegment; /* do we need to send a new-segment event? */
+ guint32 segment_seqnum; /* if the new segment must have this seqnum */
+ GstClockTime segment_ts; /* streaming; timestamp for segment start */
+ GstSegment in_segment; /* streaming; upstream segment info */
+ GstClockTime in_gap; /* streaming; upstream initial segment gap for interpolation */
+ gboolean segment_running; /* if we've started the current segment */
+ gboolean streaming; /* TRUE if we are operating chain-based */
+ GstClockTime latency;
+
+ /* for debugging only */
+ gchar *objpath;
+
+ /* simple index, if available */
+ GstClockTime sidx_interval; /* interval between entries in ns */
+ guint sidx_num_entries; /* number of index entries */
+ AsfSimpleIndexEntry *sidx_entries; /* packet number for each entry */
+
+ GSList *other_streams; /* remember streams that are in header but have unknown type */
+};
+
+struct _GstASFDemuxClass {
+ GstElementClass parent_class;
+};
+
+GType gst_asf_demux_get_type (void);
+
+AsfStream * gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id);
+
+gboolean gst_asf_demux_is_unknown_stream(GstASFDemux *demux, guint stream_num);
+
+G_END_DECLS
+
+#endif /* __ASF_DEMUX_H__ */
diff --git a/gst/asfdemux/gstrtpasfdepay.c b/gst/asfdemux/gstrtpasfdepay.c
new file mode 100644
index 0000000..1ba5d02
--- /dev/null
+++ b/gst/asfdemux/gstrtpasfdepay.c
@@ -0,0 +1,545 @@
+/* GStreamer RTP ASF depayloader
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * 2009 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstrtpasfdepay.h"
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+GST_DEBUG_CATEGORY_STATIC (rtpasfdepayload_debug);
+#define GST_CAT_DEFAULT rtpasfdepayload_debug
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-ms-asf")
+ );
+
+/* Other parameters: config, maxps */
+#define SINK_CAPS \
+ "application/x-rtp, " \
+ "media = (string) { \"application\", \"video\", \"audio\" }, " \
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " \
+ "clock-rate = (int) [1, MAX ], " \
+ "encoding-name = (string) \"X-ASF-PF\""
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (SINK_CAPS)
+ );
+
+#define gst_rtp_asf_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAsfDepay, gst_rtp_asf_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_asf_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_asf_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rtp_asf_depay_setcaps (GstRTPBaseDepayload * depay,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_asf_depay_process (GstRTPBaseDepayload * basedepay,
+ GstBuffer * buf);
+
+static void
+gst_rtp_asf_depay_class_init (GstRtpAsfDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_factory));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP ASF packet depayloader", "Codec/Depayloader/Network",
+ "Extracts ASF streams from RTP",
+ "Tim-Philipp Müller <tim centricular net>, "
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gobject_class->finalize = gst_rtp_asf_depay_finalize;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_rtp_asf_depay_change_state);
+
+ gstrtpbasedepayload_class->set_caps =
+ GST_DEBUG_FUNCPTR (gst_rtp_asf_depay_setcaps);
+ gstrtpbasedepayload_class->process =
+ GST_DEBUG_FUNCPTR (gst_rtp_asf_depay_process);
+
+ GST_DEBUG_CATEGORY_INIT (rtpasfdepayload_debug, "rtpasfdepayload", 0,
+ "RTP asf depayloader element");
+}
+
+static void
+gst_rtp_asf_depay_init (GstRtpAsfDepay * depay)
+{
+ depay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_asf_depay_finalize (GObject * object)
+{
+ GstRtpAsfDepay *depay;
+
+ depay = GST_RTP_ASF_DEPAY (object);
+
+ g_object_unref (depay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const guint8 asf_marker[16] = { 0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66,
+ 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
+};
+
+static gboolean
+gst_rtp_asf_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstRtpAsfDepay *depay;
+ GstStructure *s;
+ const gchar *config_str, *ps_string;
+ GstBuffer *buf;
+ GstCaps *src_caps;
+ guint8 *headers;
+ gsize headers_len;
+ gint clock_rate;
+
+ depay = GST_RTP_ASF_DEPAY (depayload);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (s, "clock-rate", &clock_rate) || clock_rate < 0)
+ clock_rate = 1000;
+ depayload->clock_rate = clock_rate;
+
+ /* config contains the asf headers in base64 coding */
+ config_str = gst_structure_get_string (s, "config");
+ if (config_str == NULL || *config_str == '\0')
+ goto no_config;
+
+ ps_string = gst_structure_get_string (s, "maxps");
+ if (ps_string == NULL || *ps_string == '\0')
+ goto no_packetsize;
+
+ if (depay->packet_size) {
+ /* header sent again following seek;
+ * discard to avoid confusing upstream */
+ if (depay->packet_size == atoi (ps_string)) {
+ goto duplicate_header;
+ } else {
+ /* since we should fiddle with downstream state to handle this */
+ goto refuse_renegotiation;
+ }
+ } else
+ depay->packet_size = atoi (ps_string);
+ if (depay->packet_size <= 16)
+ goto invalid_packetsize;
+
+ headers = (guint8 *) g_base64_decode (config_str, &headers_len);
+
+ if (headers == NULL || headers_len < 16
+ || memcmp (headers, asf_marker, 16) != 0)
+ goto invalid_headers;
+
+ src_caps = gst_caps_new_empty_simple ("video/x-ms-asf");
+ gst_pad_set_caps (depayload->srcpad, src_caps);
+ gst_caps_unref (src_caps);
+
+ buf = gst_buffer_new ();
+ gst_buffer_append_memory (buf,
+ gst_memory_new_wrapped (0, headers, headers_len, 0, headers_len, headers,
+ g_free));
+
+ gst_rtp_base_depayload_push (depayload, buf);
+
+ return TRUE;
+
+ /* ERRORS */
+no_config:
+ {
+ GST_WARNING_OBJECT (depay, "caps without 'config' field with asf headers");
+ return FALSE;
+ }
+no_packetsize:
+ {
+ GST_WARNING_OBJECT (depay, "caps without 'maxps' (packet size) field");
+ return FALSE;
+ }
+invalid_packetsize:
+ {
+ GST_WARNING_OBJECT (depay, "packet size %u invalid", depay->packet_size);
+ return FALSE;
+ }
+invalid_headers:
+ {
+ GST_WARNING_OBJECT (depay, "headers don't look like valid ASF headers");
+ g_free (headers);
+ return FALSE;
+ }
+duplicate_header:
+ {
+ GST_DEBUG_OBJECT (depayload, "discarding duplicate header");
+ return TRUE;
+ }
+refuse_renegotiation:
+ {
+ GST_WARNING_OBJECT (depayload, "cannot renegotiate to different header");
+ return FALSE;
+ }
+}
+
+static gint
+field_size (guint8 field)
+{
+ switch (field) {
+ /* DWORD - 32 bits */
+ case 3:
+ return 4;
+
+ /* WORD - 16 bits */
+ case 2:
+ return 2;
+
+ /* BYTE - 8 bits */
+ case 1:
+ return 1;
+
+ /* non-exitent */
+ case 0:
+ default:
+ return 0;
+ }
+}
+
+/* Set the padding field to te correct value as the spec
+ * says it should be se to 0 in the rtp packets
+ */
+static GstBuffer *
+gst_rtp_asf_depay_update_padding (GstRtpAsfDepay * depayload, GstBuffer * buf)
+{
+ GstBuffer *result;
+ GstMapInfo map;
+ guint8 *data;
+ gint offset = 0;
+ guint8 aux;
+ guint8 seq_type;
+ guint8 pad_type;
+ guint8 pkt_type;
+ gsize plen, padding;
+
+ plen = gst_buffer_get_size (buf);
+ if (plen == depayload->packet_size)
+ return buf;
+
+ padding = depayload->packet_size - plen;
+
+ GST_LOG_OBJECT (depayload,
+ "padding buffer size %" G_GSIZE_FORMAT " to packet size %d", plen,
+ depayload->packet_size);
+
+ result = gst_buffer_new_and_alloc (depayload->packet_size);
+
+ gst_buffer_map (result, &map, GST_MAP_READ);
+ data = map.data;
+ memset (data + plen, 0, padding);
+
+ gst_buffer_extract (buf, 0, data, plen);
+ gst_buffer_unref (buf);
+
+ aux = data[offset++];
+ if (aux & 0x80) {
+ guint8 err_len = 0;
+ if (aux & 0x60) {
+ GST_WARNING_OBJECT (depayload, "Error correction length type should be "
+ "set to 0");
+ /* this packet doesn't follow the spec */
+ gst_buffer_unmap (result, &map);
+ return result;
+ }
+ err_len = aux & 0x0F;
+ offset += err_len;
+
+ aux = data[offset++];
+ }
+ seq_type = (aux >> 1) & 0x3;
+ pad_type = (aux >> 3) & 0x3;
+ pkt_type = (aux >> 5) & 0x3;
+
+ offset += 1; /* skip property flags */
+ offset += field_size (pkt_type); /* skip packet length */
+ offset += field_size (seq_type); /* skip sequence field */
+
+ /* write padding */
+ switch (pad_type) {
+ /* DWORD */
+ case 3:
+ GST_WRITE_UINT32_LE (&(data[offset]), padding);
+ break;
+
+ /* WORD */
+ case 2:
+ GST_WRITE_UINT16_LE (&(data[offset]), padding);
+ break;
+
+ /* BYTE */
+ case 1:
+ data[offset] = (guint8) padding;
+ break;
+
+ /* non-existent */
+ case 0:
+ default:
+ break;
+ }
+ gst_buffer_unmap (result, &map);
+
+ return result;
+}
+
+/* Docs: 'RTSP Protocol PDF' document from http://sdp.ppona.com/ (page 8) */
+
+static GstBuffer *
+gst_rtp_asf_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpAsfDepay *depay;
+ const guint8 *payload;
+ GstBuffer *outbuf;
+ gboolean S, L, R, D, I;
+ guint payload_len, hdr_len, offset;
+ guint len_offs;
+ GstClockTime timestamp;
+ GstRTPBuffer rtpbuf = { NULL };
+
+ depay = GST_RTP_ASF_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_LOG_OBJECT (depay, "got DISCONT");
+ gst_adapter_clear (depay->adapter);
+ depay->discont = TRUE;
+ }
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuf);
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtpbuf);
+ payload = gst_rtp_buffer_get_payload (&rtpbuf);
+ offset = 0;
+
+ GST_LOG_OBJECT (depay, "got payload len of %u", payload_len);
+
+ do {
+ guint packet_len;
+
+ /* packet header is at least 4 bytes */
+ if (payload_len < 4)
+ goto too_small;
+
+ /* 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |S|L|R|D|I|RES | Length/Offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Relative Timestamp (optional) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Duration (optional) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | LocationId (optional) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * S: packet contains a keyframe.
+ * L: If 1, Length/Offset contains length, else contains the byte offset
+ * of the fragment's first byte counted from the beginning of the
+ * complete ASF data packet.
+ * R: relative timestamp present
+ * D: duration present
+ * I: locationid present
+ */
+
+ S = ((payload[0] & 0x80) != 0);
+ L = ((payload[0] & 0x40) != 0);
+ R = ((payload[0] & 0x20) != 0);
+ D = ((payload[0] & 0x10) != 0);
+ I = ((payload[0] & 0x08) != 0);
+
+ hdr_len = 4;
+
+ len_offs = (payload[1] << 16) | (payload[2] << 8) | payload[3];
+
+ if (R) {
+ GST_DEBUG ("Relative timestamp field present : %u",
+ GST_READ_UINT32_BE (payload + hdr_len));
+ hdr_len += 4;
+ }
+ if (D) {
+ GST_DEBUG ("Duration field present : %u",
+ GST_READ_UINT32_BE (payload + hdr_len));
+ hdr_len += 4;
+ }
+ if (I) {
+ GST_DEBUG ("LocationId field present : %u",
+ GST_READ_UINT32_BE (payload + hdr_len));
+ hdr_len += 4;
+ }
+
+ GST_LOG_OBJECT (depay, "S %d, L %d, R %d, D %d, I %d", S, L, R, D, I);
+ GST_LOG_OBJECT (depay, "payload_len:%d, hdr_len:%d, len_offs:%d",
+ payload_len, hdr_len, len_offs);
+
+ if (payload_len < hdr_len)
+ goto too_small;
+
+ /* skip headers */
+ payload_len -= hdr_len;
+ payload += hdr_len;
+ offset += hdr_len;
+
+ if (L) {
+ /* L bit set, len contains the length of the packet */
+ packet_len = len_offs;
+ } else {
+ /* else it contains an offset which we don't handle yet */
+ GST_LOG_OBJECT (depay, "We have a fragmented packet");
+ packet_len = payload_len;
+ }
+
+ if (packet_len > payload_len)
+ packet_len = payload_len;
+
+ GST_LOG_OBJECT (depay, "packet len %u, payload len %u, packet_size:%u",
+ packet_len, payload_len, depay->packet_size);
+
+ if (!L) {
+ guint available;
+ GstBuffer *sub;
+
+ /* Fragmented packet handling */
+ outbuf = NULL;
+
+ if (len_offs == (available = gst_adapter_available (depay->adapter))) {
+ /* fragment aligns with what we have, add it */
+ GST_LOG_OBJECT (depay, "collecting fragment");
+ sub =
+ gst_rtp_buffer_get_payload_subbuffer (&rtpbuf, offset, packet_len);
+ gst_adapter_push (depay->adapter, sub);
+ /* RTP marker bit M is set if this is last fragment */
+ if (gst_rtp_buffer_get_marker (&rtpbuf)) {
+ GST_LOG_OBJECT (depay, "last fragment, assembling packet");
+ outbuf =
+ gst_adapter_take_buffer (depay->adapter, available + packet_len);
+ }
+ } else {
+ if (available) {
+ GST_WARNING_OBJECT (depay, "Offset doesn't match previous data?!");
+ GST_DEBUG_OBJECT (depay, "clearing for re-sync");
+ gst_adapter_clear (depay->adapter);
+ } else
+ GST_DEBUG_OBJECT (depay, "waiting for start of packet");
+ }
+ } else {
+ GST_LOG_OBJECT (depay, "collecting packet");
+ outbuf =
+ gst_rtp_buffer_get_payload_subbuffer (&rtpbuf, offset, packet_len);
+ }
+
+ /* If we haven't completed a full ASF packet, return */
+ if (!outbuf)
+ return NULL;
+
+ outbuf = gst_rtp_asf_depay_update_padding (depay, outbuf);
+
+ if (!S)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ if (depay->discont) {
+ GST_LOG_OBJECT (depay, "setting DISCONT");
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ depay->discont = FALSE;
+ }
+
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+
+ gst_rtp_base_depayload_push (depayload, outbuf);
+
+ /* only apply the timestamp to the first buffer of this packet */
+ timestamp = -1;
+
+ /* skip packet data */
+ payload += packet_len;
+ offset += packet_len;
+ payload_len -= packet_len;
+ } while (payload_len > 0);
+
+ gst_rtp_buffer_unmap (&rtpbuf);
+
+ return NULL;
+
+/* ERRORS */
+too_small:
+ {
+ gst_rtp_buffer_unmap (&rtpbuf);
+ GST_WARNING_OBJECT (depayload, "Payload too small, expected at least 4 "
+ "bytes for header, but got only %d bytes", payload_len);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_asf_depay_change_state (GstElement * element, GstStateChange trans)
+{
+ GstStateChangeReturn ret;
+ GstRtpAsfDepay *depay;
+
+ depay = GST_RTP_ASF_DEPAY (element);
+
+ switch (trans) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (depay->adapter);
+ depay->discont = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
+
+ switch (trans) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_adapter_clear (depay->adapter);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/gst/asfdemux/gstrtpasfdepay.h b/gst/asfdemux/gstrtpasfdepay.h
new file mode 100644
index 0000000..8388c8a
--- /dev/null
+++ b/gst/asfdemux/gstrtpasfdepay.h
@@ -0,0 +1,64 @@
+/* GStreamer RTP ASF depayloader
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * 2009 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_ASF_DEPAY_H__
+#define __GST_RTP_ASF_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_ASF_DEPAY \
+ (gst_rtp_asf_depay_get_type())
+#define GST_RTP_ASF_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_ASF_DEPAY,GstRtpAsfDepay))
+#define GST_RTP_ASF_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_ASF_DEPAY,GstRtpAsfDepayClass))
+#define GST_IS_RTP_ASF_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_ASF_DEPAY))
+#define GST_IS_RTP_ASF_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_ASF_DEPAY))
+
+typedef struct _GstRtpAsfDepay GstRtpAsfDepay;
+typedef struct _GstRtpAsfDepayClass GstRtpAsfDepayClass;
+
+struct _GstRtpAsfDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ guint packet_size;
+
+ GstAdapter *adapter;
+ gboolean discont;
+};
+
+struct _GstRtpAsfDepayClass
+{
+ GstRTPBaseDepayloadClass depayload_class;
+};
+
+GType gst_rtp_asf_depay_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_ASF_DEPAY_H__ */
diff --git a/gst/asfdemux/gstrtspwms.c b/gst/asfdemux/gstrtspwms.c
new file mode 100644
index 0000000..c864287
--- /dev/null
+++ b/gst/asfdemux/gstrtspwms.c
@@ -0,0 +1,236 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* Element-Checklist-Version: 5 */
+
+/**
+ * SECTION:element-rtspwms
+ *
+ * A WMS RTSP extension
+ */
+
+#include <string.h>
+
+#include <gst/rtsp/gstrtspextension.h>
+
+#include "gstrtspwms.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtspwms_debug);
+#define GST_CAT_DEFAULT (rtspwms_debug)
+
+#define SERVER_PREFIX "WMServer/"
+#define HEADER_PREFIX "data:application/vnd.ms.wms-hdr.asfv1;base64,"
+#define EXTENSION_CMD "application/x-wms-extension-cmd"
+
+static GstRTSPResult
+gst_rtsp_wms_before_send (GstRTSPExtension * ext, GstRTSPMessage * request)
+{
+ GstRTSPWMS *ctx = (GstRTSPWMS *) ext;
+
+ GST_DEBUG_OBJECT (ext, "before send");
+
+ switch (request->type_data.request.method) {
+ case GST_RTSP_OPTIONS:
+ {
+ /* activate ourselves with the first request */
+ ctx->active = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ return GST_RTSP_OK;
+}
+
+static GstRTSPResult
+gst_rtsp_wms_after_send (GstRTSPExtension * ext, GstRTSPMessage * req,
+ GstRTSPMessage * resp)
+{
+ GstRTSPWMS *ctx = (GstRTSPWMS *) ext;
+
+ GST_DEBUG_OBJECT (ext, "after send");
+
+ switch (req->type_data.request.method) {
+ case GST_RTSP_OPTIONS:
+ {
+ gchar *server = NULL;
+
+ gst_rtsp_message_get_header (resp, GST_RTSP_HDR_SERVER, &server, 0);
+ if (server && g_str_has_prefix (server, SERVER_PREFIX))
+ ctx->active = TRUE;
+ else
+ ctx->active = FALSE;
+ break;
+ }
+ default:
+ break;
+ }
+ return GST_RTSP_OK;
+}
+
+
+static GstRTSPResult
+gst_rtsp_wms_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
+ GstStructure * props)
+{
+ const gchar *config, *maxps;
+ gint i;
+ GstRTSPWMS *ctx = (GstRTSPWMS *) ext;
+
+ if (!ctx->active)
+ return GST_RTSP_OK;
+
+ for (i = 0; (config = gst_sdp_message_get_attribute_val_n (sdp, "pgmpu", i));
+ i++) {
+ if (g_str_has_prefix (config, HEADER_PREFIX)) {
+ config += strlen (HEADER_PREFIX);
+ gst_structure_set (props, "config", G_TYPE_STRING, config, NULL);
+ break;
+ }
+ }
+ if (config == NULL)
+ goto no_config;
+
+ gst_structure_set (props, "config", G_TYPE_STRING, config, NULL);
+
+ maxps = gst_sdp_message_get_attribute_val (sdp, "maxps");
+ if (maxps)
+ gst_structure_set (props, "maxps", G_TYPE_STRING, maxps, NULL);
+
+ gst_structure_set (props, "encoding-name", G_TYPE_STRING, "X-ASF-PF", NULL);
+ gst_structure_set (props, "media", G_TYPE_STRING, "application", NULL);
+
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+no_config:
+ {
+ GST_DEBUG_OBJECT (ctx, "Could not find config SDP field, deactivating.");
+ ctx->active = FALSE;
+ return GST_RTSP_OK;
+ }
+}
+
+static gboolean
+gst_rtsp_wms_configure_stream (GstRTSPExtension * ext, GstCaps * caps)
+{
+ GstRTSPWMS *ctx;
+ GstStructure *s;
+ const gchar *encoding;
+
+ ctx = (GstRTSPWMS *) ext;
+ s = gst_caps_get_structure (caps, 0);
+ encoding = gst_structure_get_string (s, "encoding-name");
+
+ if (!encoding)
+ return TRUE;
+
+ GST_DEBUG_OBJECT (ctx, "%" GST_PTR_FORMAT " encoding-name: %s", caps,
+ encoding);
+
+ /* rtx streams do not need to be configured */
+ if (!strcmp (encoding, "X-WMS-RTX"))
+ return FALSE;
+
+ return TRUE;
+}
+
+static GstRTSPResult
+gst_rtsp_wms_receive_request (GstRTSPExtension * ext, GstRTSPMessage * request)
+{
+ GstRTSPWMS *ctx;
+ GstRTSPResult res = GST_RTSP_ENOTIMPL;
+ GstRTSPMessage response = { 0 };
+
+ ctx = (GstRTSPWMS *) ext;
+
+ GST_DEBUG_OBJECT (ext, "before send");
+
+ switch (request->type_data.request.method) {
+ case GST_RTSP_SET_PARAMETER:
+ {
+ gchar *content_type = NULL;
+
+ gst_rtsp_message_get_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+ &content_type, 0);
+
+ if (content_type && !g_ascii_strcasecmp (content_type, EXTENSION_CMD)) {
+ /* parse the command */
+
+ /* default implementation, send OK */
+ res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK",
+ request);
+ if (res < 0)
+ goto send_error;
+
+ GST_DEBUG_OBJECT (ctx, "replying with OK");
+
+ /* send reply */
+ if ((res = gst_rtsp_extension_send (ext, request, &response)) < 0)
+ goto send_error;
+
+ res = GST_RTSP_EEOF;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return res;
+
+send_error:
+ {
+ return res;
+ }
+}
+
+static void gst_rtsp_wms_extension_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (GstRTSPWMS, gst_rtsp_wms, GST_TYPE_ELEMENT,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_RTSP_EXTENSION,
+ gst_rtsp_wms_extension_init));
+
+static void
+gst_rtsp_wms_class_init (GstRTSPWMSClass * g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ GST_DEBUG_CATEGORY_INIT (rtspwms_debug, "rtspwms", 0, "WMS RTSP extension");
+
+ gst_element_class_set_static_metadata (element_class, "WMS RTSP Extension",
+ "Network/Extension/Protocol",
+ "Extends RTSP so that it can handle WMS setup",
+ "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtsp_wms_init (GstRTSPWMS * rtspwms)
+{
+}
+
+static void
+gst_rtsp_wms_extension_init (gpointer g_iface, gpointer iface_data)
+{
+ GstRTSPExtensionInterface *iface = (GstRTSPExtensionInterface *) g_iface;
+
+ iface->parse_sdp = gst_rtsp_wms_parse_sdp;
+ iface->before_send = gst_rtsp_wms_before_send;
+ iface->after_send = gst_rtsp_wms_after_send;
+ iface->configure_stream = gst_rtsp_wms_configure_stream;
+ iface->receive_request = gst_rtsp_wms_receive_request;
+}
diff --git a/gst/asfdemux/gstrtspwms.h b/gst/asfdemux/gstrtspwms.h
new file mode 100644
index 0000000..feb8c43
--- /dev/null
+++ b/gst/asfdemux/gstrtspwms.h
@@ -0,0 +1,50 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_WMS_H__
+#define __GST_RTSP_WMS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTSP_WMS (gst_rtsp_wms_get_type())
+#define GST_IS_RTSP_WMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSP_WMS))
+#define GST_IS_RTSP_WMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSP_WMS))
+#define GST_RTSP_WMS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSP_WMS, GstRTSPWMS))
+#define GST_RTSP_WMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTSP_WMS, GstRTSPWMSClass))
+
+typedef struct _GstRTSPWMS GstRTSPWMS;
+typedef struct _GstRTSPWMSClass GstRTSPWMSClass;
+
+struct _GstRTSPWMS {
+ GstElement element;
+
+ gboolean active;
+};
+
+struct _GstRTSPWMSClass {
+ GstElementClass parent_class;
+};
+
+GType gst_rtsp_wms_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_WMS_H__ */
diff --git a/gst/dvdlpcmdec/Makefile.am b/gst/dvdlpcmdec/Makefile.am
new file mode 100644
index 0000000..fcee1e4
--- /dev/null
+++ b/gst/dvdlpcmdec/Makefile.am
@@ -0,0 +1,24 @@
+
+plugin_LTLIBRARIES = libgstdvdlpcmdec.la
+
+libgstdvdlpcmdec_la_SOURCES = gstdvdlpcmdec.c
+libgstdvdlpcmdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstdvdlpcmdec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_API_VERSION@ $(GST_LIBS)
+libgstdvdlpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdvdlpcmdec_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = gstdvdlpcmdec.h
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstdvdlpcmdec -:SHARED libgstdvdlpcmdec \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstdvdlpcmdec_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdvdlpcmdec_la_CFLAGS) \
+ -:LDFLAGS $(libgstdvdlpcmdec_la_LDFLAGS) \
+ $(libgstdvdlpcmdec_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
diff --git a/gst/dvdlpcmdec/Makefile.in b/gst/dvdlpcmdec/Makefile.in
new file mode 100644
index 0000000..d20e1fd
--- /dev/null
+++ b/gst/dvdlpcmdec/Makefile.in
@@ -0,0 +1,839 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = gst/dvdlpcmdec
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-function.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/a52.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-sid.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstdvdlpcmdec_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstdvdlpcmdec_la_OBJECTS = libgstdvdlpcmdec_la-gstdvdlpcmdec.lo
+libgstdvdlpcmdec_la_OBJECTS = $(am_libgstdvdlpcmdec_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgstdvdlpcmdec_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstdvdlpcmdec_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(libgstdvdlpcmdec_la_CFLAGS) $(CFLAGS) \
+ $(libgstdvdlpcmdec_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgstdvdlpcmdec_la_SOURCES)
+DIST_SOURCES = $(libgstdvdlpcmdec_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A52DEC_CFLAGS = @A52DEC_CFLAGS@
+A52DEC_LIBS = @A52DEC_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMRNB_CFLAGS = @AMRNB_CFLAGS@
+AMRNB_LIBS = @AMRNB_LIBS@
+AMRWB_CFLAGS = @AMRWB_CFLAGS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDIO_CFLAGS = @CDIO_CFLAGS@
+CDIO_LIBS = @CDIO_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVDREAD_LIBS = @DVDREAD_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DVDREAD = @HAVE_DVDREAD@
+HAVE_LAME = @HAVE_LAME@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LAME_CFLAGS = @LAME_CFLAGS@
+LAME_LIBS = @LAME_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPEG2DEC_CFLAGS = @MPEG2DEC_CFLAGS@
+MPEG2DEC_LIBS = @MPEG2DEC_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIDPLAY_CFLAGS = @SIDPLAY_CFLAGS@
+SIDPLAY_LIBS = @SIDPLAY_LIBS@
+STRIP = @STRIP@
+TWOLAME_CFLAGS = @TWOLAME_CFLAGS@
+TWOLAME_LIBS = @TWOLAME_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WIN32_LIBS = @WIN32_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstdvdlpcmdec.la
+libgstdvdlpcmdec_la_SOURCES = gstdvdlpcmdec.c
+libgstdvdlpcmdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstdvdlpcmdec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_API_VERSION@ $(GST_LIBS)
+libgstdvdlpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdvdlpcmdec_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+noinst_HEADERS = gstdvdlpcmdec.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/dvdlpcmdec/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/dvdlpcmdec/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgstdvdlpcmdec.la: $(libgstdvdlpcmdec_la_OBJECTS) $(libgstdvdlpcmdec_la_DEPENDENCIES) $(EXTRA_libgstdvdlpcmdec_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstdvdlpcmdec_la_LINK) -rpath $(plugindir) $(libgstdvdlpcmdec_la_OBJECTS) $(libgstdvdlpcmdec_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdvdlpcmdec_la-gstdvdlpcmdec.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstdvdlpcmdec_la-gstdvdlpcmdec.lo: gstdvdlpcmdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdvdlpcmdec_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdvdlpcmdec_la_CFLAGS) $(CFLAGS) -MT libgstdvdlpcmdec_la-gstdvdlpcmdec.lo -MD -MP -MF $(DEPDIR)/libgstdvdlpcmdec_la-gstdvdlpcmdec.Tpo -c -o libgstdvdlpcmdec_la-gstdvdlpcmdec.lo `test -f 'gstdvdlpcmdec.c' || echo '$(srcdir)/'`gstdvdlpcmdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdvdlpcmdec_la-gstdvdlpcmdec.Tpo $(DEPDIR)/libgstdvdlpcmdec_la-gstdvdlpcmdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdvdlpcmdec.c' object='libgstdvdlpcmdec_la-gstdvdlpcmdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdvdlpcmdec_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdvdlpcmdec_la_CFLAGS) $(CFLAGS) -c -o libgstdvdlpcmdec_la-gstdvdlpcmdec.lo `test -f 'gstdvdlpcmdec.c' || echo '$(srcdir)/'`gstdvdlpcmdec.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstdvdlpcmdec -:SHARED libgstdvdlpcmdec \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstdvdlpcmdec_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdvdlpcmdec_la_CFLAGS) \
+ -:LDFLAGS $(libgstdvdlpcmdec_la_LDFLAGS) \
+ $(libgstdvdlpcmdec_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.c b/gst/dvdlpcmdec/gstdvdlpcmdec.c
new file mode 100644
index 0000000..03024b7
--- /dev/null
+++ b/gst/dvdlpcmdec/gstdvdlpcmdec.c
@@ -0,0 +1,863 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Jan Schmidt <jan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* Element-Checklist-Version: TODO */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstdvdlpcmdec.h"
+#include <gst/audio/audio.h>
+
+GST_DEBUG_CATEGORY_STATIC (dvdlpcm_debug);
+#define GST_CAT_DEFAULT dvdlpcm_debug
+
+static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-private1-lpcm; "
+ "audio/x-lpcm, "
+ "width = (int) { 16, 20, 24 }, "
+ "rate = (int) { 32000, 44100, 48000, 96000 }, "
+ "channels = (int) [ 1, 8 ], "
+ "dynamic_range = (int) [ 0, 255 ], "
+ "emphasis = (boolean) { TRUE, FALSE }, "
+ "mute = (boolean) { TRUE, FALSE } ")
+ );
+
+static GstStaticPadTemplate gst_dvdlpcmdec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) { S16BE, S24BE }, "
+ "layout = (string) interleaved, "
+ "rate = (int) { 32000, 44100, 48000, 96000 }, "
+ "channels = (int) [ 1, 8 ]")
+ );
+
+/* DvdLpcmDec signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0
+ /* FILL ME */
+};
+
+static void gst_dvdlpcmdec_base_init (gpointer g_class);
+static void gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass);
+static void gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec);
+
+static GstFlowReturn gst_dvdlpcmdec_chain_raw (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+static GstFlowReturn gst_dvdlpcmdec_chain_dvd (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+static gboolean gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean dvdlpcmdec_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+
+static GstStateChangeReturn gst_dvdlpcmdec_change_state (GstElement * element,
+ GstStateChange transition);
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_dvdlpcmdec_get_type (void)
+{
+ static GType dvdlpcmdec_type = 0;
+
+ if (!dvdlpcmdec_type) {
+ static const GTypeInfo dvdlpcmdec_info = {
+ sizeof (GstDvdLpcmDecClass),
+ gst_dvdlpcmdec_base_init,
+ NULL,
+ (GClassInitFunc) gst_dvdlpcmdec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstDvdLpcmDec),
+ 0,
+ (GInstanceInitFunc) gst_dvdlpcmdec_init,
+ };
+
+ dvdlpcmdec_type =
+ g_type_register_static (GST_TYPE_ELEMENT, "GstDvdLpcmDec",
+ &dvdlpcmdec_info, 0);
+ }
+ return dvdlpcmdec_type;
+}
+
+static void
+gst_dvdlpcmdec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_dvdlpcmdec_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_dvdlpcmdec_src_template));
+ gst_element_class_set_static_metadata (element_class,
+ "DVD LPCM Audio decoder", "Codec/Decoder/Audio",
+ "Decode DVD LPCM frames into standard PCM audio",
+ "Jan Schmidt <jan@noraisin.net>, Michael Smith <msmith@fluendo.com>");
+}
+
+static void
+gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass)
+{
+ GstElementClass *gstelement_class;
+
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gstelement_class->change_state = gst_dvdlpcmdec_change_state;
+}
+
+static void
+gst_dvdlpcm_reset (GstDvdLpcmDec * dvdlpcmdec)
+{
+ gst_audio_info_init (&dvdlpcmdec->info);
+ dvdlpcmdec->dynamic_range = 0;
+ dvdlpcmdec->emphasis = FALSE;
+ dvdlpcmdec->mute = FALSE;
+ dvdlpcmdec->timestamp = GST_CLOCK_TIME_NONE;
+
+ dvdlpcmdec->header = 0;
+
+ gst_segment_init (&dvdlpcmdec->segment, GST_FORMAT_UNDEFINED);
+}
+
+static void
+gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
+{
+ dvdlpcmdec->sinkpad =
+ gst_pad_new_from_static_template (&gst_dvdlpcmdec_sink_template, "sink");
+ gst_pad_set_event_function (dvdlpcmdec->sinkpad, dvdlpcmdec_sink_event);
+ gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->sinkpad);
+
+ dvdlpcmdec->srcpad =
+ gst_pad_new_from_static_template (&gst_dvdlpcmdec_src_template, "src");
+ gst_pad_use_fixed_caps (dvdlpcmdec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->srcpad);
+
+ gst_dvdlpcm_reset (dvdlpcmdec);
+}
+
+static const GstAudioChannelPosition channel_positions[][8] = {
+ {GST_AUDIO_CHANNEL_POSITION_MONO},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
+ {GST_AUDIO_CHANNEL_POSITION_INVALID}
+};
+
+static void
+gst_dvdlpcmdec_send_tags (GstDvdLpcmDec * dvdlpcmdec)
+{
+ GstTagList *taglist;
+ guint bitrate;
+ gint bpf, rate;
+
+ bpf = GST_AUDIO_INFO_BPF (&dvdlpcmdec->info);
+ rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
+
+ bitrate = bpf * 8 * rate;
+
+ taglist = gst_tag_list_new (GST_TAG_AUDIO_CODEC, "LPCM Audio",
+ GST_TAG_BITRATE, bitrate, NULL);
+
+ gst_pad_push_event (dvdlpcmdec->srcpad, gst_event_new_tag (taglist));
+}
+
+static gboolean
+gst_dvdlpcmdec_set_outcaps (GstDvdLpcmDec * dvdlpcmdec)
+{
+ gboolean res = TRUE;
+ GstCaps *src_caps;
+
+ /* Build caps to set on the src pad, which we know from the incoming caps */
+ src_caps = gst_audio_info_to_caps (&dvdlpcmdec->info);
+
+ res = gst_pad_set_caps (dvdlpcmdec->srcpad, src_caps);
+ if (res) {
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Successfully set output caps: %"
+ GST_PTR_FORMAT, src_caps);
+
+ gst_dvdlpcmdec_send_tags (dvdlpcmdec);
+ } else {
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set output caps: %"
+ GST_PTR_FORMAT, src_caps);
+ }
+
+ gst_caps_unref (src_caps);
+
+ return res;
+}
+
+static gboolean
+gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstStructure *structure;
+ gboolean res = TRUE;
+ GstDvdLpcmDec *dvdlpcmdec;
+ GstAudioFormat format;
+ gint rate, channels, width;
+ const GstAudioChannelPosition *position;
+
+ g_return_val_if_fail (caps != NULL, FALSE);
+ g_return_val_if_fail (pad != NULL, FALSE);
+
+ dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* If we have the DVD structured LPCM (including header) then we wait
+ * for incoming data before creating the output pad caps */
+ if (gst_structure_has_name (structure, "audio/x-private1-lpcm")) {
+ gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_dvd);
+ goto done;
+ }
+
+ gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_raw);
+
+ res &= gst_structure_get_int (structure, "rate", &rate);
+ res &= gst_structure_get_int (structure, "channels", &channels);
+ res &= gst_structure_get_int (structure, "width", &width);
+ res &= gst_structure_get_int (structure, "dynamic_range",
+ &dvdlpcmdec->dynamic_range);
+ res &= gst_structure_get_boolean (structure, "emphasis",
+ &dvdlpcmdec->emphasis);
+ res &= gst_structure_get_boolean (structure, "mute", &dvdlpcmdec->mute);
+
+ if (!res)
+ goto caps_parse_error;
+
+ switch (width) {
+ case 24:
+ case 20:
+ format = GST_AUDIO_FORMAT_S24BE;
+ break;
+ case 16:
+ format = GST_AUDIO_FORMAT_S16BE;
+ break;
+ default:
+ format = GST_AUDIO_FORMAT_UNKNOWN;
+ break;
+ }
+
+ gst_audio_info_set_format (&dvdlpcmdec->info, format, rate, channels, NULL);
+ if (channels < 9
+ && channel_positions[channels - 1][0] !=
+ GST_AUDIO_CHANNEL_POSITION_INVALID) {
+ dvdlpcmdec->info.flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
+ position = channel_positions[channels - 1];
+ dvdlpcmdec->lpcm_layout = position;
+ memcpy (dvdlpcmdec->info.position, position,
+ sizeof (GstAudioChannelPosition) * channels);
+ gst_audio_channel_positions_to_valid_order (dvdlpcmdec->info.position,
+ channels);
+ }
+
+ dvdlpcmdec->width = width;
+
+ res = gst_dvdlpcmdec_set_outcaps (dvdlpcmdec);
+
+done:
+ gst_object_unref (dvdlpcmdec);
+ return res;
+
+ /* ERRORS */
+caps_parse_error:
+ {
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't get parameters; missing caps?");
+ gst_object_unref (dvdlpcmdec);
+ return FALSE;
+ }
+}
+
+static void
+update_timestamps (GstDvdLpcmDec * dvdlpcmdec, GstBuffer * buf, int samples)
+{
+ gboolean take_buf_ts = FALSE;
+ gint rate;
+
+ rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
+
+ GST_BUFFER_DURATION (buf) = gst_util_uint64_scale (samples, GST_SECOND, rate);
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ if (GST_CLOCK_TIME_IS_VALID (dvdlpcmdec->timestamp)) {
+ GstClockTimeDiff one_sample = GST_SECOND / rate;
+ GstClockTimeDiff diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buf),
+ dvdlpcmdec->timestamp);
+
+ if (diff > one_sample || diff < -one_sample)
+ take_buf_ts = TRUE;
+ } else {
+ take_buf_ts = TRUE;
+ }
+ } else if (!GST_CLOCK_TIME_IS_VALID (dvdlpcmdec->timestamp)) {
+ dvdlpcmdec->timestamp = 0;
+ }
+
+ if (take_buf_ts) {
+ /* Take buffer timestamp */
+ dvdlpcmdec->timestamp = GST_BUFFER_TIMESTAMP (buf);
+ } else {
+ GST_BUFFER_TIMESTAMP (buf) = dvdlpcmdec->timestamp;
+ }
+
+ dvdlpcmdec->timestamp += GST_BUFFER_DURATION (buf);
+
+ GST_LOG_OBJECT (dvdlpcmdec, "Updated timestamp to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+}
+
+static void
+parse_header (GstDvdLpcmDec * dec, guint32 header)
+{
+ GstAudioFormat format;
+ gint rate, channels, width;
+
+ /* We don't actually use 'dynamic range', 'mute', or 'emphasis' currently,
+ * but parse them out */
+ dec->dynamic_range = header & 0xff;
+
+ dec->mute = (header & 0x400000) != 0;
+ dec->emphasis = (header & 0x800000) != 0;
+
+ /* These two bits tell us the bit depth */
+ switch (header & 0xC000) {
+ case 0x8000:
+ /* 24 bits in 3 bytes */
+ format = GST_AUDIO_FORMAT_S24BE;
+ width = 24;
+ break;
+ case 0x4000:
+ /* 20 bits in 3 bytes */
+ format = GST_AUDIO_FORMAT_S24BE;
+ width = 20;
+ break;
+ default:
+ format = GST_AUDIO_FORMAT_S16BE;
+ width = 16;
+ break;
+ }
+
+ dec->width = width;
+
+ /* Only four sample rates supported */
+ switch (header & 0x3000) {
+ case 0x0000:
+ rate = 48000;
+ break;
+ case 0x1000:
+ rate = 96000;
+ break;
+ case 0x2000:
+ rate = 44100;
+ break;
+ case 0x3000:
+ rate = 32000;
+ break;
+ default:
+ rate = 0;
+ break;
+ }
+
+ /* And, of course, the number of channels (up to 8) */
+ channels = ((header >> 8) & 0x7) + 1;
+
+ gst_audio_info_set_format (&dec->info, format, rate, channels, NULL);
+ if (channels < 9
+ && channel_positions[channels - 1][0] !=
+ GST_AUDIO_CHANNEL_POSITION_INVALID) {
+ const GstAudioChannelPosition *position;
+
+ dec->info.flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
+ position = channel_positions[channels - 1];
+ dec->lpcm_layout = position;
+ memcpy (dec->info.position, position,
+ sizeof (GstAudioChannelPosition) * channels);
+ gst_audio_channel_positions_to_valid_order (dec->info.position, channels);
+ }
+}
+
+static GstFlowReturn
+gst_dvdlpcmdec_chain_dvd (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstDvdLpcmDec *dvdlpcmdec;
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ guint first_access;
+ guint32 header;
+ GstBuffer *subbuf;
+ GstFlowReturn ret = GST_FLOW_OK;
+ gint off, len;
+ gint rate, channels;
+
+ dvdlpcmdec = GST_DVDLPCMDEC (parent);
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ if (size < 5)
+ goto too_small;
+
+ /* We have a 5 byte header, now.
+ * The first two bytes are a (big endian) 16 bit offset into our buffer.
+ * The buffer timestamp refers to this offset.
+ *
+ * The other three bytes are a (big endian) number in which the header is
+ * encoded.
+ */
+ first_access = (data[0] << 8) | data[1];
+ if (first_access > size)
+ goto invalid_data;
+
+ /* Don't keep the 'frame number' low 5 bits of the first byte */
+ header = ((data[2] & 0xC0) << 16) | (data[3] << 8) | data[4];
+
+ /* see if we have a new header */
+ if (header != dvdlpcmdec->header) {
+ parse_header (dvdlpcmdec, header);
+
+ if (!gst_dvdlpcmdec_set_outcaps (dvdlpcmdec))
+ goto negotiation_failed;
+
+ dvdlpcmdec->header = header;
+ }
+
+ GST_LOG_OBJECT (dvdlpcmdec, "first_access %d, buffer length %" G_GSIZE_FORMAT,
+ first_access, size);
+
+ rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
+ channels = GST_AUDIO_INFO_CHANNELS (&dvdlpcmdec->info);
+
+ /* After first_access, we have an additional 3 bytes of data we've parsed and
+ * don't want to handle; this is included within the value of first_access.
+ * So a first_access value of between 1 and 3 is just broken, we treat that
+ * the same as zero. first_access == 4 means we only need to create a single
+ * sub-buffer, greater than that we need to create two. */
+
+ /* skip access unit bytes and info */
+ off = 5;
+
+ if (first_access > 4) {
+ guint samples = 0;
+ GstClockTime ts;
+
+ /* length of first buffer */
+ len = first_access - 4;
+
+ GST_LOG_OBJECT (dvdlpcmdec, "Creating first sub-buffer off %d, len %d",
+ off, len);
+
+ /* see if we need a subbuffer without timestamp */
+ if (off + len > size)
+ goto bad_first_access;
+
+ subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, len);
+
+ /* If we don't have a stored timestamp from the last packet,
+ * (it's straight after a new-segment, but we have one on the
+ * first access buffer, then calculate the timestamp to align
+ * this buffer to just before the first_access buffer */
+ if (!GST_CLOCK_TIME_IS_VALID (dvdlpcmdec->timestamp) &&
+ GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ switch (dvdlpcmdec->width) {
+ case 16:
+ samples = len / channels / 2;
+ break;
+ case 20:
+ samples = (len / channels) * 2 / 5;
+ break;
+ case 24:
+ samples = len / channels / 3;
+ break;
+ }
+ }
+ if (samples != 0) {
+ ts = gst_util_uint64_scale (samples, GST_SECOND, rate);
+ if (ts < GST_BUFFER_TIMESTAMP (buf))
+ GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf) - ts;
+ else
+ GST_BUFFER_TIMESTAMP (subbuf) = 0;
+ } else {
+ GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
+ }
+
+ ret = gst_dvdlpcmdec_chain_raw (pad, parent, subbuf);
+ if (ret != GST_FLOW_OK)
+ goto done;
+
+ /* then the buffer with new timestamp */
+ off += len;
+ len = size - off;
+
+ GST_LOG_OBJECT (dvdlpcmdec, "Creating next sub-buffer off %d, len %d", off,
+ len);
+
+ if (len > 0) {
+ subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, len);
+ GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
+
+ ret = gst_dvdlpcmdec_chain_raw (pad, parent, subbuf);
+ }
+ } else {
+ GST_LOG_OBJECT (dvdlpcmdec,
+ "Creating single sub-buffer off %d, len %" G_GSIZE_FORMAT, off,
+ size - off);
+ subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, size - off);
+ GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
+ ret = gst_dvdlpcmdec_chain_raw (pad, parent, subbuf);
+ }
+
+done:
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+
+ return ret;
+
+ /* ERRORS */
+too_small:
+ {
+ /* Buffer is too small */
+ GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
+ ("Invalid data found parsing LPCM packet"),
+ ("LPCM packet was too small. Dropping"));
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+invalid_data:
+ {
+ GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
+ ("Invalid data found parsing LPCM packet"),
+ ("LPCM packet contained invalid first access. Dropping"));
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+negotiation_failed:
+ {
+ GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
+ ("Failed to configure output format"));
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+bad_first_access:
+ {
+ GST_WARNING_OBJECT (pad, "Bad first_access parameter in buffer");
+ GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, DECODE,
+ (NULL),
+ ("first_access parameter out of range: bad buffer from demuxer"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+}
+
+static GstFlowReturn
+gst_dvdlpcmdec_chain_raw (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstDvdLpcmDec *dvdlpcmdec;
+ gsize size;
+ GstFlowReturn ret;
+ guint samples = 0;
+ gint rate, channels;
+
+ dvdlpcmdec = GST_DVDLPCMDEC (parent);
+
+ size = gst_buffer_get_size (buf);
+
+ GST_LOG_OBJECT (dvdlpcmdec,
+ "got buffer %p of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT,
+ buf, size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
+ channels = GST_AUDIO_INFO_CHANNELS (&dvdlpcmdec->info);
+
+ if (rate == 0)
+ goto not_negotiated;
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
+ dvdlpcmdec->timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ /* We don't currently do anything at all regarding emphasis, mute or
+ * dynamic_range - I'm not sure what they're for */
+ switch (dvdlpcmdec->width) {
+ case 16:
+ {
+ /* We can just pass 16-bits straight through intact, once we set
+ * appropriate things on the buffer */
+ samples = size / channels / 2;
+ if (samples < 1)
+ goto drop;
+ buf = gst_buffer_make_writable (buf);
+ break;
+ }
+ case 20:
+ {
+ /* Allocate a new buffer and copy 20-bit width to 24-bit */
+ gint64 samples = size * 8 / 20;
+ gint64 count = size / 10;
+ gint64 i;
+ GstMapInfo srcmap, destmap;
+ guint8 *src;
+ guint8 *dest;
+ GstBuffer *outbuf;
+
+ if (samples < 1)
+ goto drop;
+
+ outbuf = gst_buffer_new_allocate (NULL, samples * 3, NULL);
+ gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+ /* adjust samples so we can calc the new timestamp */
+ samples = samples / channels;
+
+ gst_buffer_map (buf, &srcmap, GST_MAP_READ);
+ gst_buffer_map (outbuf, &destmap, GST_MAP_WRITE);
+ src = srcmap.data;
+ dest = destmap.data;
+
+ /* Copy 20-bit LPCM format to 24-bit buffers, with 0x00 in the lowest
+ * nibble. Note that the first 2 bytes are already correct */
+ for (i = 0; i < count; i++) {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[8] & 0xf0;
+ dest[3] = src[2];
+ dest[4] = src[3];
+ dest[5] = (src[8] & 0x0f) << 4;
+ dest[6] = src[4];
+ dest[7] = src[5];
+ dest[8] = src[9] & 0x0f;
+ dest[9] = src[6];
+ dest[10] = src[7];
+ dest[11] = (src[9] & 0x0f) << 4;
+
+ src += 10;
+ dest += 12;
+ }
+ gst_buffer_unmap (outbuf, &destmap);
+ gst_buffer_unmap (buf, &srcmap);
+ gst_buffer_unref (buf);
+ buf = outbuf;
+ break;
+ }
+ case 24:
+ {
+ /* Rearrange 24-bit LPCM format in-place. Note that the first 2
+ * and last byte are already correct */
+ guint count = size / 12;
+ gint i;
+ GstMapInfo map;
+ guint8 *ptr;
+
+ samples = size / channels / 3;
+
+ if (samples < 1)
+ goto drop;
+
+ /* Ensure our output buffer is writable */
+ buf = gst_buffer_make_writable (buf);
+
+ gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+ ptr = map.data;
+
+ for (i = 0; i < count; i++) {
+ guint8 tmp;
+
+ tmp = ptr[10];
+ ptr[10] = ptr[7];
+ ptr[7] = ptr[5];
+ ptr[5] = ptr[9];
+ ptr[9] = ptr[6];
+ ptr[6] = ptr[4];
+ ptr[4] = ptr[3];
+ ptr[3] = ptr[2];
+ ptr[2] = ptr[8];
+ ptr[8] = tmp;
+
+ ptr += 12;
+ }
+ gst_buffer_unmap (buf, &map);
+ break;
+ }
+ default:
+ goto invalid_width;
+ }
+
+ update_timestamps (dvdlpcmdec, buf, samples);
+
+ if (dvdlpcmdec->lpcm_layout)
+ gst_audio_buffer_reorder_channels (buf, dvdlpcmdec->info.finfo->format,
+ dvdlpcmdec->info.channels, dvdlpcmdec->lpcm_layout,
+ dvdlpcmdec->info.position);
+
+ ret = gst_pad_push (dvdlpcmdec->srcpad, buf);
+
+done:
+ return ret;
+
+ /* ERRORS */
+drop:
+ {
+ GST_DEBUG_OBJECT (dvdlpcmdec,
+ "Buffer of size %" G_GSIZE_FORMAT " is too small. Dropping", size);
+ gst_buffer_unref (buf);
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+not_negotiated:
+ {
+ GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
+ ("Buffer pushed before negotiation"));
+ gst_buffer_unref (buf);
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+invalid_width:
+ {
+ GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, WRONG_TYPE, (NULL),
+ ("Invalid sample width configured"));
+ gst_buffer_unref (buf);
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+}
+
+static gboolean
+dvdlpcmdec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstDvdLpcmDec *dvdlpcmdec;
+ gboolean res;
+
+ dvdlpcmdec = GST_DVDLPCMDEC (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ res = gst_dvdlpcmdec_setcaps (pad, caps);
+ gst_event_unref (event);
+ break;
+ }
+ case GST_EVENT_SEGMENT:
+ {
+ GstSegment seg;
+
+ gst_event_copy_segment (event, &seg);
+
+ GST_DEBUG_OBJECT (dvdlpcmdec, "segment %" GST_SEGMENT_FORMAT, &seg);
+
+ dvdlpcmdec->segment = seg;
+
+ if (seg.format == GST_FORMAT_TIME) {
+ dvdlpcmdec->timestamp = GST_CLOCK_TIME_NONE;
+ } else {
+ dvdlpcmdec->timestamp = 0;
+ }
+ res = gst_pad_push_event (dvdlpcmdec->srcpad, event);
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:
+ gst_segment_init (&dvdlpcmdec->segment, GST_FORMAT_UNDEFINED);
+ res = gst_pad_push_event (dvdlpcmdec->srcpad, event);
+ break;
+ default:
+ res = gst_pad_push_event (dvdlpcmdec->srcpad, event);
+ break;
+ }
+
+ return res;
+}
+
+static GstStateChangeReturn
+gst_dvdlpcmdec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (element);
+ GstStateChangeReturn res;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_dvdlpcm_reset (dvdlpcmdec);
+ break;
+ default:
+ break;
+ }
+
+ res = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (dvdlpcm_debug, "dvdlpcmdec", 0, "DVD LPCM Decoder");
+
+ if (!gst_element_register (plugin, "dvdlpcmdec", GST_RANK_PRIMARY,
+ GST_TYPE_DVDLPCMDEC)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ dvdlpcmdec,
+ "Decode DVD LPCM frames into standard PCM",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.h b/gst/dvdlpcmdec/gstdvdlpcmdec.h
new file mode 100644
index 0000000..955f60c
--- /dev/null
+++ b/gst/dvdlpcmdec/gstdvdlpcmdec.h
@@ -0,0 +1,69 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Jan Schmidt <jan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DVDLPCMDEC_H__
+#define __GST_DVDLPCMDEC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DVDLPCMDEC \
+ (gst_dvdlpcmdec_get_type())
+#define GST_DVDLPCMDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDLPCMDEC,GstDvdLpcmDec))
+#define GST_DVDLPCMDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDLPCMDEC,GstDvdLpcmDecClass))
+#define GST_IS_DVDLPCMDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDLPCMDEC))
+#define GST_IS_DVDLPCMDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDLPCMDEC))
+
+typedef struct _GstDvdLpcmDec GstDvdLpcmDec;
+typedef struct _GstDvdLpcmDecClass GstDvdLpcmDecClass;
+
+struct _GstDvdLpcmDec {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ guint32 header;
+
+ GstAudioInfo info;
+ const GstAudioChannelPosition *lpcm_layout;
+ gint width;
+ gint dynamic_range;
+ gint emphasis;
+ gint mute;
+
+ GstClockTime timestamp;
+ GstSegment segment;
+};
+
+struct _GstDvdLpcmDecClass {
+ GstElementClass parent_class;
+};
+
+GType gst_dvdlpcmdec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DVDLPCMDEC_H__ */
diff --git a/gst/dvdsub/Makefile.am b/gst/dvdsub/Makefile.am
new file mode 100644
index 0000000..5272ac5
--- /dev/null
+++ b/gst/dvdsub/Makefile.am
@@ -0,0 +1,25 @@
+plugin_LTLIBRARIES = libgstdvdsub.la
+
+libgstdvdsub_la_SOURCES = gstdvdsubdec.c gstdvdsubparse.c
+libgstdvdsub_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstdvdsub_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+ $(GST_BASE_LIBS) $(GST_LIBS)
+libgstdvdsub_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdvdsub_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = gstdvdsubdec.h gstdvdsubparse.h
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstdvdsub -:SHARED libgstdvdsub \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstdvdsub_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdvdsub_la_CFLAGS) \
+ -:LDFLAGS $(libgstdvdsub_la_LDFLAGS) \
+ $(libgstdvdsub_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
diff --git a/gst/dvdsub/Makefile.in b/gst/dvdsub/Makefile.in
new file mode 100644
index 0000000..9fd3f77
--- /dev/null
+++ b/gst/dvdsub/Makefile.in
@@ -0,0 +1,852 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = gst/dvdsub
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-function.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/a52.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-sid.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstdvdsub_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstdvdsub_la_OBJECTS = libgstdvdsub_la-gstdvdsubdec.lo \
+ libgstdvdsub_la-gstdvdsubparse.lo
+libgstdvdsub_la_OBJECTS = $(am_libgstdvdsub_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgstdvdsub_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstdvdsub_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstdvdsub_la_CFLAGS) $(CFLAGS) \
+ $(libgstdvdsub_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgstdvdsub_la_SOURCES)
+DIST_SOURCES = $(libgstdvdsub_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A52DEC_CFLAGS = @A52DEC_CFLAGS@
+A52DEC_LIBS = @A52DEC_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMRNB_CFLAGS = @AMRNB_CFLAGS@
+AMRNB_LIBS = @AMRNB_LIBS@
+AMRWB_CFLAGS = @AMRWB_CFLAGS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDIO_CFLAGS = @CDIO_CFLAGS@
+CDIO_LIBS = @CDIO_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVDREAD_LIBS = @DVDREAD_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DVDREAD = @HAVE_DVDREAD@
+HAVE_LAME = @HAVE_LAME@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LAME_CFLAGS = @LAME_CFLAGS@
+LAME_LIBS = @LAME_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPEG2DEC_CFLAGS = @MPEG2DEC_CFLAGS@
+MPEG2DEC_LIBS = @MPEG2DEC_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIDPLAY_CFLAGS = @SIDPLAY_CFLAGS@
+SIDPLAY_LIBS = @SIDPLAY_LIBS@
+STRIP = @STRIP@
+TWOLAME_CFLAGS = @TWOLAME_CFLAGS@
+TWOLAME_LIBS = @TWOLAME_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WIN32_LIBS = @WIN32_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstdvdsub.la
+libgstdvdsub_la_SOURCES = gstdvdsubdec.c gstdvdsubparse.c
+libgstdvdsub_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+
+libgstdvdsub_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+ $(GST_BASE_LIBS) $(GST_LIBS)
+
+libgstdvdsub_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdvdsub_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+noinst_HEADERS = gstdvdsubdec.h gstdvdsubparse.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/dvdsub/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/dvdsub/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgstdvdsub.la: $(libgstdvdsub_la_OBJECTS) $(libgstdvdsub_la_DEPENDENCIES) $(EXTRA_libgstdvdsub_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstdvdsub_la_LINK) -rpath $(plugindir) $(libgstdvdsub_la_OBJECTS) $(libgstdvdsub_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdvdsub_la-gstdvdsubdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdvdsub_la-gstdvdsubparse.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstdvdsub_la-gstdvdsubdec.lo: gstdvdsubdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdvdsub_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdvdsub_la_CFLAGS) $(CFLAGS) -MT libgstdvdsub_la-gstdvdsubdec.lo -MD -MP -MF $(DEPDIR)/libgstdvdsub_la-gstdvdsubdec.Tpo -c -o libgstdvdsub_la-gstdvdsubdec.lo `test -f 'gstdvdsubdec.c' || echo '$(srcdir)/'`gstdvdsubdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdvdsub_la-gstdvdsubdec.Tpo $(DEPDIR)/libgstdvdsub_la-gstdvdsubdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdvdsubdec.c' object='libgstdvdsub_la-gstdvdsubdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdvdsub_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdvdsub_la_CFLAGS) $(CFLAGS) -c -o libgstdvdsub_la-gstdvdsubdec.lo `test -f 'gstdvdsubdec.c' || echo '$(srcdir)/'`gstdvdsubdec.c
+
+libgstdvdsub_la-gstdvdsubparse.lo: gstdvdsubparse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdvdsub_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdvdsub_la_CFLAGS) $(CFLAGS) -MT libgstdvdsub_la-gstdvdsubparse.lo -MD -MP -MF $(DEPDIR)/libgstdvdsub_la-gstdvdsubparse.Tpo -c -o libgstdvdsub_la-gstdvdsubparse.lo `test -f 'gstdvdsubparse.c' || echo '$(srcdir)/'`gstdvdsubparse.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdvdsub_la-gstdvdsubparse.Tpo $(DEPDIR)/libgstdvdsub_la-gstdvdsubparse.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdvdsubparse.c' object='libgstdvdsub_la-gstdvdsubparse.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdvdsub_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdvdsub_la_CFLAGS) $(CFLAGS) -c -o libgstdvdsub_la-gstdvdsubparse.lo `test -f 'gstdvdsubparse.c' || echo '$(srcdir)/'`gstdvdsubparse.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstdvdsub -:SHARED libgstdvdsub \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstdvdsub_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdvdsub_la_CFLAGS) \
+ -:LDFLAGS $(libgstdvdsub_la_LDFLAGS) \
+ $(libgstdvdsub_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/dvdsub/gstdvdsubdec.c b/gst/dvdsub/gstdvdsubdec.c
new file mode 100644
index 0000000..2589ee6
--- /dev/null
+++ b/gst/dvdsub/gstdvdsubdec.c
@@ -0,0 +1,1160 @@
+/* GStreamer
+ * Copyright (C) <2005> Jan Schmidt <jan@fluendo.com>
+ * Copyright (C) <2002> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdvdsubdec.h"
+#include "gstdvdsubparse.h"
+#include <string.h>
+
+#define gst_dvd_sub_dec_parent_class parent_class
+G_DEFINE_TYPE (GstDvdSubDec, gst_dvd_sub_dec, GST_TYPE_ELEMENT);
+
+static gboolean gst_dvd_sub_dec_src_event (GstPad * srcpad, GstObject * parent,
+ GstEvent * event);
+static GstFlowReturn gst_dvd_sub_dec_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buf);
+
+static gboolean gst_dvd_sub_dec_handle_dvd_event (GstDvdSubDec * dec,
+ GstEvent * event);
+static void gst_dvd_sub_dec_finalize (GObject * gobject);
+static void gst_setup_palette (GstDvdSubDec * dec);
+static void gst_dvd_sub_dec_merge_title (GstDvdSubDec * dec,
+ GstVideoFrame * frame);
+static GstClockTime gst_dvd_sub_dec_get_event_delay (GstDvdSubDec * dec);
+static gboolean gst_dvd_sub_dec_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static gboolean gst_dvd_sub_dec_sink_setcaps (GstPad * pad, GstCaps * caps);
+
+static GstFlowReturn gst_send_subtitle_frame (GstDvdSubDec * dec,
+ GstClockTime end_ts);
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw, format = (string) { AYUV, ARGB },"
+ "width = (int) 720, height = (int) 576, framerate = (fraction) 0/1")
+ );
+
+static GstStaticPadTemplate subtitle_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("subpicture/x-dvd")
+ );
+
+GST_DEBUG_CATEGORY_STATIC (gst_dvd_sub_dec_debug);
+#define GST_CAT_DEFAULT (gst_dvd_sub_dec_debug)
+
+enum
+{
+ SPU_FORCE_DISPLAY = 0x00,
+ SPU_SHOW = 0x01,
+ SPU_HIDE = 0x02,
+ SPU_SET_PALETTE = 0x03,
+ SPU_SET_ALPHA = 0x04,
+ SPU_SET_SIZE = 0x05,
+ SPU_SET_OFFSETS = 0x06,
+ SPU_WIPE = 0x07,
+ SPU_END = 0xff
+};
+
+static const guint32 default_clut[16] = {
+ 0xb48080, 0x248080, 0x628080, 0xd78080,
+ 0x808080, 0x808080, 0x808080, 0x808080,
+ 0x808080, 0x808080, 0x808080, 0x808080,
+ 0x808080, 0x808080, 0x808080, 0x808080
+};
+
+typedef struct RLE_state
+{
+ gint id;
+ gint aligned;
+ gint offset[2];
+ gint hl_left;
+ gint hl_right;
+
+ guchar *target;
+
+ guchar next;
+}
+RLE_state;
+
+static void
+gst_dvd_sub_dec_class_init (GstDvdSubDecClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_dvd_sub_dec_finalize;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&subtitle_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "DVD subtitle decoder", "Codec/Decoder/Video",
+ "Decodes DVD subtitles into AYUV video frames",
+ "Wim Taymans <wim.taymans@gmail.com>, "
+ "Jan Schmidt <thaytan@mad.scientist.com>");
+}
+
+static void
+gst_dvd_sub_dec_init (GstDvdSubDec * dec)
+{
+ GstPadTemplate *tmpl;
+
+ dec->sinkpad = gst_pad_new_from_static_template (&subtitle_template, "sink");
+ gst_pad_set_chain_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_chain));
+ gst_pad_set_event_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_sink_event));
+ gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+
+ tmpl = gst_static_pad_template_get (&src_template);
+ dec->srcpad = gst_pad_new_from_template (tmpl, "src");
+ gst_pad_set_event_function (dec->srcpad,
+ GST_DEBUG_FUNCPTR (gst_dvd_sub_dec_src_event));
+ gst_pad_use_fixed_caps (dec->srcpad);
+ gst_object_unref (tmpl);
+ gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+
+ /* FIXME: aren't there more possible sizes? (tpm) */
+ dec->in_width = 720;
+ dec->in_height = 576;
+
+ dec->partialbuf = NULL;
+ dec->have_title = FALSE;
+ dec->parse_pos = NULL;
+ dec->forced_display = FALSE;
+ dec->visible = FALSE;
+
+ memcpy (dec->current_clut, default_clut, sizeof (guint32) * 16);
+
+ gst_setup_palette (dec);
+
+ dec->next_ts = 0;
+ dec->next_event_ts = GST_CLOCK_TIME_NONE;
+
+ dec->buf_dirty = TRUE;
+ dec->use_ARGB = FALSE;
+}
+
+static void
+gst_dvd_sub_dec_finalize (GObject * gobject)
+{
+ GstDvdSubDec *dec = GST_DVD_SUB_DEC (gobject);
+
+ if (dec->partialbuf) {
+ gst_buffer_unmap (dec->partialbuf, &dec->partialmap);
+ gst_buffer_unref (dec->partialbuf);
+ dec->partialbuf = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (gobject);
+}
+
+static gboolean
+gst_dvd_sub_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ gboolean res = FALSE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ default:
+ res = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return res;
+}
+
+static GstClockTime
+gst_dvd_sub_dec_get_event_delay (GstDvdSubDec * dec)
+{
+ guchar *buf;
+ guint16 ticks;
+ GstClockTime event_delay;
+
+ /* If starting a new buffer, follow the first DCSQ ptr */
+ if (dec->parse_pos == dec->partialmap.data) {
+ buf = dec->parse_pos + dec->data_size;
+ } else {
+ buf = dec->parse_pos;
+ }
+
+ ticks = GST_READ_UINT16_BE (buf);
+ event_delay = gst_util_uint64_scale (ticks, 1024 * GST_SECOND, 90000);
+
+ GST_DEBUG_OBJECT (dec, "returning delay %" GST_TIME_FORMAT " from offset %u",
+ GST_TIME_ARGS (event_delay), (guint) (buf - dec->parse_pos));
+
+ return event_delay;
+}
+
+/*
+ * Parse the next event time in the current subpicture buffer, stopping
+ * when time advances to the next state.
+ */
+static void
+gst_dvd_sub_dec_parse_subpic (GstDvdSubDec * dec)
+{
+#define PARSE_BYTES_NEEDED(x) if ((buf+(x)) >= end) \
+ { GST_WARNING("Subtitle stream broken parsing %c", *buf); \
+ broken = TRUE; break; }
+
+ guchar *start = dec->partialmap.data;
+ guchar *buf;
+ guchar *end;
+ gboolean broken = FALSE;
+ gboolean last_seq = FALSE;
+ guchar *next_seq = NULL;
+ GstClockTime event_time;
+
+ /* nothing to do if we finished this buffer already */
+ if (dec->parse_pos == NULL)
+ return;
+
+ g_return_if_fail (dec->packet_size >= 4);
+
+ end = start + dec->packet_size;
+ if (dec->parse_pos == start) {
+ buf = dec->parse_pos + dec->data_size;
+ } else {
+ buf = dec->parse_pos;
+ }
+
+ g_assert (buf >= start && buf < end);
+
+ /* If the next control sequence is at the current offset, this is
+ * the last one */
+ next_seq = start + GST_READ_UINT16_BE (buf + 2);
+ last_seq = (next_seq == buf);
+ buf += 4;
+
+ while ((buf < end) && (!broken)) {
+ switch (*buf) {
+ case SPU_FORCE_DISPLAY: /* Forced display menu subtitle */
+ dec->forced_display = TRUE;
+ dec->buf_dirty = TRUE;
+ GST_DEBUG_OBJECT (dec, "SPU FORCE_DISPLAY");
+ buf++;
+ break;
+ case SPU_SHOW: /* Show the subtitle in this packet */
+ dec->visible = TRUE;
+ dec->buf_dirty = TRUE;
+ GST_DEBUG_OBJECT (dec, "SPU SHOW at %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dec->next_event_ts));
+ buf++;
+ break;
+ case SPU_HIDE:
+ /* 02 ff (ff) is the end of the packet, hide the subpicture */
+ dec->visible = FALSE;
+ dec->buf_dirty = TRUE;
+
+ GST_DEBUG_OBJECT (dec, "SPU HIDE at %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dec->next_event_ts));
+ buf++;
+ break;
+ case SPU_SET_PALETTE: /* palette */
+ PARSE_BYTES_NEEDED (3);
+
+ GST_DEBUG_OBJECT (dec, "SPU SET_PALETTE");
+
+ dec->subtitle_index[3] = buf[1] >> 4;
+ dec->subtitle_index[2] = buf[1] & 0xf;
+ dec->subtitle_index[1] = buf[2] >> 4;
+ dec->subtitle_index[0] = buf[2] & 0xf;
+ gst_setup_palette (dec);
+
+ dec->buf_dirty = TRUE;
+ buf += 3;
+ break;
+ case SPU_SET_ALPHA: /* transparency palette */
+ PARSE_BYTES_NEEDED (3);
+
+ GST_DEBUG_OBJECT (dec, "SPU SET_ALPHA");
+
+ dec->subtitle_alpha[3] = buf[1] >> 4;
+ dec->subtitle_alpha[2] = buf[1] & 0xf;
+ dec->subtitle_alpha[1] = buf[2] >> 4;
+ dec->subtitle_alpha[0] = buf[2] & 0xf;
+ gst_setup_palette (dec);
+
+ dec->buf_dirty = TRUE;
+ buf += 3;
+ break;
+ case SPU_SET_SIZE: /* image coordinates */
+ PARSE_BYTES_NEEDED (7);
+
+ dec->top = ((buf[4] & 0x3f) << 4) | ((buf[5] & 0xe0) >> 4);
+ dec->left = ((buf[1] & 0x3f) << 4) | ((buf[2] & 0xf0) >> 4);
+ dec->right = ((buf[2] & 0x03) << 8) | buf[3];
+ dec->bottom = ((buf[5] & 0x03) << 8) | buf[6];
+
+ GST_DEBUG_OBJECT (dec, "SPU SET_SIZE left %d, top %d, right %d, "
+ "bottom %d", dec->left, dec->top, dec->right, dec->bottom);
+
+ dec->buf_dirty = TRUE;
+ buf += 7;
+ break;
+ case SPU_SET_OFFSETS: /* image 1 / image 2 offsets */
+ PARSE_BYTES_NEEDED (5);
+
+ dec->offset[0] = (((guint) buf[1]) << 8) | buf[2];
+ dec->offset[1] = (((guint) buf[3]) << 8) | buf[4];
+ GST_DEBUG_OBJECT (dec, "Offset1 %d, Offset2 %d",
+ dec->offset[0], dec->offset[1]);
+
+ dec->buf_dirty = TRUE;
+ buf += 5;
+ break;
+ case SPU_WIPE:
+ {
+ guint length;
+
+ PARSE_BYTES_NEEDED (3);
+
+ GST_WARNING_OBJECT (dec, "SPU_WIPE not yet implemented");
+
+ length = (buf[1] << 8) | (buf[2]);
+ buf += 1 + length;
+
+ dec->buf_dirty = TRUE;
+ break;
+ }
+ case SPU_END:
+ buf = (last_seq) ? end : next_seq;
+
+ /* Start a new control sequence */
+ if (buf + 4 < end) {
+ guint16 ticks = GST_READ_UINT16_BE (buf);
+
+ event_time = gst_util_uint64_scale (ticks, 1024 * GST_SECOND, 90000);
+
+ GST_DEBUG_OBJECT (dec,
+ "Next DCSQ at offset %u, delay %g secs (%d ticks)",
+ (guint) (buf - start),
+ gst_util_guint64_to_gdouble (event_time / GST_SECOND), ticks);
+
+ dec->parse_pos = buf;
+ if (event_time > 0) {
+ dec->next_event_ts += event_time;
+
+ GST_LOG_OBJECT (dec, "Exiting parse loop with time %g",
+ gst_guint64_to_gdouble (dec->next_event_ts) /
+ gst_guint64_to_gdouble (GST_SECOND));
+ return;
+ }
+ break;
+ } else {
+ dec->parse_pos = NULL;
+ dec->next_event_ts = GST_CLOCK_TIME_NONE;
+ GST_LOG_OBJECT (dec, "Finished all cmds. Exiting parse loop");
+ return;
+ }
+ default:
+ GST_ERROR
+ ("Invalid sequence in subtitle packet header (%.2x). Skipping",
+ *buf);
+ broken = TRUE;
+ dec->parse_pos = NULL;
+ break;
+ }
+ }
+}
+
+static inline int
+gst_get_nibble (guchar * buffer, RLE_state * state)
+{
+ if (state->aligned) {
+ state->next = buffer[state->offset[state->id]++];
+ state->aligned = 0;
+ return state->next >> 4;
+ } else {
+ state->aligned = 1;
+ return state->next & 0xf;
+ }
+}
+
+/* Premultiply the current lookup table into the "target" cache */
+static void
+gst_setup_palette (GstDvdSubDec * dec)
+{
+ gint i;
+ guint32 col;
+ Color_val *target_yuv = dec->palette_cache_yuv;
+ Color_val *target2_yuv = dec->hl_palette_cache_yuv;
+ Color_val *target_rgb = dec->palette_cache_rgb;
+ Color_val *target2_rgb = dec->hl_palette_cache_rgb;
+
+ for (i = 0; i < 4; i++, target2_yuv++, target_yuv++) {
+ col = dec->current_clut[dec->subtitle_index[i]];
+ target_yuv->Y_R = (col >> 16) & 0xff;
+ target_yuv->V_B = (col >> 8) & 0xff;
+ target_yuv->U_G = col & 0xff;
+ target_yuv->A = dec->subtitle_alpha[i] * 0xff / 0xf;
+
+ col = dec->current_clut[dec->menu_index[i]];
+ target2_yuv->Y_R = (col >> 16) & 0xff;
+ target2_yuv->V_B = (col >> 8) & 0xff;
+ target2_yuv->U_G = col & 0xff;
+ target2_yuv->A = dec->menu_alpha[i] * 0xff / 0xf;
+
+ /* If ARGB flag set, then convert YUV palette to RGB */
+ /* Using integer aritmetic */
+ if (dec->use_ARGB) {
+ guchar C = target_yuv->Y_R - 16;
+ guchar D = target_yuv->U_G - 128;
+ guchar E = target_yuv->V_B - 128;
+
+ target_rgb->Y_R = CLAMP (((298 * C + 409 * E + 128) >> 8), 0, 255);
+ target_rgb->U_G =
+ CLAMP (((298 * C - 100 * D - 128 * E + 128) >> 8), 0, 255);
+ target_rgb->V_B = CLAMP (((298 * C + 516 * D + 128) >> 8), 0, 255);
+ target_rgb->A = target_yuv->A;
+
+ C = target2_yuv->Y_R - 16;
+ D = target2_yuv->U_G - 128;
+ E = target2_yuv->V_B - 128;
+
+ target2_rgb->Y_R = CLAMP (((298 * C + 409 * E + 128) >> 8), 0, 255);
+ target2_rgb->U_G =
+ CLAMP (((298 * C - 100 * D - 128 * E + 128) >> 8), 0, 255);
+ target2_rgb->V_B = CLAMP (((298 * C + 516 * D + 128) >> 8), 0, 255);
+ target2_rgb->A = target2_yuv->A;
+ }
+ target_rgb++;
+ target2_rgb++;
+ }
+}
+
+static inline guint
+gst_get_rle_code (guchar * buffer, RLE_state * state)
+{
+ gint code;
+
+ code = gst_get_nibble (buffer, state);
+ if (code < 0x4) { /* 4 .. f */
+ code = (code << 4) | gst_get_nibble (buffer, state);
+ if (code < 0x10) { /* 1x .. 3x */
+ code = (code << 4) | gst_get_nibble (buffer, state);
+ if (code < 0x40) { /* 04x .. 0fx */
+ code = (code << 4) | gst_get_nibble (buffer, state);
+ }
+ }
+ }
+ return code;
+}
+
+#define DRAW_RUN(target,len,c) \
+G_STMT_START { \
+ gint i = 0; \
+ if ((c)->A) { \
+ for (i = 0; i < (len); i++) { \
+ *(target)++ = (c)->A; \
+ *(target)++ = (c)->Y_R; \
+ *(target)++ = (c)->U_G; \
+ *(target)++ = (c)->V_B; \
+ } \
+ } else { \
+ (target) += 4 * (len); \
+ } \
+} G_STMT_END
+
+/*
+ * This function steps over each run-length segment, drawing
+ * into the YUVA/ARGB buffers as it goes. UV are composited and then output
+ * at half width/height
+ */
+static void
+gst_draw_rle_line (GstDvdSubDec * dec, guchar * buffer, RLE_state * state)
+{
+ gint length, colourid;
+ guint code;
+ gint x, right;
+ guchar *target;
+
+ target = state->target;
+
+ x = dec->left;
+ right = dec->right + 1;
+
+ while (x < right) {
+ gboolean in_hl;
+ const Color_val *colour_entry;
+
+ code = gst_get_rle_code (buffer, state);
+ length = code >> 2;
+ colourid = code & 3;
+ if (dec->use_ARGB)
+ colour_entry = dec->palette_cache_rgb + colourid;
+ else
+ colour_entry = dec->palette_cache_yuv + colourid;
+
+ /* Length = 0 implies fill to the end of the line */
+ /* Restrict the colour run to the end of the line */
+ if (length == 0 || x + length > right)
+ length = right - x;
+
+ /* Check if this run of colour touches the highlight region */
+ in_hl = ((x <= state->hl_right) && (x + length) >= state->hl_left);
+ if (in_hl) {
+ gint run;
+
+ /* Draw to the left of the highlight */
+ if (x <= state->hl_left) {
+ run = MIN (length, state->hl_left - x + 1);
+
+ DRAW_RUN (target, run, colour_entry);
+ length -= run;
+ x += run;
+ }
+
+ /* Draw across the highlight region */
+ if (x <= state->hl_right) {
+ const Color_val *hl_colour;
+ if (dec->use_ARGB)
+ hl_colour = dec->hl_palette_cache_rgb + colourid;
+ else
+ hl_colour = dec->hl_palette_cache_yuv + colourid;
+
+ run = MIN (length, state->hl_right - x + 1);
+
+ DRAW_RUN (target, run, hl_colour);
+ length -= run;
+ x += run;
+ }
+ }
+
+ /* Draw the rest of the run */
+ if (length > 0) {
+ DRAW_RUN (target, length, colour_entry);
+ x += length;
+ }
+ }
+}
+
+/*
+ * Decode the RLE subtitle image and blend with the current
+ * frame buffer.
+ */
+static void
+gst_dvd_sub_dec_merge_title (GstDvdSubDec * dec, GstVideoFrame * frame)
+{
+ gint y;
+ gint Y_stride;
+ guchar *buffer = dec->partialmap.data;
+ gint hl_top, hl_bottom;
+ gint last_y;
+ RLE_state state;
+ guint8 *Y_data;;
+
+ GST_DEBUG_OBJECT (dec, "Merging subtitle on frame");
+
+ Y_data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+ Y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+ state.id = 0;
+ state.aligned = 1;
+ state.next = 0;
+ state.offset[0] = dec->offset[0];
+ state.offset[1] = dec->offset[1];
+
+ /* center the image when display rectangle exceeds the video width */
+ if (dec->in_width <= dec->right) {
+ gint left, disp_width;
+
+ disp_width = dec->right - dec->left + 1;
+ left = (dec->in_width - disp_width) / 2;
+ dec->left = left;
+ dec->right = left + disp_width - 1;
+
+ /* if it clips to the right, shift it left, but only till zero */
+ if (dec->right >= dec->in_width) {
+ gint shift = dec->right - dec->in_width - 1;
+ if (shift > dec->left)
+ shift = dec->left;
+ dec->left -= shift;
+ dec->right -= shift;
+ }
+
+ GST_DEBUG_OBJECT (dec, "clipping width to %d,%d",
+ dec->left, dec->in_width - 1);
+ }
+
+ /* for the height, bring it up till it fits as well as it can. We
+ * assume the picture is in the lower part. We should better check where it
+ * is and do something more clever. */
+ if (dec->in_height <= dec->bottom) {
+
+ /* shift it up, but only till zero */
+ gint shift = dec->bottom - dec->in_height - 1;
+ if (shift > dec->top)
+ shift = dec->top;
+ dec->top -= shift;
+ dec->bottom -= shift;
+
+ /* start on even line */
+ if (dec->top & 1) {
+ dec->top--;
+ dec->bottom--;
+ }
+
+ GST_DEBUG_OBJECT (dec, "clipping height to %d,%d",
+ dec->top, dec->in_height - 1);
+ }
+
+ if (dec->current_button) {
+ hl_top = dec->hl_top;
+ hl_bottom = dec->hl_bottom;
+ } else {
+ hl_top = -1;
+ hl_bottom = -1;
+ }
+ last_y = MIN (dec->bottom, dec->in_height);
+
+ y = dec->top;
+ state.target = Y_data + 4 * dec->left + (y * Y_stride);
+
+ /* Now draw scanlines until we hit last_y or end of RLE data */
+ for (; ((state.offset[1] < dec->data_size + 2) && (y <= last_y)); y++) {
+ /* Set up to draw the highlight if we're in the right scanlines */
+ if (y > hl_bottom || y < hl_top) {
+ state.hl_left = -1;
+ state.hl_right = -1;
+ } else {
+ state.hl_left = dec->hl_left;
+ state.hl_right = dec->hl_right;
+ }
+ gst_draw_rle_line (dec, buffer, &state);
+
+ state.target += Y_stride;
+
+ /* Realign the RLE state for the next line */
+ if (!state.aligned)
+ gst_get_nibble (buffer, &state);
+ state.id = !state.id;
+ }
+}
+
+static void
+gst_send_empty_fill (GstDvdSubDec * dec, GstClockTime ts)
+{
+ if (dec->next_ts < ts) {
+ GST_LOG_OBJECT (dec, "Sending GAP event update to advance time to %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+
+ gst_pad_push_event (dec->srcpad,
+ gst_event_new_gap (dec->next_ts, ts - dec->next_ts));
+ }
+ dec->next_ts = ts;
+}
+
+static GstFlowReturn
+gst_send_subtitle_frame (GstDvdSubDec * dec, GstClockTime end_ts)
+{
+ GstFlowReturn flow;
+ GstBuffer *out_buf;
+ GstVideoFrame frame;
+ guint8 *data;
+ gint x, y;
+ static GstAllocationParams params = { 0, 3, 0, 0, };
+
+ g_assert (dec->have_title);
+ g_assert (dec->next_ts <= end_ts);
+
+ /* Check if we need to redraw the output buffer */
+ if (!dec->buf_dirty) {
+ flow = GST_FLOW_OK;
+ goto out;
+ }
+
+ out_buf =
+ gst_buffer_new_allocate (NULL, GST_VIDEO_INFO_SIZE (&dec->info),
+ &params);
+ gst_video_frame_map (&frame, &dec->info, out_buf, GST_MAP_READWRITE);
+
+ data = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
+
+ /* Clear the buffer */
+ /* FIXME - move this into the buffer rendering code */
+ for (y = 0; y < dec->in_height; y++) {
+ guchar *line = data + 4 * dec->in_width * y;
+
+ for (x = 0; x < dec->in_width; x++) {
+ line[0] = 0; /* A */
+ if (!dec->use_ARGB) {
+ line[1] = 16; /* Y */
+ line[2] = 128; /* U */
+ line[3] = 128; /* V */
+ } else {
+ line[1] = 0; /* R */
+ line[2] = 0; /* G */
+ line[3] = 0; /* B */
+ }
+
+ line += 4;
+ }
+ }
+
+ /* FIXME: do we really want to honour the forced_display flag
+ * for subtitles streans? */
+ if (dec->visible || dec->forced_display) {
+ gst_dvd_sub_dec_merge_title (dec, &frame);
+ }
+
+ gst_video_frame_unmap (&frame);
+
+ dec->buf_dirty = FALSE;
+
+ GST_BUFFER_TIMESTAMP (out_buf) = dec->next_ts;
+ if (GST_CLOCK_TIME_IS_VALID (dec->next_event_ts)) {
+ GST_BUFFER_DURATION (out_buf) = GST_CLOCK_DIFF (dec->next_ts,
+ dec->next_event_ts);
+ } else {
+ GST_BUFFER_DURATION (out_buf) = GST_CLOCK_TIME_NONE;
+ }
+
+ GST_DEBUG_OBJECT (dec, "Sending subtitle buffer with ts %"
+ GST_TIME_FORMAT ", dur %" G_GINT64_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf)),
+ GST_BUFFER_DURATION (out_buf));
+
+ flow = gst_pad_push (dec->srcpad, out_buf);
+
+out:
+ dec->next_ts = end_ts;
+ return flow;
+}
+
+/* Walk time forward, processing any subtitle events as needed. */
+static GstFlowReturn
+gst_dvd_sub_dec_advance_time (GstDvdSubDec * dec, GstClockTime new_ts)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ GST_LOG_OBJECT (dec, "Advancing time to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (new_ts));
+
+ if (!dec->have_title) {
+ gst_send_empty_fill (dec, new_ts);
+ return ret;
+ }
+
+ while (dec->next_ts < new_ts) {
+ GstClockTime next_ts = new_ts;
+
+ if (GST_CLOCK_TIME_IS_VALID (dec->next_event_ts) &&
+ dec->next_event_ts < next_ts) {
+ /* We might need to process the subtitle cmd queue */
+ next_ts = dec->next_event_ts;
+ }
+
+ /*
+ * Now, either output a filler or a frame spanning
+ * dec->next_ts to next_ts
+ */
+ if (dec->visible || dec->forced_display) {
+ ret = gst_send_subtitle_frame (dec, next_ts);
+ } else {
+ gst_send_empty_fill (dec, next_ts);
+ }
+
+ /*
+ * and then process some subtitle cmds if we need
+ */
+ if (next_ts == dec->next_event_ts)
+ gst_dvd_sub_dec_parse_subpic (dec);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_dvd_sub_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstDvdSubDec *dec;
+ guint8 *data;
+ glong size = 0;
+
+ dec = GST_DVD_SUB_DEC (parent);
+
+ GST_DEBUG_OBJECT (dec, "Have buffer of size %" G_GSIZE_FORMAT ", ts %"
+ GST_TIME_FORMAT ", dur %" G_GINT64_FORMAT, gst_buffer_get_size (buf),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_DURATION (buf));
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ if (!GST_CLOCK_TIME_IS_VALID (dec->next_ts)) {
+ dec->next_ts = GST_BUFFER_TIMESTAMP (buf);
+ }
+
+ /* Move time forward to the start of the new buffer */
+ ret = gst_dvd_sub_dec_advance_time (dec, GST_BUFFER_TIMESTAMP (buf));
+ }
+
+ if (dec->have_title) {
+ gst_buffer_unmap (dec->partialbuf, &dec->partialmap);
+ gst_buffer_unref (dec->partialbuf);
+ dec->partialbuf = NULL;
+ dec->have_title = FALSE;
+ }
+
+ GST_DEBUG_OBJECT (dec, "Got subtitle buffer, pts %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ /* deal with partial frame from previous buffer */
+ if (dec->partialbuf) {
+ gst_buffer_unmap (dec->partialbuf, &dec->partialmap);
+ dec->partialbuf = gst_buffer_append (dec->partialbuf, buf);
+ } else {
+ dec->partialbuf = buf;
+ }
+
+ gst_buffer_map (dec->partialbuf, &dec->partialmap, GST_MAP_READ);
+
+ data = dec->partialmap.data;
+ size = dec->partialmap.size;
+
+ if (size > 4) {
+ dec->packet_size = GST_READ_UINT16_BE (data);
+
+ if (dec->packet_size == size) {
+ GST_LOG_OBJECT (dec, "Subtitle packet size %d, current size %ld",
+ dec->packet_size, size);
+
+ dec->data_size = GST_READ_UINT16_BE (data + 2);
+
+ /* Reset parameters for a new subtitle buffer */
+ dec->parse_pos = data;
+ dec->forced_display = FALSE;
+ dec->visible = FALSE;
+
+ dec->have_title = TRUE;
+ dec->next_event_ts = GST_BUFFER_TIMESTAMP (dec->partialbuf);
+
+ if (!GST_CLOCK_TIME_IS_VALID (dec->next_event_ts))
+ dec->next_event_ts = dec->next_ts;
+
+ dec->next_event_ts += gst_dvd_sub_dec_get_event_delay (dec);
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_dvd_sub_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstDvdSubDec *dec = GST_DVD_SUB_DEC (gst_pad_get_parent (pad));
+ gboolean ret = FALSE;
+ GstCaps *out_caps = NULL, *peer_caps = NULL;
+
+ GST_DEBUG_OBJECT (dec, "setcaps called with %" GST_PTR_FORMAT, caps);
+
+ out_caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "AYUV",
+ "width", G_TYPE_INT, dec->in_width,
+ "height", G_TYPE_INT, dec->in_height,
+ "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+
+ peer_caps = gst_pad_get_allowed_caps (dec->srcpad);
+ if (G_LIKELY (peer_caps)) {
+ guint i = 0, n = 0;
+
+ n = gst_caps_get_size (peer_caps);
+ GST_DEBUG_OBJECT (dec, "peer allowed caps (%u structure(s)) are %"
+ GST_PTR_FORMAT, n, peer_caps);
+
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (peer_caps, i);
+ /* Check if the peer pad support ARGB format, if yes change caps */
+ if (gst_structure_has_name (s, "video/x-raw")) {
+ gst_caps_unref (out_caps);
+ GST_DEBUG_OBJECT (dec, "trying with ARGB");
+
+ out_caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "ARGB",
+ "width", G_TYPE_INT, dec->in_width,
+ "height", G_TYPE_INT, dec->in_height,
+ "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+
+ if (gst_pad_peer_query_accept_caps (dec->srcpad, out_caps)) {
+ GST_DEBUG_OBJECT (dec, "peer accepted ARGB");
+ /* If ARGB format then set the flag */
+ dec->use_ARGB = TRUE;
+ break;
+ }
+ }
+ }
+ gst_caps_unref (peer_caps);
+ }
+ GST_DEBUG_OBJECT (dec, "setting caps downstream to %" GST_PTR_FORMAT,
+ out_caps);
+ if (gst_pad_set_caps (dec->srcpad, out_caps)) {
+ gst_video_info_from_caps (&dec->info, out_caps);
+ } else {
+ GST_WARNING_OBJECT (dec, "failed setting downstream caps");
+ gst_caps_unref (out_caps);
+ goto beach;
+ }
+
+ gst_caps_unref (out_caps);
+ ret = TRUE;
+
+beach:
+ gst_object_unref (dec);
+ return ret;
+}
+
+static gboolean
+gst_dvd_sub_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstDvdSubDec *dec = GST_DVD_SUB_DEC (parent);
+ gboolean ret = FALSE;
+
+ GST_LOG_OBJECT (dec, "%s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ ret = gst_dvd_sub_dec_sink_setcaps (pad, caps);
+ gst_event_unref (event);
+ break;
+ }
+ case GST_EVENT_CUSTOM_DOWNSTREAM:{
+ GstClockTime ts = GST_EVENT_TIMESTAMP (event);
+
+ if (gst_event_has_name (event, "application/x-gst-dvd")) {
+ if (GST_CLOCK_TIME_IS_VALID (ts))
+ gst_dvd_sub_dec_advance_time (dec, ts);
+
+ if (gst_dvd_sub_dec_handle_dvd_event (dec, event)) {
+ /* gst_dvd_sub_dec_advance_time (dec, dec->next_ts + GST_SECOND / 30.0); */
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ }
+ }
+
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+ case GST_EVENT_GAP:
+ {
+ GstClockTime start, duration;
+
+ gst_event_parse_gap (event, &start, &duration);
+ if (GST_CLOCK_TIME_IS_VALID (start)) {
+ if (GST_CLOCK_TIME_IS_VALID (duration))
+ start += duration;
+ /* we do not expect another buffer until after gap,
+ * so that is our position now */
+ GST_DEBUG_OBJECT (dec, "Got GAP event, advancing time from %"
+ GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dec->next_ts), GST_TIME_ARGS (start));
+
+ gst_dvd_sub_dec_advance_time (dec, start);
+ } else {
+ GST_WARNING_OBJECT (dec, "Got GAP event with invalid position");
+ }
+
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ }
+ case GST_EVENT_SEGMENT:
+ {
+ GstSegment seg;
+
+ gst_event_copy_segment (event, &seg);
+
+ {
+#if 0
+ /* Turn off forced highlight display */
+ dec->forced_display = 0;
+ dec->current_button = 0;
+#endif
+ if (dec->partialbuf) {
+ gst_buffer_unmap (dec->partialbuf, &dec->partialmap);
+ gst_buffer_unref (dec->partialbuf);
+ dec->partialbuf = NULL;
+ dec->have_title = FALSE;
+ }
+
+ if (GST_CLOCK_TIME_IS_VALID (seg.time))
+ dec->next_ts = seg.time;
+ else
+ dec->next_ts = GST_CLOCK_TIME_NONE;
+
+ GST_DEBUG_OBJECT (dec, "Got newsegment, new time = %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (dec->next_ts));
+
+ ret = gst_pad_event_default (pad, parent, event);
+ }
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:{
+ /* Turn off forced highlight display */
+ dec->forced_display = 0;
+ dec->current_button = 0;
+
+ if (dec->partialbuf) {
+ gst_buffer_unmap (dec->partialbuf, &dec->partialmap);
+ gst_buffer_unref (dec->partialbuf);
+ dec->partialbuf = NULL;
+ dec->have_title = FALSE;
+ }
+
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+ default:{
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+ }
+ return ret;
+}
+
+static gboolean
+gst_dvd_sub_dec_handle_dvd_event (GstDvdSubDec * dec, GstEvent * event)
+{
+ GstStructure *structure;
+ const gchar *event_name;
+
+ structure = (GstStructure *) gst_event_get_structure (event);
+
+ if (structure == NULL)
+ goto not_handled;
+
+ event_name = gst_structure_get_string (structure, "event");
+
+ GST_LOG_OBJECT (dec,
+ "DVD event %s with timestamp %" G_GINT64_FORMAT " on sub pad",
+ GST_STR_NULL (event_name), GST_EVENT_TIMESTAMP (event));
+
+ if (event_name == NULL)
+ goto not_handled;
+
+ if (strcmp (event_name, "dvd-spu-highlight") == 0) {
+ gint button;
+ gint palette, sx, sy, ex, ey;
+ gint i;
+
+ /* Details for the highlight region to display */
+ if (!gst_structure_get_int (structure, "button", &button) ||
+ !gst_structure_get_int (structure, "palette", &palette) ||
+ !gst_structure_get_int (structure, "sx", &sx) ||
+ !gst_structure_get_int (structure, "sy", &sy) ||
+ !gst_structure_get_int (structure, "ex", &ex) ||
+ !gst_structure_get_int (structure, "ey", &ey)) {
+ GST_ERROR_OBJECT (dec, "Invalid dvd-spu-highlight event received");
+ return TRUE;
+ }
+ dec->current_button = button;
+ dec->hl_left = sx;
+ dec->hl_top = sy;
+ dec->hl_right = ex;
+ dec->hl_bottom = ey;
+ for (i = 0; i < 4; i++) {
+ dec->menu_alpha[i] = ((guint32) (palette) >> (i * 4)) & 0x0f;
+ dec->menu_index[i] = ((guint32) (palette) >> (16 + (i * 4))) & 0x0f;
+ }
+
+ GST_DEBUG_OBJECT (dec, "New button activated highlight=(%d,%d) to (%d,%d) "
+ "palette 0x%x", sx, sy, ex, ey, palette);
+ gst_setup_palette (dec);
+
+ dec->buf_dirty = TRUE;
+ } else if (strcmp (event_name, "dvd-spu-clut-change") == 0) {
+ /* Take a copy of the colour table */
+ gchar name[16];
+ int i;
+ gint value;
+
+ GST_LOG_OBJECT (dec, "New colour table received");
+ for (i = 0; i < 16; i++) {
+ g_snprintf (name, sizeof (name), "clut%02d", i);
+ if (!gst_structure_get_int (structure, name, &value)) {
+ GST_ERROR_OBJECT (dec, "dvd-spu-clut-change event did not "
+ "contain %s field", name);
+ break;
+ }
+ dec->current_clut[i] = (guint32) (value);
+ }
+
+ gst_setup_palette (dec);
+
+ dec->buf_dirty = TRUE;
+ } else if (strcmp (event_name, "dvd-spu-stream-change") == 0
+ || strcmp (event_name, "dvd-spu-reset-highlight") == 0) {
+ /* Turn off forced highlight display */
+ dec->current_button = 0;
+
+ GST_LOG_OBJECT (dec, "Clearing button state");
+ dec->buf_dirty = TRUE;
+ } else if (strcmp (event_name, "dvd-spu-still-frame") == 0) {
+ /* Handle a still frame */
+ GST_LOG_OBJECT (dec, "Received still frame notification");
+ } else {
+ goto not_handled;
+ }
+
+ return TRUE;
+
+not_handled:
+ {
+ /* Ignore all other unknown events */
+ GST_LOG_OBJECT (dec, "Ignoring other custom event %" GST_PTR_FORMAT,
+ structure);
+ return FALSE;
+ }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "dvdsubdec", GST_RANK_NONE,
+ GST_TYPE_DVD_SUB_DEC) ||
+ !gst_element_register (plugin, "dvdsubparse", GST_RANK_NONE,
+ GST_TYPE_DVD_SUB_PARSE)) {
+ return FALSE;
+ }
+
+ GST_DEBUG_CATEGORY_INIT (gst_dvd_sub_dec_debug, "dvdsubdec", 0,
+ "DVD subtitle decoder");
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ dvdsub,
+ "DVD subtitle parser and decoder", plugin_init,
+ VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/dvdsub/gstdvdsubdec.h b/gst/dvdsub/gstdvdsubdec.h
new file mode 100644
index 0000000..a75e439
--- /dev/null
+++ b/gst/dvdsub/gstdvdsubdec.h
@@ -0,0 +1,102 @@
+/* GStreamer
+ * Copyright (C) <2005> Jan Schmidt <jan@fluendo.com>
+ * Copyright (C) <2002> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#define GST_TYPE_DVD_SUB_DEC (gst_dvd_sub_dec_get_type())
+#define GST_DVD_SUB_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVD_SUB_DEC,GstDvdSubDec))
+#define GST_DVD_SUB_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVD_SUB_DEC,GstDvdSubDecClass))
+#define GST_IS_DVD_SUB_DEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVD_SUB_DEC))
+#define GST_IS_DVD_SUB_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVD_SUB_DEC))
+
+typedef struct _GstDvdSubDec GstDvdSubDec;
+typedef struct _GstDvdSubDecClass GstDvdSubDecClass;
+
+/* Hold premultimplied colour values */
+typedef struct Color_val
+{
+ guchar Y_R;
+ guchar U_G;
+ guchar V_B;
+ guchar A;
+
+} Color_val;
+
+struct _GstDvdSubDec
+{
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ gint in_width, in_height;
+
+ /* Collect together subtitle buffers until we have a full control sequence */
+ GstBuffer *partialbuf;
+ GstMapInfo partialmap;
+ gboolean have_title;
+
+ guchar subtitle_index[4];
+ guchar menu_index[4];
+ guchar subtitle_alpha[4];
+ guchar menu_alpha[4];
+
+ guint32 current_clut[16];
+ Color_val palette_cache_yuv[4];
+ Color_val hl_palette_cache_yuv[4];
+
+ Color_val palette_cache_rgb[4];
+ Color_val hl_palette_cache_rgb[4];
+
+ GstVideoInfo info;
+ gboolean use_ARGB;
+ GstClockTime next_ts;
+
+ /*
+ * State info for the current subpicture
+ * buffer
+ */
+ guchar *parse_pos;
+
+ guint16 packet_size;
+ guint16 data_size;
+
+ gint offset[2];
+
+ gboolean forced_display;
+ gboolean visible;
+
+ gint left, top, right, bottom;
+ gint hl_left, hl_top, hl_right, hl_bottom;
+
+ gint current_button;
+
+ GstClockTime next_event_ts;
+
+ gboolean buf_dirty;
+};
+
+struct _GstDvdSubDecClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_dvd_sub_dec_get_type (void);
diff --git a/gst/dvdsub/gstdvdsubparse.c b/gst/dvdsub/gstdvdsubparse.c
new file mode 100644
index 0000000..ea49e53
--- /dev/null
+++ b/gst/dvdsub/gstdvdsubparse.c
@@ -0,0 +1,241 @@
+/* GStreamer DVD subtitle parser
+ * Copyright (C) 2007 Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+#include "gstdvdsubparse.h"
+
+GST_DEBUG_CATEGORY_STATIC (dvdsubparse_debug);
+#define GST_CAT_DEFAULT dvdsubparse_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("subpicture/x-dvd, parsed=(boolean)true")
+ );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("subpicture/x-dvd")
+ );
+
+static void gst_dvd_sub_parse_finalize (GObject * object);
+
+static void gst_dvd_sub_parse_reset (GstDvdSubParse * parse);
+
+static gboolean gst_dvd_sub_parse_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static GstFlowReturn gst_dvd_sub_parse_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buf);
+
+static GstStateChangeReturn gst_dvd_sub_parse_change_state (GstElement *
+ element, GstStateChange transition);
+
+#define gst_dvd_sub_parse_parent_class parent_class
+G_DEFINE_TYPE (GstDvdSubParse, gst_dvd_sub_parse, GST_TYPE_ELEMENT);
+
+static void
+gst_dvd_sub_parse_class_init (GstDvdSubParseClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_dvd_sub_parse_finalize;
+
+ GST_DEBUG_CATEGORY_INIT (dvdsubparse_debug, "dvdsubparse", 0,
+ "DVD subtitle parser");
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_dvd_sub_parse_change_state);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "DVD subtitle parser", "Codec/Parser/Subtitle",
+ "Parses and packetizes DVD subtitle streams",
+ "Mark Nauwelaerts <mnauw@users.sourceforge.net>");
+}
+
+static void
+gst_dvd_sub_parse_finalize (GObject * object)
+{
+ GstDvdSubParse *parse = GST_DVD_SUB_PARSE (object);
+
+ g_object_unref (parse->adapter);
+ parse->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_dvd_sub_parse_init (GstDvdSubParse * parse)
+{
+ parse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
+ gst_pad_set_chain_function (parse->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvd_sub_parse_chain));
+ gst_pad_set_event_function (parse->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvd_sub_parse_event));
+ gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
+
+ parse->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+ gst_pad_use_fixed_caps (parse->srcpad);
+ gst_pad_set_caps (parse->srcpad,
+ gst_static_pad_template_get_caps (&src_template));
+ gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
+
+ /* remainder */
+ parse->adapter = gst_adapter_new ();
+ gst_dvd_sub_parse_reset (parse);
+}
+
+static void
+gst_dvd_sub_parse_reset (GstDvdSubParse * parse)
+{
+ parse->needed = 0;
+ parse->stamp = GST_CLOCK_TIME_NONE;
+ gst_adapter_clear (parse->adapter);
+}
+
+static gboolean
+gst_dvd_sub_parse_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstDvdSubParse *parse;
+ gboolean ret;
+
+ parse = GST_DVD_SUB_PARSE (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_unref (event);
+ caps = gst_static_pad_template_get_caps (&src_template);
+ gst_pad_push_event (parse->srcpad, gst_event_new_caps (caps));
+ gst_caps_unref (caps);
+ ret = TRUE;
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:
+ gst_dvd_sub_parse_reset (parse);
+ /* fall-through */
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+}
+
+
+static GstFlowReturn
+gst_dvd_sub_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstDvdSubParse *parse = GST_DVD_SUB_PARSE (parent);
+ GstAdapter *adapter;
+ GstBuffer *outbuf = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ adapter = parse->adapter;
+
+ GST_LOG_OBJECT (parse, "%" G_GSIZE_FORMAT " bytes, ts: %" GST_TIME_FORMAT,
+ gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ gst_adapter_push (adapter, buf);
+
+ if (!parse->needed) {
+ guint8 data[2];
+
+ gst_adapter_copy (adapter, data, 0, 2);
+ parse->needed = GST_READ_UINT16_BE (data);
+ }
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ if (GST_CLOCK_TIME_IS_VALID (parse->stamp))
+ /* normally, we expect only the first fragment to carry a timestamp */
+ GST_WARNING_OBJECT (parse, "Received more timestamps than expected.");
+ else
+ parse->stamp = GST_BUFFER_TIMESTAMP (buf);
+ }
+
+ if (parse->needed) {
+ guint av;
+
+ av = gst_adapter_available (adapter);
+ if (av >= parse->needed) {
+ if (av > parse->needed) {
+ /* normally, we expect several fragment, boundary aligned */
+ GST_WARNING_OBJECT (parse, "Unexpected: needed %d, "
+ "but more (%d) is available.", parse->needed, av);
+ }
+ outbuf = gst_adapter_take_buffer (adapter, parse->needed);
+ /* decorate buffer */
+ GST_BUFFER_TIMESTAMP (outbuf) = parse->stamp;
+ /* reset state */
+ parse->stamp = GST_CLOCK_TIME_NONE;
+ parse->needed = 0;
+ /* and send along */
+ ret = gst_pad_push (parse->srcpad, outbuf);
+ }
+ }
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_dvd_sub_parse_change_state (GstElement * element, GstStateChange transition)
+{
+ GstDvdSubParse *parse = GST_DVD_SUB_PARSE (element);
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_dvd_sub_parse_reset (parse);
+ break;
+ default:
+ break;
+ }
+
+ return GST_STATE_CHANGE_SUCCESS;
+}
diff --git a/gst/dvdsub/gstdvdsubparse.h b/gst/dvdsub/gstdvdsubparse.h
new file mode 100644
index 0000000..6149232
--- /dev/null
+++ b/gst/dvdsub/gstdvdsubparse.h
@@ -0,0 +1,65 @@
+/* GStreamer DVD subtitle parser
+ * Copyright (C) 2007 Mark Nauwelaerts <mnauw@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DVDSUBPARSE_H__
+#define __GST_DVDSUBPARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DVD_SUB_PARSE \
+ (gst_dvd_sub_parse_get_type())
+#define GST_DVD_SUB_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DVD_SUB_PARSE, GstDvdSubParse))
+#define GST_DVD_SUB_PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DVD_SUB_PARSE, GstDvdSubParseClass))
+#define GST_DVD_SUB_PARSE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_DVD_SUB_PARSE, GstDvdSubParseClass))
+#define GST_IS_DVD_SUB_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DVD_SUB_PARSE))
+#define GST_IS_DVD_SUB_PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DVD_SUB_PARSE))
+
+typedef struct _GstDvdSubParse GstDvdSubParse;
+typedef struct _GstDvdSubParseClass GstDvdSubParseClass;
+
+struct _GstDvdSubParse {
+ GstElement element;
+
+ /*< private >*/
+ GstPad *srcpad;
+ GstPad *sinkpad;
+
+ GstAdapter *adapter; /* buffer incoming data */
+ GstClockTime stamp; /* timestamp of current packet */
+ guint needed; /* size of current packet to be assembled */
+};
+
+struct _GstDvdSubParseClass {
+ GstElementClass parent_class;
+};
+
+GType gst_dvd_sub_parse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DVDSUBPARSE_H__ */
+
diff --git a/gst/realmedia/Makefile.am b/gst/realmedia/Makefile.am
new file mode 100644
index 0000000..46cbbc3
--- /dev/null
+++ b/gst/realmedia/Makefile.am
@@ -0,0 +1,39 @@
+plugin_LTLIBRARIES = libgstrmdemux.la
+
+libgstrmdemux_la_SOURCES = rademux.c rmdemux.c \
+ rmutils.c rdtdepay.c rdtmanager.c \
+ rtspreal.c realhash.c asmrules.c \
+ rdtjitterbuffer.c gstrdtbuffer.c \
+ pnmsrc.c realmedia.c
+
+
+libgstrmdemux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstrmdemux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ -lgstrtsp-@GST_API_VERSION@ \
+ -lgstsdp-@GST_API_VERSION@ \
+ -lgstpbutils-@GST_API_VERSION@ \
+ $(GST_BASE_LIBS) $(GST_LIBS)
+libgstrmdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstrmdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = rademux.h rmdemux.h rmutils.h rdtdepay.h rdtmanager.h \
+ rdtjitterbuffer.h rtspreal.h realhash.h asmrules.h gstrdtbuffer.h \
+ pnmsrc.h
+
+noinst_PROGRAMS = asmrules
+asmrules_CFLAGS = $(GST_CFLAGS) -DTEST
+asmrules_LDADD = $(GST_LIBS) $(LIBM)
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstrmdemux -:SHARED libgstrmdemux \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstrmdemux_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstrmdemux_la_CFLAGS) \
+ -:LDFLAGS $(libgstrmdemux_la_LDFLAGS) \
+ $(libgstrmdemux_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
diff --git a/gst/realmedia/Makefile.in b/gst/realmedia/Makefile.in
new file mode 100644
index 0000000..5909e4a
--- /dev/null
+++ b/gst/realmedia/Makefile.in
@@ -0,0 +1,986 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+noinst_PROGRAMS = asmrules$(EXEEXT)
+subdir = gst/realmedia
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-function.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/a52.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-sid.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstrmdemux_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstrmdemux_la_OBJECTS = libgstrmdemux_la-rademux.lo \
+ libgstrmdemux_la-rmdemux.lo libgstrmdemux_la-rmutils.lo \
+ libgstrmdemux_la-rdtdepay.lo libgstrmdemux_la-rdtmanager.lo \
+ libgstrmdemux_la-rtspreal.lo libgstrmdemux_la-realhash.lo \
+ libgstrmdemux_la-asmrules.lo \
+ libgstrmdemux_la-rdtjitterbuffer.lo \
+ libgstrmdemux_la-gstrdtbuffer.lo libgstrmdemux_la-pnmsrc.lo \
+ libgstrmdemux_la-realmedia.lo
+libgstrmdemux_la_OBJECTS = $(am_libgstrmdemux_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgstrmdemux_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) \
+ $(libgstrmdemux_la_LDFLAGS) $(LDFLAGS) -o $@
+PROGRAMS = $(noinst_PROGRAMS)
+asmrules_SOURCES = asmrules.c
+asmrules_OBJECTS = asmrules-asmrules.$(OBJEXT)
+asmrules_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+asmrules_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(asmrules_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgstrmdemux_la_SOURCES) asmrules.c
+DIST_SOURCES = $(libgstrmdemux_la_SOURCES) asmrules.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A52DEC_CFLAGS = @A52DEC_CFLAGS@
+A52DEC_LIBS = @A52DEC_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMRNB_CFLAGS = @AMRNB_CFLAGS@
+AMRNB_LIBS = @AMRNB_LIBS@
+AMRWB_CFLAGS = @AMRWB_CFLAGS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDIO_CFLAGS = @CDIO_CFLAGS@
+CDIO_LIBS = @CDIO_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVDREAD_LIBS = @DVDREAD_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DVDREAD = @HAVE_DVDREAD@
+HAVE_LAME = @HAVE_LAME@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LAME_CFLAGS = @LAME_CFLAGS@
+LAME_LIBS = @LAME_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPEG2DEC_CFLAGS = @MPEG2DEC_CFLAGS@
+MPEG2DEC_LIBS = @MPEG2DEC_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIDPLAY_CFLAGS = @SIDPLAY_CFLAGS@
+SIDPLAY_LIBS = @SIDPLAY_LIBS@
+STRIP = @STRIP@
+TWOLAME_CFLAGS = @TWOLAME_CFLAGS@
+TWOLAME_LIBS = @TWOLAME_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WIN32_LIBS = @WIN32_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstrmdemux.la
+libgstrmdemux_la_SOURCES = rademux.c rmdemux.c \
+ rmutils.c rdtdepay.c rdtmanager.c \
+ rtspreal.c realhash.c asmrules.c \
+ rdtjitterbuffer.c gstrdtbuffer.c \
+ pnmsrc.c realmedia.c
+
+libgstrmdemux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstrmdemux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ -lgstrtsp-@GST_API_VERSION@ \
+ -lgstsdp-@GST_API_VERSION@ \
+ -lgstpbutils-@GST_API_VERSION@ \
+ $(GST_BASE_LIBS) $(GST_LIBS)
+
+libgstrmdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstrmdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+noinst_HEADERS = rademux.h rmdemux.h rmutils.h rdtdepay.h rdtmanager.h \
+ rdtjitterbuffer.h rtspreal.h realhash.h asmrules.h gstrdtbuffer.h \
+ pnmsrc.h
+
+asmrules_CFLAGS = $(GST_CFLAGS) -DTEST
+asmrules_LDADD = $(GST_LIBS) $(LIBM)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/realmedia/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/realmedia/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgstrmdemux.la: $(libgstrmdemux_la_OBJECTS) $(libgstrmdemux_la_DEPENDENCIES) $(EXTRA_libgstrmdemux_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstrmdemux_la_LINK) -rpath $(plugindir) $(libgstrmdemux_la_OBJECTS) $(libgstrmdemux_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+asmrules$(EXEEXT): $(asmrules_OBJECTS) $(asmrules_DEPENDENCIES) $(EXTRA_asmrules_DEPENDENCIES)
+ @rm -f asmrules$(EXEEXT)
+ $(AM_V_CCLD)$(asmrules_LINK) $(asmrules_OBJECTS) $(asmrules_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asmrules-asmrules.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-asmrules.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-gstrdtbuffer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-pnmsrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rademux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rdtdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rdtjitterbuffer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rdtmanager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-realhash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-realmedia.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rmdemux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rmutils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrmdemux_la-rtspreal.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstrmdemux_la-rademux.lo: rademux.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rademux.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rademux.Tpo -c -o libgstrmdemux_la-rademux.lo `test -f 'rademux.c' || echo '$(srcdir)/'`rademux.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rademux.Tpo $(DEPDIR)/libgstrmdemux_la-rademux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rademux.c' object='libgstrmdemux_la-rademux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rademux.lo `test -f 'rademux.c' || echo '$(srcdir)/'`rademux.c
+
+libgstrmdemux_la-rmdemux.lo: rmdemux.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rmdemux.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rmdemux.Tpo -c -o libgstrmdemux_la-rmdemux.lo `test -f 'rmdemux.c' || echo '$(srcdir)/'`rmdemux.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rmdemux.Tpo $(DEPDIR)/libgstrmdemux_la-rmdemux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rmdemux.c' object='libgstrmdemux_la-rmdemux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rmdemux.lo `test -f 'rmdemux.c' || echo '$(srcdir)/'`rmdemux.c
+
+libgstrmdemux_la-rmutils.lo: rmutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rmutils.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rmutils.Tpo -c -o libgstrmdemux_la-rmutils.lo `test -f 'rmutils.c' || echo '$(srcdir)/'`rmutils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rmutils.Tpo $(DEPDIR)/libgstrmdemux_la-rmutils.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rmutils.c' object='libgstrmdemux_la-rmutils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rmutils.lo `test -f 'rmutils.c' || echo '$(srcdir)/'`rmutils.c
+
+libgstrmdemux_la-rdtdepay.lo: rdtdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rdtdepay.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rdtdepay.Tpo -c -o libgstrmdemux_la-rdtdepay.lo `test -f 'rdtdepay.c' || echo '$(srcdir)/'`rdtdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rdtdepay.Tpo $(DEPDIR)/libgstrmdemux_la-rdtdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rdtdepay.c' object='libgstrmdemux_la-rdtdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rdtdepay.lo `test -f 'rdtdepay.c' || echo '$(srcdir)/'`rdtdepay.c
+
+libgstrmdemux_la-rdtmanager.lo: rdtmanager.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rdtmanager.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rdtmanager.Tpo -c -o libgstrmdemux_la-rdtmanager.lo `test -f 'rdtmanager.c' || echo '$(srcdir)/'`rdtmanager.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rdtmanager.Tpo $(DEPDIR)/libgstrmdemux_la-rdtmanager.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rdtmanager.c' object='libgstrmdemux_la-rdtmanager.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rdtmanager.lo `test -f 'rdtmanager.c' || echo '$(srcdir)/'`rdtmanager.c
+
+libgstrmdemux_la-rtspreal.lo: rtspreal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rtspreal.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rtspreal.Tpo -c -o libgstrmdemux_la-rtspreal.lo `test -f 'rtspreal.c' || echo '$(srcdir)/'`rtspreal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rtspreal.Tpo $(DEPDIR)/libgstrmdemux_la-rtspreal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtspreal.c' object='libgstrmdemux_la-rtspreal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rtspreal.lo `test -f 'rtspreal.c' || echo '$(srcdir)/'`rtspreal.c
+
+libgstrmdemux_la-realhash.lo: realhash.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-realhash.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-realhash.Tpo -c -o libgstrmdemux_la-realhash.lo `test -f 'realhash.c' || echo '$(srcdir)/'`realhash.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-realhash.Tpo $(DEPDIR)/libgstrmdemux_la-realhash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='realhash.c' object='libgstrmdemux_la-realhash.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-realhash.lo `test -f 'realhash.c' || echo '$(srcdir)/'`realhash.c
+
+libgstrmdemux_la-asmrules.lo: asmrules.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-asmrules.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-asmrules.Tpo -c -o libgstrmdemux_la-asmrules.lo `test -f 'asmrules.c' || echo '$(srcdir)/'`asmrules.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-asmrules.Tpo $(DEPDIR)/libgstrmdemux_la-asmrules.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asmrules.c' object='libgstrmdemux_la-asmrules.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-asmrules.lo `test -f 'asmrules.c' || echo '$(srcdir)/'`asmrules.c
+
+libgstrmdemux_la-rdtjitterbuffer.lo: rdtjitterbuffer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-rdtjitterbuffer.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-rdtjitterbuffer.Tpo -c -o libgstrmdemux_la-rdtjitterbuffer.lo `test -f 'rdtjitterbuffer.c' || echo '$(srcdir)/'`rdtjitterbuffer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-rdtjitterbuffer.Tpo $(DEPDIR)/libgstrmdemux_la-rdtjitterbuffer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rdtjitterbuffer.c' object='libgstrmdemux_la-rdtjitterbuffer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-rdtjitterbuffer.lo `test -f 'rdtjitterbuffer.c' || echo '$(srcdir)/'`rdtjitterbuffer.c
+
+libgstrmdemux_la-gstrdtbuffer.lo: gstrdtbuffer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-gstrdtbuffer.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-gstrdtbuffer.Tpo -c -o libgstrmdemux_la-gstrdtbuffer.lo `test -f 'gstrdtbuffer.c' || echo '$(srcdir)/'`gstrdtbuffer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-gstrdtbuffer.Tpo $(DEPDIR)/libgstrmdemux_la-gstrdtbuffer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrdtbuffer.c' object='libgstrmdemux_la-gstrdtbuffer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-gstrdtbuffer.lo `test -f 'gstrdtbuffer.c' || echo '$(srcdir)/'`gstrdtbuffer.c
+
+libgstrmdemux_la-pnmsrc.lo: pnmsrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-pnmsrc.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-pnmsrc.Tpo -c -o libgstrmdemux_la-pnmsrc.lo `test -f 'pnmsrc.c' || echo '$(srcdir)/'`pnmsrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-pnmsrc.Tpo $(DEPDIR)/libgstrmdemux_la-pnmsrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pnmsrc.c' object='libgstrmdemux_la-pnmsrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-pnmsrc.lo `test -f 'pnmsrc.c' || echo '$(srcdir)/'`pnmsrc.c
+
+libgstrmdemux_la-realmedia.lo: realmedia.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -MT libgstrmdemux_la-realmedia.lo -MD -MP -MF $(DEPDIR)/libgstrmdemux_la-realmedia.Tpo -c -o libgstrmdemux_la-realmedia.lo `test -f 'realmedia.c' || echo '$(srcdir)/'`realmedia.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrmdemux_la-realmedia.Tpo $(DEPDIR)/libgstrmdemux_la-realmedia.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='realmedia.c' object='libgstrmdemux_la-realmedia.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrmdemux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrmdemux_la_CFLAGS) $(CFLAGS) -c -o libgstrmdemux_la-realmedia.lo `test -f 'realmedia.c' || echo '$(srcdir)/'`realmedia.c
+
+asmrules-asmrules.o: asmrules.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(asmrules_CFLAGS) $(CFLAGS) -MT asmrules-asmrules.o -MD -MP -MF $(DEPDIR)/asmrules-asmrules.Tpo -c -o asmrules-asmrules.o `test -f 'asmrules.c' || echo '$(srcdir)/'`asmrules.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asmrules-asmrules.Tpo $(DEPDIR)/asmrules-asmrules.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asmrules.c' object='asmrules-asmrules.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(asmrules_CFLAGS) $(CFLAGS) -c -o asmrules-asmrules.o `test -f 'asmrules.c' || echo '$(srcdir)/'`asmrules.c
+
+asmrules-asmrules.obj: asmrules.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(asmrules_CFLAGS) $(CFLAGS) -MT asmrules-asmrules.obj -MD -MP -MF $(DEPDIR)/asmrules-asmrules.Tpo -c -o asmrules-asmrules.obj `if test -f 'asmrules.c'; then $(CYGPATH_W) 'asmrules.c'; else $(CYGPATH_W) '$(srcdir)/asmrules.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/asmrules-asmrules.Tpo $(DEPDIR)/asmrules-asmrules.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asmrules.c' object='asmrules-asmrules.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(asmrules_CFLAGS) $(CFLAGS) -c -o asmrules-asmrules.obj `if test -f 'asmrules.c'; then $(CYGPATH_W) 'asmrules.c'; else $(CYGPATH_W) '$(srcdir)/asmrules.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS clean-pluginLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pluginLTLIBRARIES install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pluginLTLIBRARIES
+
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstrmdemux -:SHARED libgstrmdemux \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstrmdemux_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstrmdemux_la_CFLAGS) \
+ -:LDFLAGS $(libgstrmdemux_la_LDFLAGS) \
+ $(libgstrmdemux_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/realmedia/asmrules.c b/gst/realmedia/asmrules.c
new file mode 100644
index 0000000..1d52568
--- /dev/null
+++ b/gst/realmedia/asmrules.c
@@ -0,0 +1,711 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "asmrules.h"
+
+#define MAX_RULE_LENGTH 2048
+
+/* define to enable some more debug */
+#undef DEBUG
+
+static GstASMNode *
+gst_asm_node_new (void)
+{
+ GstASMNode *node;
+
+ node = g_new0 (GstASMNode, 1);
+ node->type = GST_ASM_NODE_UNKNOWN;
+
+ return node;
+}
+
+static void
+gst_asm_node_free (GstASMNode * node)
+{
+ if (node->left)
+ gst_asm_node_free (node->left);
+ if (node->right)
+ gst_asm_node_free (node->right);
+ if (node->type == GST_ASM_NODE_VARIABLE && node->data.varname)
+ g_free (node->data.varname);
+ g_free (node);
+}
+
+static gfloat
+gst_asm_operator_eval (GstASMOp optype, gfloat left, gfloat right)
+{
+ gfloat result = 0.0;
+
+ switch (optype) {
+ case GST_ASM_OP_GREATER:
+ result = (gfloat) (left > right);
+ break;
+ case GST_ASM_OP_LESS:
+ result = (gfloat) (left < right);
+ break;
+ case GST_ASM_OP_GREATEREQUAL:
+ result = (gfloat) (left >= right);
+ break;
+ case GST_ASM_OP_LESSEQUAL:
+ result = (gfloat) (left <= right);
+ break;
+ case GST_ASM_OP_EQUAL:
+ result = (gfloat) (left == right);
+ break;
+ case GST_ASM_OP_NOTEQUAL:
+ result = (gfloat) (left != right);
+ break;
+ case GST_ASM_OP_AND:
+ result = (gfloat) (left && right);
+ break;
+ case GST_ASM_OP_OR:
+ result = (gfloat) (left || right);
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+static gfloat
+gst_asm_node_evaluate (GstASMNode * node, GHashTable * vars)
+{
+ gfloat result = 0.0;
+
+ if (node == NULL)
+ return 0.0;
+
+ switch (node->type) {
+ case GST_ASM_NODE_VARIABLE:
+ {
+ gchar *val;
+
+ val = g_hash_table_lookup (vars, node->data.varname);
+ if (val)
+ result = (gfloat) atof (val);
+ break;
+ }
+ case GST_ASM_NODE_INTEGER:
+ result = (gfloat) node->data.intval;
+ break;
+ case GST_ASM_NODE_FLOAT:
+ result = node->data.floatval;
+ break;
+ case GST_ASM_NODE_OPERATOR:
+ {
+ gfloat left, right;
+
+ left = gst_asm_node_evaluate (node->left, vars);
+ right = gst_asm_node_evaluate (node->right, vars);
+
+ result = gst_asm_operator_eval (node->data.optype, left, right);
+ break;
+ }
+ default:
+ break;
+ }
+ return result;
+}
+
+#define IS_SPACE(p) (((p) == ' ') || ((p) == '\n') || \
+ ((p) == '\r') || ((p) == '\t'))
+#define IS_RULE_DELIM(p) (((p) == ',') || ((p) == ';') || ((p) == ')'))
+#define IS_OPERATOR(p) (((p) == '>') || ((p) == '<') || \
+ ((p) == '=') || ((p) == '!') || \
+ ((p) == '&') || ((p) == '|'))
+#define IS_NUMBER(p) ((((p) >= '0') && ((p) <= '9')) || ((p) == '.'))
+#define IS_CHAR(p) (!IS_OPERATOR(ch) && !IS_RULE_DELIM(ch) && (ch != '\0'))
+
+#define IS_OP_TOKEN(t) (((t) == GST_ASM_TOKEN_AND) || ((t) == GST_ASM_TOKEN_OR))
+#define IS_COND_TOKEN(t) (((t) == GST_ASM_TOKEN_LESS) || ((t) == GST_ASM_TOKEN_LESSEQUAL) || \
+ ((t) == GST_ASM_TOKEN_GREATER) || ((t) == GST_ASM_TOKEN_GREATEREQUAL) || \
+ ((t) == GST_ASM_TOKEN_EQUAL) || ((t) == GST_ASM_TOKEN_NOTEQUAL))
+
+typedef struct
+{
+ const gchar *buffer;
+ gint pos;
+ gchar ch;
+
+ GstASMToken token;
+ gchar val[MAX_RULE_LENGTH];
+} GstASMScan;
+
+#define NEXT_CHAR(scan) ((scan)->ch = (scan)->buffer[(scan)->pos++])
+#define THIS_CHAR(scan) ((scan)->ch)
+
+static GstASMScan *
+gst_asm_scan_new (const gchar * buffer)
+{
+ GstASMScan *scan;
+
+ scan = g_new0 (GstASMScan, 1);
+ scan->buffer = buffer;
+ NEXT_CHAR (scan);
+
+ return scan;
+}
+
+static void
+gst_asm_scan_free (GstASMScan * scan)
+{
+ g_free (scan);
+}
+
+static void
+gst_asm_scan_string (GstASMScan * scan, gchar delim)
+{
+ gchar ch;
+ gint i = 0;
+
+ ch = THIS_CHAR (scan);
+ while ((ch != delim) && (ch != '\0')) {
+ if (i < MAX_RULE_LENGTH - 1)
+ scan->val[i++] = ch;
+ ch = NEXT_CHAR (scan);
+ if (ch == '\\')
+ ch = NEXT_CHAR (scan);
+ }
+ scan->val[i] = '\0';
+
+ if (ch == delim)
+ NEXT_CHAR (scan);
+
+ scan->token = GST_ASM_TOKEN_STRING;
+}
+
+static void
+gst_asm_scan_number (GstASMScan * scan)
+{
+ gchar ch;
+ gint i = 0;
+ gboolean have_float = FALSE;
+
+ ch = THIS_CHAR (scan);
+ /* real strips all spaces that are not inside quotes for numbers */
+ while ((IS_NUMBER (ch) || IS_SPACE (ch))) {
+ if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch))
+ scan->val[i++] = ch;
+ if (ch == '.')
+ have_float = TRUE;
+ ch = NEXT_CHAR (scan);
+ }
+ scan->val[i] = '\0';
+
+ if (have_float)
+ scan->token = GST_ASM_TOKEN_FLOAT;
+ else
+ scan->token = GST_ASM_TOKEN_INT;
+}
+
+static void
+gst_asm_scan_identifier (GstASMScan * scan)
+{
+ gchar ch;
+ gint i = 0;
+
+ ch = THIS_CHAR (scan);
+ /* real strips all spaces that are not inside quotes for identifiers */
+ while ((IS_CHAR (ch) || IS_SPACE (ch))) {
+ if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch))
+ scan->val[i++] = ch;
+ ch = NEXT_CHAR (scan);
+ }
+ scan->val[i] = '\0';
+
+ scan->token = GST_ASM_TOKEN_IDENTIFIER;
+}
+
+static void
+gst_asm_scan_print_token (GstASMScan * scan)
+{
+#ifdef DEBUG
+ switch (scan->token) {
+ case GST_ASM_TOKEN_NONE:
+ g_print ("none\n");
+ break;
+ case GST_ASM_TOKEN_EOF:
+ g_print ("EOF\n");
+ break;
+
+ case GST_ASM_TOKEN_INT:
+ g_print ("INT %d\n", atoi (scan->val));
+ break;
+ case GST_ASM_TOKEN_FLOAT:
+ g_print ("FLOAT %f\n", atof (scan->val));
+ break;
+ case GST_ASM_TOKEN_IDENTIFIER:
+ g_print ("ID %s\n", scan->val);
+ break;
+ case GST_ASM_TOKEN_STRING:
+ g_print ("STRING %s\n", scan->val);
+ break;
+
+ case GST_ASM_TOKEN_HASH:
+ g_print ("HASH\n");
+ break;
+ case GST_ASM_TOKEN_SEMICOLON:
+ g_print ("SEMICOLON\n");
+ break;
+ case GST_ASM_TOKEN_COMMA:
+ g_print ("COMMA\n");
+ break;
+ case GST_ASM_TOKEN_EQUAL:
+ g_print ("==\n");
+ break;
+ case GST_ASM_TOKEN_NOTEQUAL:
+ g_print ("!=\n");
+ break;
+ case GST_ASM_TOKEN_AND:
+ g_print ("&&\n");
+ break;
+ case GST_ASM_TOKEN_OR:
+ g_print ("||\n");
+ break;
+ case GST_ASM_TOKEN_LESS:
+ g_print ("<\n");
+ break;
+ case GST_ASM_TOKEN_LESSEQUAL:
+ g_print ("<=\n");
+ break;
+ case GST_ASM_TOKEN_GREATER:
+ g_print (">\n");
+ break;
+ case GST_ASM_TOKEN_GREATEREQUAL:
+ g_print (">=\n");
+ break;
+ case GST_ASM_TOKEN_DOLLAR:
+ g_print ("$\n");
+ break;
+ case GST_ASM_TOKEN_LPAREN:
+ g_print ("(\n");
+ break;
+ case GST_ASM_TOKEN_RPAREN:
+ g_print (")\n");
+ break;
+ default:
+ break;
+ }
+#endif
+}
+
+static GstASMToken
+gst_asm_scan_next_token (GstASMScan * scan)
+{
+ gchar ch;
+
+ ch = THIS_CHAR (scan);
+
+ /* skip spaces */
+ while (IS_SPACE (ch))
+ ch = NEXT_CHAR (scan);
+
+ /* remove \ which is common in front of " */
+ while (ch == '\\')
+ ch = NEXT_CHAR (scan);
+
+ switch (ch) {
+ case '#':
+ scan->token = GST_ASM_TOKEN_HASH;
+ NEXT_CHAR (scan);
+ break;
+ case ';':
+ scan->token = GST_ASM_TOKEN_SEMICOLON;
+ NEXT_CHAR (scan);
+ break;
+ case ',':
+ scan->token = GST_ASM_TOKEN_COMMA;
+ NEXT_CHAR (scan);
+ break;
+ case '=':
+ scan->token = GST_ASM_TOKEN_EQUAL;
+ if (NEXT_CHAR (scan) == '=')
+ NEXT_CHAR (scan);
+ break;
+ case '!':
+ if (NEXT_CHAR (scan) == '=') {
+ scan->token = GST_ASM_TOKEN_NOTEQUAL;
+ NEXT_CHAR (scan);
+ }
+ break;
+ case '&':
+ scan->token = GST_ASM_TOKEN_AND;
+ if (NEXT_CHAR (scan) == '&')
+ NEXT_CHAR (scan);
+ break;
+ case '|':
+ scan->token = GST_ASM_TOKEN_OR;
+ if (NEXT_CHAR (scan) == '|')
+ NEXT_CHAR (scan);
+ break;
+ case '<':
+ scan->token = GST_ASM_TOKEN_LESS;
+ if (NEXT_CHAR (scan) == '=') {
+ scan->token = GST_ASM_TOKEN_LESSEQUAL;
+ NEXT_CHAR (scan);
+ }
+ break;
+ case '>':
+ scan->token = GST_ASM_TOKEN_GREATER;
+ if (NEXT_CHAR (scan) == '=') {
+ scan->token = GST_ASM_TOKEN_GREATEREQUAL;
+ NEXT_CHAR (scan);
+ }
+ break;
+ case '$':
+ scan->token = GST_ASM_TOKEN_DOLLAR;
+ NEXT_CHAR (scan);
+ break;
+ case '(':
+ scan->token = GST_ASM_TOKEN_LPAREN;
+ NEXT_CHAR (scan);
+ break;
+ case ')':
+ scan->token = GST_ASM_TOKEN_RPAREN;
+ NEXT_CHAR (scan);
+ break;
+ case '"':
+ NEXT_CHAR (scan);
+ gst_asm_scan_string (scan, '"');
+ break;
+ case '\'':
+ NEXT_CHAR (scan);
+ gst_asm_scan_string (scan, '\'');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ gst_asm_scan_number (scan);
+ break;
+ case '\0':
+ scan->token = GST_ASM_TOKEN_EOF;
+ break;
+ default:
+ gst_asm_scan_identifier (scan);
+ break;
+ }
+ gst_asm_scan_print_token (scan);
+ return scan->token;
+}
+
+static GstASMRule *
+gst_asm_rule_new (void)
+{
+ GstASMRule *rule;
+
+ rule = g_new (GstASMRule, 1);
+ rule->root = NULL;
+ rule->props = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ return rule;
+}
+
+static void
+gst_asm_rule_free (GstASMRule * rule)
+{
+ g_hash_table_destroy (rule->props);
+ if (rule->root)
+ gst_asm_node_free (rule->root);
+ g_free (rule);
+}
+
+static void
+gst_asm_rule_add_property (GstASMRule * rule, gchar * key, gchar * val)
+{
+ g_hash_table_insert (rule->props, key, val);
+}
+
+static GstASMNode *gst_asm_scan_parse_condition (GstASMScan * scan);
+
+static GstASMNode *
+gst_asm_scan_parse_operand (GstASMScan * scan)
+{
+ GstASMNode *node;
+
+ switch (scan->token) {
+ case GST_ASM_TOKEN_DOLLAR:
+ gst_asm_scan_next_token (scan);
+
+ if (scan->token != GST_ASM_TOKEN_IDENTIFIER)
+ g_warning ("identifier expected");
+
+ node = gst_asm_node_new ();
+ node->type = GST_ASM_NODE_VARIABLE;
+ node->data.varname = g_strdup (scan->val);
+ break;
+ case GST_ASM_TOKEN_INT:
+ node = gst_asm_node_new ();
+ node->type = GST_ASM_NODE_INTEGER;
+ node->data.intval = (gfloat) atof (scan->val);
+ break;
+ case GST_ASM_TOKEN_FLOAT:
+ node = gst_asm_node_new ();
+ node->type = GST_ASM_NODE_FLOAT;
+ node->data.floatval = atoi (scan->val);
+ break;
+ case GST_ASM_TOKEN_LPAREN:
+ gst_asm_scan_next_token (scan);
+ node = gst_asm_scan_parse_condition (scan);
+ if (scan->token != GST_ASM_TOKEN_RPAREN)
+ g_warning (") expected");
+ break;
+ default:
+ g_warning ("$ <number> or ) expected");
+ node = NULL;
+ break;
+ }
+ gst_asm_scan_next_token (scan);
+
+ return node;
+}
+
+static GstASMNode *
+gst_asm_scan_parse_expression (GstASMScan * scan)
+{
+ GstASMNode *node, *left;
+
+ node = gst_asm_scan_parse_operand (scan);
+
+ while (IS_COND_TOKEN (scan->token)) {
+ left = node;
+
+ node = gst_asm_node_new ();
+ node->type = GST_ASM_NODE_OPERATOR;
+ node->data.optype = (GstASMOp) scan->token;
+
+ gst_asm_scan_next_token (scan);
+
+ node->right = gst_asm_scan_parse_operand (scan);
+ node->left = left;
+ }
+ return node;
+}
+
+static GstASMNode *
+gst_asm_scan_parse_condition (GstASMScan * scan)
+{
+ GstASMNode *node, *left;
+
+ node = gst_asm_scan_parse_expression (scan);
+
+ while (IS_OP_TOKEN (scan->token)) {
+ left = node;
+
+ node = gst_asm_node_new ();
+ node->type = GST_ASM_NODE_OPERATOR;
+ node->data.optype = (GstASMOp) scan->token;
+
+ gst_asm_scan_next_token (scan);
+
+ node->right = gst_asm_scan_parse_expression (scan);
+ node->left = left;
+ }
+ return node;
+}
+
+static void
+gst_asm_scan_parse_property (GstASMRule * rule, GstASMScan * scan)
+{
+ gchar *key, *val;
+
+ if (scan->token != GST_ASM_TOKEN_IDENTIFIER) {
+ g_warning ("identifier expected");
+ return;
+ }
+ key = g_strdup (scan->val);
+
+ gst_asm_scan_next_token (scan);
+ if (scan->token != GST_ASM_TOKEN_EQUAL) {
+ g_warning ("= expected");
+ return;
+ }
+ gst_asm_scan_next_token (scan);
+ val = g_strdup (scan->val);
+
+ gst_asm_rule_add_property (rule, key, val);
+ gst_asm_scan_next_token (scan);
+}
+
+static GstASMRule *
+gst_asm_scan_parse_rule (GstASMScan * scan)
+{
+ GstASMRule *rule;
+
+ rule = gst_asm_rule_new ();
+
+ if (scan->token == GST_ASM_TOKEN_HASH) {
+ gst_asm_scan_next_token (scan);
+ rule->root = gst_asm_scan_parse_condition (scan);
+ if (scan->token == GST_ASM_TOKEN_COMMA)
+ gst_asm_scan_next_token (scan);
+ }
+
+ if (scan->token != GST_ASM_TOKEN_SEMICOLON) {
+ gst_asm_scan_parse_property (rule, scan);
+ while (scan->token == GST_ASM_TOKEN_COMMA) {
+ gst_asm_scan_next_token (scan);
+ gst_asm_scan_parse_property (rule, scan);
+ }
+ gst_asm_scan_next_token (scan);
+ }
+ return rule;
+}
+
+static gboolean
+gst_asm_rule_evaluate (GstASMRule * rule, GHashTable * vars)
+{
+ gboolean res;
+
+ if (rule->root) {
+ res = (gboolean) gst_asm_node_evaluate (rule->root, vars);
+ } else
+ res = TRUE;
+
+ return res;
+}
+
+GstASMRuleBook *
+gst_asm_rule_book_new (const gchar * rulebook)
+{
+ GstASMRuleBook *book;
+ GstASMRule *rule = NULL;
+ GstASMScan *scan;
+ GstASMToken token;
+
+ book = g_new0 (GstASMRuleBook, 1);
+ book->rulebook = rulebook;
+
+ scan = gst_asm_scan_new (book->rulebook);
+ gst_asm_scan_next_token (scan);
+
+ do {
+ rule = gst_asm_scan_parse_rule (scan);
+ if (rule) {
+ book->rules = g_list_append (book->rules, rule);
+ book->n_rules++;
+ }
+ token = scan->token;
+ } while (token != GST_ASM_TOKEN_EOF);
+
+ gst_asm_scan_free (scan);
+
+ return book;
+}
+
+void
+gst_asm_rule_book_free (GstASMRuleBook * book)
+{
+ GList *walk;
+
+ for (walk = book->rules; walk; walk = g_list_next (walk)) {
+ GstASMRule *rule = (GstASMRule *) walk->data;
+
+ gst_asm_rule_free (rule);
+ }
+ g_list_free (book->rules);
+ g_free (book);
+}
+
+gint
+gst_asm_rule_book_match (GstASMRuleBook * book, GHashTable * vars,
+ gint * rulematches)
+{
+ GList *walk;
+ gint i, n = 0;
+
+ for (walk = book->rules, i = 0; walk; walk = g_list_next (walk), i++) {
+ GstASMRule *rule = (GstASMRule *) walk->data;
+
+ if (gst_asm_rule_evaluate (rule, vars)) {
+ rulematches[n++] = i;
+ }
+ }
+ return n;
+}
+
+#ifdef TEST
+gint
+main (gint argc, gchar * argv[])
+{
+ GstASMRuleBook *book;
+ gint rulematch[MAX_RULEMATCHES];
+ GHashTable *vars;
+ gint i, n;
+
+ static const gchar rules1[] =
+ "#($Bandwidth < 67959),TimestampDelivery=T,DropByN=T,"
+ "priority=9;#($Bandwidth >= 67959) && ($Bandwidth < 167959),"
+ "AverageBandwidth=67959,Priority=9;#($Bandwidth >= 67959) && ($Bandwidth"
+ " < 167959),AverageBandwidth=0,Priority=5,OnDepend=\\\"1\\\";#($Bandwidth >= 167959)"
+ " && ($Bandwidth < 267959),AverageBandwidth=167959,Priority=9;#($Bandwidth >= 167959)"
+ " && ($Bandwidth < 267959),AverageBandwidth=0,Priority=5,OnDepend=\\\"3\\\";"
+ "#($Bandwidth >= 267959),AverageBandwidth=267959,Priority=9;#($Bandwidth >= 267959)"
+ ",AverageBandwidth=0,Priority=5,OnDepend=\\\"5\\\";";
+ static const gchar rules2[] =
+ "AverageBandwidth=32041,Priority=5;AverageBandwidth=0,"
+ "Priority=5,OnDepend=\\\"0\\\", OffDepend=\\\"0\\\";";
+ static const gchar rules3[] =
+ "#(($Bandwidth >= 27500) && ($OldPNMPlayer)),AverageBandwidth=27500,priority=9,PNMKeyframeRule=T;#(($Bandwidth >= 27500) && ($OldPNMPlayer)),AverageBandwidth=0,priority=5,PNMNonKeyframeRule=T;#(($Bandwidth < 27500) && ($OldPNMPlayer)),TimestampDelivery=T,DropByN=T,priority=9,PNMThinningRule=T;#($Bandwidth < 13899),TimestampDelivery=T,DropByN=T,priority=9;#($Bandwidth >= 13899) && ($Bandwidth < 19000),AverageBandwidth=13899,Priority=9;#($Bandwidth >= 13899) && ($Bandwidth < 19000),AverageBandwidth=0,Priority=5,OnDepend=\\\"4\\\";#($Bandwidth >= 19000) && ($Bandwidth < 27500),AverageBandwidth=19000,Priority=9;#($Bandwidth >= 19000) && ($Bandwidth < 27500),AverageBandwidth=0,Priority=5,OnDepend=\\\"6\\\";#($Bandwidth >= 27500) && ($Bandwidth < 132958),AverageBandwidth=27500,Priority=9;#($Bandwidth >= 27500) && ($Bandwidth < 132958),AverageBandwidth=0,Priority=5,OnDepend=\\\"8\\\";#($Bandwidth >= 132958) && ($Bandwidth < 187958),AverageBandwidth=132958,Priority=9;#($Bandwidth >= 132958) && ($Bandwidth < 187958),AverageBandwidth=0,Priority=5,OnDepend=\\\"10\\\";#($Bandwidth >= 187958),AverageBandwidth=187958,Priority=9;#($Bandwidth >= 187958),AverageBandwidth=0,Priority=5,OnDepend=\\\"12\\\";";
+
+ vars = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (vars, (gchar *) "Bandwidth", (gchar *) "300000");
+
+ book = gst_asm_rule_book_new (rules1);
+ n = gst_asm_rule_book_match (book, vars, rulematch);
+ gst_asm_rule_book_free (book);
+
+ g_print ("%d rules matched\n", n);
+ for (i = 0; i < n; i++) {
+ g_print ("rule %d matched\n", rulematch[i]);
+ }
+
+ book = gst_asm_rule_book_new (rules2);
+ n = gst_asm_rule_book_match (book, vars, rulematch);
+ gst_asm_rule_book_free (book);
+
+ g_print ("%d rules matched\n", n);
+ for (i = 0; i < n; i++) {
+ g_print ("rule %d matched\n", rulematch[i]);
+ }
+
+ book = gst_asm_rule_book_new (rules3);
+ n = gst_asm_rule_book_match (book, vars, rulematch);
+ gst_asm_rule_book_free (book);
+
+
+ g_print ("%d rules matched\n", n);
+ for (i = 0; i < n; i++) {
+ g_print ("rule %d matched\n", rulematch[i]);
+ }
+
+ g_hash_table_destroy (vars);
+
+ return 0;
+}
+#endif
diff --git a/gst/realmedia/asmrules.h b/gst/realmedia/asmrules.h
new file mode 100644
index 0000000..1f84f68
--- /dev/null
+++ b/gst/realmedia/asmrules.h
@@ -0,0 +1,115 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ASM_RULES_H__
+#define __GST_ASM_RULES_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define MAX_RULEMATCHES 16
+
+typedef struct _GstASMNode GstASMNode;
+typedef struct _GstASMRule GstASMRule;
+typedef struct _GstASMRuleBook GstASMRuleBook;
+
+typedef enum {
+ GST_ASM_TOKEN_NONE,
+ GST_ASM_TOKEN_EOF,
+
+ GST_ASM_TOKEN_INT,
+ GST_ASM_TOKEN_FLOAT,
+ GST_ASM_TOKEN_IDENTIFIER,
+ GST_ASM_TOKEN_STRING,
+
+ GST_ASM_TOKEN_HASH,
+ GST_ASM_TOKEN_SEMICOLON,
+ GST_ASM_TOKEN_COMMA,
+ GST_ASM_TOKEN_DOLLAR,
+
+ GST_ASM_TOKEN_LPAREN,
+ GST_ASM_TOKEN_RPAREN,
+
+ GST_ASM_TOKEN_GREATER,
+ GST_ASM_TOKEN_LESS,
+ GST_ASM_TOKEN_GREATEREQUAL,
+ GST_ASM_TOKEN_LESSEQUAL,
+ GST_ASM_TOKEN_EQUAL,
+ GST_ASM_TOKEN_NOTEQUAL,
+
+ GST_ASM_TOKEN_AND,
+ GST_ASM_TOKEN_OR
+} GstASMToken;
+
+typedef enum {
+ GST_ASM_NODE_UNKNOWN,
+ GST_ASM_NODE_VARIABLE,
+ GST_ASM_NODE_INTEGER,
+ GST_ASM_NODE_FLOAT,
+ GST_ASM_NODE_OPERATOR
+} GstASMNodeType;
+
+typedef enum {
+ GST_ASM_OP_GREATER = GST_ASM_TOKEN_GREATER,
+ GST_ASM_OP_LESS = GST_ASM_TOKEN_LESS,
+ GST_ASM_OP_GREATEREQUAL = GST_ASM_TOKEN_GREATEREQUAL,
+ GST_ASM_OP_LESSEQUAL = GST_ASM_TOKEN_LESSEQUAL,
+ GST_ASM_OP_EQUAL = GST_ASM_TOKEN_EQUAL,
+ GST_ASM_OP_NOTEQUAL = GST_ASM_TOKEN_NOTEQUAL,
+
+ GST_ASM_OP_AND = GST_ASM_TOKEN_AND,
+ GST_ASM_OP_OR = GST_ASM_TOKEN_OR
+} GstASMOp;
+
+struct _GstASMNode {
+ GstASMNodeType type;
+
+ union {
+ gchar *varname;
+ gint intval;
+ gfloat floatval;
+ GstASMOp optype;
+ } data;
+
+ GstASMNode *left;
+ GstASMNode *right;
+};
+
+struct _GstASMRule {
+ GstASMNode *root;
+ GHashTable *props;
+};
+
+struct _GstASMRuleBook {
+ const gchar *rulebook;
+
+ guint n_rules;
+ GList *rules;
+};
+
+G_END_DECLS
+
+GstASMRuleBook* gst_asm_rule_book_new (const gchar *rulebook);
+void gst_asm_rule_book_free (GstASMRuleBook *book);
+
+gint gst_asm_rule_book_match (GstASMRuleBook *book, GHashTable *vars,
+ gint *rulematches);
+
+#endif /* __GST_ASM_RULES_H__ */
diff --git a/gst/realmedia/gstrdtbuffer.c b/gst/realmedia/gstrdtbuffer.c
new file mode 100644
index 0000000..50bc7f4
--- /dev/null
+++ b/gst/realmedia/gstrdtbuffer.c
@@ -0,0 +1,477 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <string.h>
+
+#include "gstrdtbuffer.h"
+
+gboolean
+gst_rdt_buffer_validate_data (guint8 * data, guint len)
+{
+ return TRUE;
+}
+
+gboolean
+gst_rdt_buffer_validate (GstBuffer * buffer)
+{
+ return TRUE;
+}
+
+guint
+gst_rdt_buffer_get_packet_count (GstBuffer * buffer)
+{
+ GstRDTPacket packet;
+ guint count;
+
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
+
+ count = 0;
+ if (gst_rdt_buffer_get_first_packet (buffer, &packet)) {
+ do {
+ count++;
+ } while (gst_rdt_packet_move_to_next (&packet));
+ }
+ return count;
+}
+
+static gboolean
+read_packet_header (GstRDTPacket * packet)
+{
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ guint offset;
+ guint length;
+ guint length_offset;
+
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
+
+ gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ offset = packet->offset;
+
+ /* check if we are at the end of the buffer, we add 3 because we also want to
+ * ensure we can read the type, which is always at offset 1 and 2 bytes long. */
+ if (offset + 3 > size)
+ goto packet_end;
+
+ /* read type */
+ packet->type = GST_READ_UINT16_BE (&data[offset + 1]);
+
+ length = -1;
+ length_offset = -1;
+
+ /* figure out the length of the packet, this depends on the type */
+ if (GST_RDT_IS_DATA_TYPE (packet->type)) {
+ if (data[offset] & 0x80)
+ /* length is present */
+ length_offset = 3;
+ } else {
+ switch (packet->type) {
+ case GST_RDT_TYPE_ASMACTION:
+ if (data[offset] & 0x80)
+ length_offset = 5;
+ break;
+ case GST_RDT_TYPE_BWREPORT:
+ if (data[offset] & 0x80)
+ length_offset = 3;
+ break;
+ case GST_RDT_TYPE_ACK:
+ if (data[offset] & 0x80)
+ length_offset = 3;
+ break;
+ case GST_RDT_TYPE_RTTREQ:
+ length = 3;
+ break;
+ case GST_RDT_TYPE_RTTRESP:
+ length = 11;
+ break;
+ case GST_RDT_TYPE_CONGESTION:
+ length = 11;
+ break;
+ case GST_RDT_TYPE_STREAMEND:
+ length = 9;
+ /* total_reliable */
+ if (data[offset] & 0x80)
+ length += 2;
+ /* stream_id_expansion */
+ if ((data[offset] & 0x7c) == 0x7c)
+ length += 2;
+ /* ext_flag, FIXME, get string length */
+ if ((data[offset] & 0x1) == 0x1)
+ length += 7;
+ break;
+ case GST_RDT_TYPE_REPORT:
+ if (data[offset] & 0x80)
+ length_offset = 3;
+ break;
+ case GST_RDT_TYPE_LATENCY:
+ if (data[offset] & 0x80)
+ length_offset = 3;
+ break;
+ case GST_RDT_TYPE_INFOREQ:
+ length = 3;
+ /* request_time_ms */
+ if (data[offset] & 0x2)
+ length += 2;
+ break;
+ case GST_RDT_TYPE_INFORESP:
+ length = 3;
+ /* has_rtt_info */
+ if (data[offset] & 0x4) {
+ length += 4;
+ /* is_delayed */
+ if (data[offset] & 0x2) {
+ length += 4;
+ }
+ }
+ if (data[offset] & 0x1) {
+ /* buffer_info_count, FIXME read and skip */
+ length += 2;
+ }
+ break;
+ case GST_RDT_TYPE_AUTOBW:
+ if (data[offset] & 0x80)
+ length_offset = 3;
+ break;
+ case GST_RDT_TYPE_INVALID:
+ default:
+ goto unknown_packet;
+ }
+ }
+
+ if (length != -1) {
+ /* we have a fixed length */
+ packet->length = length;
+ } else if (length_offset != -1) {
+ /* we can read the length from an offset */
+ packet->length = GST_READ_UINT16_BE (&data[length_offset]);
+ } else {
+ /* length is remainder of packet */
+ packet->length = size - offset;
+ }
+ gst_buffer_unmap (packet->buffer, &map);
+
+ /* the length should be smaller than the remaining size */
+ if (packet->length + offset > size)
+ goto invalid_length;
+
+ return TRUE;
+
+ /* ERRORS */
+packet_end:
+ {
+ gst_buffer_unmap (packet->buffer, &map);
+ return FALSE;
+ }
+unknown_packet:
+ {
+ packet->type = GST_RDT_TYPE_INVALID;
+ gst_buffer_unmap (packet->buffer, &map);
+ return FALSE;
+ }
+invalid_length:
+ {
+ packet->type = GST_RDT_TYPE_INVALID;
+ packet->length = 0;
+ return FALSE;
+ }
+}
+
+gboolean
+gst_rdt_buffer_get_first_packet (GstBuffer * buffer, GstRDTPacket * packet)
+{
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (packet != NULL, FALSE);
+
+ /* init to 0 */
+ packet->buffer = buffer;
+ packet->offset = 0;
+ packet->type = GST_RDT_TYPE_INVALID;
+ memset (&packet->map, 0, sizeof (GstMapInfo));
+
+ if (!read_packet_header (packet))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+gst_rdt_packet_move_to_next (GstRDTPacket * packet)
+{
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
+
+ /* if we have an invalid packet, it must be the last,
+ * return FALSE */
+ if (packet->type == GST_RDT_TYPE_INVALID)
+ goto end;
+
+ /* move to next packet */
+ packet->offset += packet->length;
+
+ /* try to read new header */
+ if (!read_packet_header (packet))
+ goto end;
+
+ return TRUE;
+
+ /* ERRORS */
+end:
+ {
+ packet->type = GST_RDT_TYPE_INVALID;
+ return FALSE;
+ }
+}
+
+GstRDTType
+gst_rdt_packet_get_type (GstRDTPacket * packet)
+{
+ g_return_val_if_fail (packet != NULL, GST_RDT_TYPE_INVALID);
+ g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID,
+ GST_RDT_TYPE_INVALID);
+
+ return packet->type;
+}
+
+guint16
+gst_rdt_packet_get_length (GstRDTPacket * packet)
+{
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, 0);
+
+ return packet->length;
+}
+
+GstBuffer *
+gst_rdt_packet_to_buffer (GstRDTPacket * packet)
+{
+ GstBuffer *result;
+
+ g_return_val_if_fail (packet != NULL, NULL);
+ g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, NULL);
+
+ result =
+ gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
+ packet->offset, packet->length);
+ /* timestamp applies to all packets in this buffer */
+ GST_BUFFER_TIMESTAMP (result) = GST_BUFFER_TIMESTAMP (packet->buffer);
+
+ return result;
+}
+
+gint
+gst_rdt_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
+{
+ return (gint16) (seqnum2 - seqnum1);
+}
+
+guint16
+gst_rdt_packet_data_get_seq (GstRDTPacket * packet)
+{
+ GstMapInfo map;
+ guint header;
+ guint16 result;
+
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), FALSE);
+
+ gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
+
+ /* skip header bits */
+ header = packet->offset + 1;
+
+ /* read seq_no */
+ result = GST_READ_UINT16_BE (&map.data[header]);
+
+ gst_buffer_unmap (packet->buffer, &map);
+
+ return result;
+}
+
+guint8 *
+gst_rdt_packet_data_map (GstRDTPacket * packet, guint * size)
+{
+ GstMapInfo map;
+ guint header;
+ gboolean length_included_flag;
+ gboolean need_reliable_flag;
+ guint8 stream_id;
+ guint8 asm_rule_number;
+
+ g_return_val_if_fail (packet != NULL, NULL);
+ g_return_val_if_fail (packet->map.data == NULL, NULL);
+ g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), NULL);
+
+ gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
+
+ header = packet->offset;
+
+ length_included_flag = (map.data[header] & 0x80) == 0x80;
+ need_reliable_flag = (map.data[header] & 0x40) == 0x40;
+ stream_id = (map.data[header] & 0x3e) >> 1;
+
+ /* skip seq_no and header bits */
+ header += 3;
+
+ if (length_included_flag) {
+ /* skip length */
+ header += 2;
+ }
+ asm_rule_number = (map.data[header] & 0x3f);
+
+ /* skip timestamp and asm_rule_number */
+ header += 5;
+
+ if (stream_id == 0x1f) {
+ /* skip stream_id_expansion */
+ header += 2;
+ }
+ if (need_reliable_flag) {
+ /* skip total_reliable */
+ header += 2;
+ }
+ if (asm_rule_number == 63) {
+ /* skip asm_rule_number_expansion */
+ header += 2;
+ }
+
+ if (size)
+ *size = packet->length - (header - packet->offset);
+
+ packet->map = map;
+
+ return &map.data[header];
+}
+
+gboolean
+gst_rdt_packet_data_unmap (GstRDTPacket * packet)
+{
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (packet->map.data != NULL, FALSE);
+
+ gst_buffer_unmap (packet->buffer, &packet->map);
+ packet->map.data = NULL;
+
+ return TRUE;
+}
+
+guint16
+gst_rdt_packet_data_get_stream_id (GstRDTPacket * packet)
+{
+ GstMapInfo map;
+ guint16 result;
+ guint header;
+ gboolean length_included_flag;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
+
+ gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
+
+ header = packet->offset;
+
+ length_included_flag = (map.data[header] & 0x80) == 0x80;
+ result = (map.data[header] & 0x3e) >> 1;
+ if (result == 31) {
+ /* skip seq_no and header bits */
+ header += 3;
+
+ if (length_included_flag) {
+ /* skip length */
+ header += 2;
+ }
+ /* skip asm_rule_number and timestamp */
+ header += 5;
+
+ /* stream_id_expansion */
+ result = GST_READ_UINT16_BE (&map.data[header]);
+ }
+ gst_buffer_unmap (packet->buffer, &map);
+
+ return result;
+}
+
+guint32
+gst_rdt_packet_data_get_timestamp (GstRDTPacket * packet)
+{
+ GstMapInfo map;
+ guint header;
+ gboolean length_included_flag;
+ guint32 result;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
+
+ gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
+
+ header = packet->offset;
+
+ length_included_flag = (map.data[header] & 0x80) == 0x80;
+
+ /* skip seq_no and header bits */
+ header += 3;
+
+ if (length_included_flag) {
+ /* skip length */
+ header += 2;
+ }
+ /* skip asm_rule_number */
+ header += 1;
+
+ /* get timestamp */
+ result = GST_READ_UINT32_BE (&map.data[header]);
+ gst_buffer_unmap (packet->buffer, &map);
+
+ return result;
+}
+
+guint8
+gst_rdt_packet_data_get_flags (GstRDTPacket * packet)
+{
+ GstMapInfo map;
+ guint8 result;
+ guint header;
+ gboolean length_included_flag;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
+
+ gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
+
+ header = packet->offset;
+
+ length_included_flag = (map.data[header] & 0x80) == 0x80;
+
+ /* skip seq_no and header bits */
+ header += 3;
+
+ if (length_included_flag) {
+ /* skip length */
+ header += 2;
+ }
+ /* get flags */
+ result = map.data[header];
+ gst_buffer_unmap (packet->buffer, &map);
+
+ return result;
+}
diff --git a/gst/realmedia/gstrdtbuffer.h b/gst/realmedia/gstrdtbuffer.h
new file mode 100644
index 0000000..1ff9c93
--- /dev/null
+++ b/gst/realmedia/gstrdtbuffer.h
@@ -0,0 +1,122 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * gstrdtbuffer.h: various helper functions to manipulate buffers
+ * with RDT payload.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RDTBUFFER_H__
+#define __GST_RDTBUFFER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstRDTType:
+ * @GST_RDT_TYPE_INVALID:
+ * @GST_RDT_TYPE_ASMACTION:
+ * @GST_RDT_TYPE_ACK:
+ * @GST_RDT_TYPE_RTTREQ:
+ * @GST_RDT_TYPE_RTTRESP:
+ * @GST_RDT_TYPE_CONGESTION:
+ * @GST_RDT_TYPE_STREAMEND:
+ * @GST_RDT_TYPE_LATENCY:
+ * @GST_RDT_TYPE_INFOREQ:
+ * @GST_RDT_TYPE_INFORESP:
+ * @GST_RDT_TYPE_AUTOBW:
+ *
+ * Different RDT packet types.
+ */
+typedef enum
+{
+ GST_RDT_TYPE_INVALID = 0xffff,
+ GST_RDT_TYPE_ASMACTION = 0xff00,
+ GST_RDT_TYPE_BWREPORT = 0xff01,
+ GST_RDT_TYPE_ACK = 0xff02,
+ GST_RDT_TYPE_RTTREQ = 0xff03,
+ GST_RDT_TYPE_RTTRESP = 0xff04,
+ GST_RDT_TYPE_CONGESTION = 0xff05,
+ GST_RDT_TYPE_STREAMEND = 0xff06,
+ GST_RDT_TYPE_REPORT = 0xff07,
+ GST_RDT_TYPE_LATENCY = 0xff08,
+ GST_RDT_TYPE_INFOREQ = 0xff09,
+ GST_RDT_TYPE_INFORESP = 0xff0a,
+ GST_RDT_TYPE_AUTOBW = 0xff0b
+} GstRDTType;
+
+/**
+ * GST_RDT_IS_DATA_TYPE:
+ * @t: the #GstRDTType to check
+ *
+ * Check if @t is a data packet type.
+ */
+#define GST_RDT_IS_DATA_TYPE(t) ((t) < 0xff00)
+
+typedef struct _GstRDTPacket GstRDTPacket;
+
+/**
+ * GstRDTPacket:
+ * @buffer: pointer to RDT buffer
+ * @offset: offset of packet in buffer data
+ *
+ * Data structure that points to a packet at @offset in @buffer.
+ * The size of the structure is made public to allow stack allocations.
+ */
+struct _GstRDTPacket
+{
+ GstBuffer *buffer;
+ guint offset;
+
+ /*< private >*/
+ GstRDTType type; /* type of current packet */
+ guint16 length; /* length of current packet in bytes */
+ GstMapInfo map; /* last mapped data */
+};
+
+/* validate buffers */
+gboolean gst_rdt_buffer_validate_data (guint8 *data, guint len);
+gboolean gst_rdt_buffer_validate (GstBuffer *buffer);
+
+/* retrieving packets */
+guint gst_rdt_buffer_get_packet_count (GstBuffer *buffer);
+gboolean gst_rdt_buffer_get_first_packet (GstBuffer *buffer, GstRDTPacket *packet);
+gboolean gst_rdt_packet_move_to_next (GstRDTPacket *packet);
+
+/* working with packets */
+GstRDTType gst_rdt_packet_get_type (GstRDTPacket *packet);
+guint16 gst_rdt_packet_get_length (GstRDTPacket *packet);
+GstBuffer* gst_rdt_packet_to_buffer (GstRDTPacket *packet);
+
+
+/* data packets */
+guint16 gst_rdt_packet_data_get_seq (GstRDTPacket *packet);
+guint8 * gst_rdt_packet_data_map (GstRDTPacket *packet, guint *size);
+gboolean gst_rdt_packet_data_unmap (GstRDTPacket *packet);
+guint16 gst_rdt_packet_data_get_stream_id (GstRDTPacket *packet);
+guint32 gst_rdt_packet_data_get_timestamp (GstRDTPacket *packet);
+
+guint8 gst_rdt_packet_data_get_flags (GstRDTPacket * packet);
+
+/* utils */
+gint gst_rdt_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2);
+
+G_END_DECLS
+
+#endif /* __GST_RDTBUFFER_H__ */
+
diff --git a/gst/realmedia/pnmsrc.c b/gst/realmedia/pnmsrc.c
new file mode 100644
index 0000000..241036c
--- /dev/null
+++ b/gst/realmedia/pnmsrc.c
@@ -0,0 +1,240 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "pnmsrc.h"
+
+GST_DEBUG_CATEGORY_STATIC (pnmsrc_debug);
+#define GST_CAT_DEFAULT pnmsrc_debug
+
+/* PNMSrc signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_LOCATION NULL
+
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_LAST
+};
+
+static GstStaticPadTemplate gst_pnm_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/vnd.rn-realmedia")
+ );
+
+static GstFlowReturn gst_pnm_src_create (GstPushSrc * psrc, GstBuffer ** buf);
+
+static void gst_pnm_src_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
+
+#define gst_pnm_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstPNMSrc, gst_pnm_src, GST_TYPE_PUSH_SRC,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_pnm_src_uri_handler_init));
+
+static void gst_pnm_src_finalize (GObject * object);
+
+static void gst_pnm_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pnm_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_pnm_src_class_init (GstPNMSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstPushSrcClass *gstpushsrc_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstpushsrc_class = (GstPushSrcClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gst_pnm_src_set_property;
+ gobject_class->get_property = gst_pnm_src_get_property;
+
+ gobject_class->finalize = gst_pnm_src_finalize;
+
+ g_object_class_install_property (gobject_class, PROP_LOCATION,
+ g_param_spec_string ("location", "PNM Location",
+ "Location of the PNM url to read",
+ DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_pnm_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "PNM packet receiver", "Source/Network",
+ "Receive data over the network via PNM",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstpushsrc_class->create = gst_pnm_src_create;
+
+ GST_DEBUG_CATEGORY_INIT (pnmsrc_debug, "pnmsrc",
+ 0, "Source for the pnm:// uri");
+}
+
+static void
+gst_pnm_src_init (GstPNMSrc * pnmsrc)
+{
+ pnmsrc->location = g_strdup (DEFAULT_LOCATION);
+}
+
+gboolean
+gst_pnm_src_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "pnmsrc",
+ GST_RANK_MARGINAL, GST_TYPE_PNM_SRC);
+}
+
+static void
+gst_pnm_src_finalize (GObject * object)
+{
+ GstPNMSrc *pnmsrc;
+
+ pnmsrc = GST_PNM_SRC (object);
+
+ g_free (pnmsrc->location);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_pnm_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstPNMSrc *src;
+
+ src = GST_PNM_SRC (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_free (src->location);
+ src->location = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pnm_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstPNMSrc *src;
+
+ src = GST_PNM_SRC (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_value_set_string (value, src->location);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstFlowReturn
+gst_pnm_src_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+ GstPNMSrc *src;
+ GstMessage *m;
+ gchar *url;
+
+ src = GST_PNM_SRC (psrc);
+
+ if (src->location == NULL)
+ return GST_FLOW_ERROR;
+ url = g_strdup_printf ("rtsp%s", &src->location[3]);
+
+ /* the only thing we do is redirect to an RTSP url */
+ m = gst_message_new_element (GST_OBJECT_CAST (src),
+ gst_structure_new ("redirect", "new-location", G_TYPE_STRING, url, NULL));
+ g_free (url);
+
+ gst_element_post_message (GST_ELEMENT_CAST (src), m);
+
+
+ return GST_FLOW_EOS;
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_pnm_src_uri_get_type (GType type)
+{
+ return GST_URI_SRC;
+}
+
+static const gchar *const *
+gst_pnm_src_uri_get_protocols (GType type)
+{
+ static const gchar *protocols[] = { "pnm", NULL };
+
+ return protocols;
+}
+
+static gchar *
+gst_pnm_src_uri_get_uri (GstURIHandler * handler)
+{
+ GstPNMSrc *src = GST_PNM_SRC (handler);
+
+ /* FIXME: make thread-safe */
+ return g_strdup (src->location);
+}
+
+static gboolean
+gst_pnm_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+ GError ** error)
+{
+ GstPNMSrc *src = GST_PNM_SRC (handler);
+
+ g_free (src->location);
+ src->location = g_strdup (uri);
+
+ return TRUE;
+}
+
+static void
+gst_pnm_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_pnm_src_uri_get_type;
+ iface->get_protocols = gst_pnm_src_uri_get_protocols;
+ iface->get_uri = gst_pnm_src_uri_get_uri;
+ iface->set_uri = gst_pnm_src_uri_set_uri;
+}
diff --git a/gst/realmedia/pnmsrc.h b/gst/realmedia/pnmsrc.h
new file mode 100644
index 0000000..fa343e7
--- /dev/null
+++ b/gst/realmedia/pnmsrc.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_PNM_SRC_H__
+#define __GST_PNM_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PNM_SRC \
+ (gst_pnm_src_get_type())
+#define GST_PNM_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNM_SRC,GstPNMSrc))
+#define GST_PNM_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNM_SRC,GstPNMSrcClass))
+#define GST_IS_PNM_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNM_SRC))
+#define GST_IS_PNM_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNM_SRC))
+
+typedef struct _GstPNMSrc GstPNMSrc;
+typedef struct _GstPNMSrcClass GstPNMSrcClass;
+
+struct _GstPNMSrc
+{
+ GstPushSrc parent;
+
+ gchar *location;
+};
+
+struct _GstPNMSrcClass
+{
+ GstPushSrcClass parent_class;
+};
+
+GType gst_pnm_src_get_type (void);
+gboolean gst_pnm_src_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_PNM_SRC_H__ */
diff --git a/gst/realmedia/rademux.c b/gst/realmedia/rademux.c
new file mode 100644
index 0000000..130f7a8
--- /dev/null
+++ b/gst/realmedia/rademux.c
@@ -0,0 +1,1007 @@
+/* GStreamer RealAudio demuxer
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rademux
+ *
+ * Demuxes/parses a RealAudio (.ra) file or stream into compressed audio.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=interview.ra ! rademux ! ffdec_real_288 ! audioconvert ! audioresample ! alsasink
+ * ]| Read a RealAudio file and decode it and output it to the soundcard using
+ * the ALSA element. The .ra file is assumed to contain RealAudio version 2.
+ * |[
+ * gst-launch gnomevfssrc location=http://www.example.org/interview.ra ! rademux ! a52dec ! audioconvert ! audioresample ! alsasink
+ * ]| Stream RealAudio data containing AC3 (dnet) compressed audio and decode it
+ * and output it to the soundcard using the ALSA element.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rademux.h"
+#include "rmdemux.h"
+#include "rmutils.h"
+
+#include <string.h>
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-pn-realaudio")
+ );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (real_audio_demux_debug);
+#define GST_CAT_DEFAULT real_audio_demux_debug
+
+#define gst_real_audio_demux_parent_class parent_class
+G_DEFINE_TYPE (GstRealAudioDemux, gst_real_audio_demux, GST_TYPE_ELEMENT);
+
+static GstStateChangeReturn gst_real_audio_demux_change_state (GstElement * e,
+ GstStateChange transition);
+static GstFlowReturn gst_real_audio_demux_chain (GstPad * pad,
+ GstObject * parent, GstBuffer * buf);
+static gboolean gst_real_audio_demux_sink_event (GstPad * pad,
+ GstObject * parent, GstEvent * ev);
+static gboolean gst_real_audio_demux_src_event (GstPad * pad,
+ GstObject * parent, GstEvent * ev);
+static gboolean gst_real_audio_demux_src_query (GstPad * pad,
+ GstObject * parent, GstQuery * query);
+static void gst_real_audio_demux_loop (GstRealAudioDemux * demux);
+static gboolean gst_real_audio_demux_sink_activate (GstPad * sinkpad,
+ GstObject * parent);
+static gboolean gst_real_audio_demux_sink_activate_mode (GstPad * sinkpad,
+ GstObject * parent, GstPadMode mode, gboolean active);
+
+static void
+gst_real_audio_demux_finalize (GObject * obj)
+{
+ GstRealAudioDemux *demux = GST_REAL_AUDIO_DEMUX (obj);
+
+ g_object_unref (demux->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_real_audio_demux_class_init (GstRealAudioDemuxClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_real_audio_demux_finalize;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RealAudio Demuxer",
+ "Codec/Demuxer",
+ "Demultiplex a RealAudio file",
+ "Tim-Philipp Müller <tim centricular net>");
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_change_state);
+
+ GST_DEBUG_CATEGORY_INIT (real_audio_demux_debug, "rademux",
+ 0, "Demuxer for RealAudio streams");
+}
+
+static void
+gst_real_audio_demux_reset (GstRealAudioDemux * demux)
+{
+ gst_adapter_clear (demux->adapter);
+
+ if (demux->srcpad) {
+ GST_DEBUG_OBJECT (demux, "Removing source pad");
+ gst_element_remove_pad (GST_ELEMENT (demux), demux->srcpad);
+ demux->srcpad = NULL;
+ }
+
+ if (demux->pending_tags) {
+ gst_tag_list_unref (demux->pending_tags);
+ demux->pending_tags = NULL;
+ }
+
+ demux->state = REAL_AUDIO_DEMUX_STATE_MARKER;
+ demux->ra_version = 0;
+ demux->data_offset = 0;
+ demux->packet_size = 0;
+
+ demux->sample_rate = 0;
+ demux->sample_width = 0;
+ demux->channels = 0;
+ demux->fourcc = 0;
+
+ demux->need_newsegment = TRUE;
+
+ demux->segment_running = FALSE;
+
+ demux->byterate_num = 0;
+ demux->byterate_denom = 0;
+
+ demux->duration = 0;
+ demux->upstream_size = 0;
+
+ demux->offset = 0;
+
+ demux->have_group_id = FALSE;
+ demux->group_id = G_MAXUINT;
+
+ gst_adapter_clear (demux->adapter);
+}
+
+static void
+gst_real_audio_demux_init (GstRealAudioDemux * demux)
+{
+ demux->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
+
+ gst_pad_set_chain_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_chain));
+ gst_pad_set_event_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_sink_event));
+ gst_pad_set_activate_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_sink_activate));
+ gst_pad_set_activatemode_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_sink_activate_mode));
+
+ gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
+
+ demux->adapter = gst_adapter_new ();
+ gst_real_audio_demux_reset (demux);
+}
+
+static gboolean
+gst_real_audio_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+ GstQuery *query;
+ gboolean pull_mode;
+
+ query = gst_query_new_scheduling ();
+
+ if (!gst_pad_peer_query (sinkpad, query)) {
+ gst_query_unref (query);
+ goto activate_push;
+ }
+
+ pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+ GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+ gst_query_unref (query);
+
+ if (!pull_mode)
+ goto activate_push;
+
+ GST_DEBUG_OBJECT (sinkpad, "activating pull");
+ return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+ {
+ GST_DEBUG_OBJECT (sinkpad, "activating push");
+ return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+ }
+}
+
+static gboolean
+gst_real_audio_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+ GstPadMode mode, gboolean active)
+{
+ gboolean res;
+ GstRealAudioDemux *demux;
+
+ demux = GST_REAL_AUDIO_DEMUX (parent);
+
+ switch (mode) {
+ case GST_PAD_MODE_PUSH:
+ demux->seekable = FALSE;
+ res = TRUE;
+ break;
+ case GST_PAD_MODE_PULL:
+ if (active) {
+ demux->seekable = TRUE;
+
+ res = gst_pad_start_task (sinkpad,
+ (GstTaskFunction) gst_real_audio_demux_loop, demux, NULL);
+ } else {
+ demux->seekable = FALSE;
+ res = gst_pad_stop_task (sinkpad);
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
+static GstFlowReturn
+gst_real_audio_demux_parse_marker (GstRealAudioDemux * demux)
+{
+ guint8 data[6];
+
+ if (gst_adapter_available (demux->adapter) < 6) {
+ GST_LOG_OBJECT (demux, "need at least 6 bytes, waiting for more data");
+ return GST_FLOW_OK;
+ }
+
+ gst_adapter_copy (demux->adapter, data, 0, 6);
+ if (memcmp (data, ".ra\375", 4) != 0)
+ goto wrong_format;
+
+ demux->ra_version = GST_READ_UINT16_BE (data + 4);
+ GST_DEBUG_OBJECT (demux, "ra_version = %u", demux->ra_version);
+ if (demux->ra_version != 4 && demux->ra_version != 3)
+ goto unsupported_ra_version;
+
+ gst_adapter_flush (demux->adapter, 6);
+ demux->state = REAL_AUDIO_DEMUX_STATE_HEADER;
+ return GST_FLOW_OK;
+
+/* ERRORS */
+wrong_format:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, WRONG_TYPE, (NULL), (NULL));
+ return GST_FLOW_ERROR;
+ }
+
+unsupported_ra_version:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE,
+ ("Cannot decode this RealAudio file, please file a bug"),
+ ("ra_version = %u", demux->ra_version));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstClockTime
+gst_real_demux_get_timestamp_from_offset (GstRealAudioDemux * demux,
+ guint64 offset)
+{
+ if (offset >= demux->data_offset && demux->byterate_num > 0 &&
+ demux->byterate_denom > 0) {
+ return gst_util_uint64_scale (offset - demux->data_offset,
+ demux->byterate_denom * GST_SECOND, demux->byterate_num);
+ } else if (offset == demux->data_offset) {
+ return (GstClockTime) 0;
+ } else {
+ return GST_CLOCK_TIME_NONE;
+ }
+}
+
+static gboolean
+gst_real_audio_demux_get_data_offset_from_header (GstRealAudioDemux * demux)
+{
+ guint8 data[16];
+
+ gst_adapter_copy (demux->adapter, data, 0, 16);
+
+ switch (demux->ra_version) {
+ case 3:
+ demux->data_offset = GST_READ_UINT16_BE (data) + 8;
+ break;
+ case 4:
+ demux->data_offset = GST_READ_UINT32_BE (data + 12) + 16;
+ break;
+ default:
+ demux->data_offset = 0;
+ g_return_val_if_reached (FALSE);
+ }
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_real_audio_demux_parse_header (GstRealAudioDemux * demux)
+{
+ const guint8 *data;
+ gchar *codec_name = NULL;
+ GstCaps *caps = NULL;
+ GstEvent *event;
+ gchar *stream_id;
+ guint avail;
+
+ g_assert (demux->ra_version == 4 || demux->ra_version == 3);
+
+ avail = gst_adapter_available (demux->adapter);
+ if (avail < 16)
+ return GST_FLOW_OK;
+
+ if (!gst_real_audio_demux_get_data_offset_from_header (demux))
+ return GST_FLOW_ERROR; /* shouldn't happen */
+
+ GST_DEBUG_OBJECT (demux, "data_offset = %u", demux->data_offset);
+
+ if (avail + 6 < demux->data_offset) {
+ GST_DEBUG_OBJECT (demux, "Need %u bytes, but only %u available now",
+ demux->data_offset - 6, avail);
+ return GST_FLOW_OK;
+ }
+
+ data = gst_adapter_map (demux->adapter, demux->data_offset - 6);
+ g_assert (data);
+
+ switch (demux->ra_version) {
+ case 3:
+ demux->fourcc = GST_RM_AUD_14_4;
+ demux->packet_size = 20;
+ demux->sample_rate = 8000;
+ demux->channels = 1;
+ demux->sample_width = 16;
+ demux->flavour = 1;
+ demux->leaf_size = 0;
+ demux->height = 0;
+ break;
+ case 4:
+ demux->flavour = GST_READ_UINT16_BE (data + 16);
+ /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */
+ demux->leaf_size = GST_READ_UINT16_BE (data + 38);
+ demux->height = GST_READ_UINT16_BE (data + 34);
+ demux->packet_size = GST_READ_UINT32_BE (data + 18);
+ demux->sample_rate = GST_READ_UINT16_BE (data + 42);
+ demux->sample_width = GST_READ_UINT16_BE (data + 46);
+ demux->channels = GST_READ_UINT16_BE (data + 48);
+ demux->fourcc = GST_READ_UINT32_LE (data + 56);
+ demux->pending_tags = gst_rm_utils_read_tags (data + 63,
+ demux->data_offset - 63, gst_rm_utils_read_string8);
+ if (demux->pending_tags)
+ gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL);
+ break;
+ default:
+ g_assert_not_reached ();
+#if 0
+ case 5:
+ demux->flavour = GST_READ_UINT16_BE (data + 16);
+ /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */
+ demux->leaf_size = GST_READ_UINT16_BE (data + 38);
+ demux->height = GST_READ_UINT16_BE (data + 34);
+
+ demux->sample_rate = GST_READ_UINT16_BE (data + 48);
+ demux->sample_width = GST_READ_UINT16_BE (data + 52);
+ demux->n_channels = GST_READ_UINT16_BE (data + 54);
+ demux->fourcc = RMDEMUX_FOURCC_GET (data + 60);
+ break;
+#endif
+ }
+
+ GST_INFO_OBJECT (demux, "packet_size = %u", demux->packet_size);
+ GST_INFO_OBJECT (demux, "sample_rate = %u", demux->sample_rate);
+ GST_INFO_OBJECT (demux, "sample_width = %u", demux->sample_width);
+ GST_INFO_OBJECT (demux, "channels = %u", demux->channels);
+ GST_INFO_OBJECT (demux, "fourcc = '%" GST_FOURCC_FORMAT "' (%08X)",
+ GST_FOURCC_ARGS (demux->fourcc), demux->fourcc);
+
+ switch (demux->fourcc) {
+ case GST_RM_AUD_14_4:
+ caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion",
+ G_TYPE_INT, 1, NULL);
+ demux->byterate_num = 1000;
+ demux->byterate_denom = 1;
+ break;
+
+ case GST_RM_AUD_28_8:
+ /* FIXME: needs descrambling */
+ caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion",
+ G_TYPE_INT, 2, NULL);
+ break;
+
+ case GST_RM_AUD_DNET:
+ caps = gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT,
+ demux->sample_rate, NULL);
+ if (demux->packet_size == 0 || demux->sample_rate == 0)
+ goto broken_file;
+ demux->byterate_num = demux->packet_size * demux->sample_rate;
+ demux->byterate_denom = 1536;
+ break;
+
+ /* Sipro/ACELP.NET Voice Codec (MIME unknown) */
+ case GST_RM_AUD_SIPR:
+ caps = gst_caps_new_empty_simple ("audio/x-sipro");
+ break;
+
+ default:
+ GST_WARNING_OBJECT (demux, "unknown fourcc %08X", demux->fourcc);
+ break;
+ }
+
+ if (caps == NULL)
+ goto unknown_fourcc;
+
+ gst_caps_set_simple (caps,
+ "flavor", G_TYPE_INT, demux->flavour,
+ "rate", G_TYPE_INT, demux->sample_rate,
+ "channels", G_TYPE_INT, demux->channels,
+ "width", G_TYPE_INT, demux->sample_width,
+ "leaf_size", G_TYPE_INT, demux->leaf_size,
+ "packet_size", G_TYPE_INT, demux->packet_size,
+ "height", G_TYPE_INT, demux->height, NULL);
+
+ GST_INFO_OBJECT (demux, "Adding source pad, caps %" GST_PTR_FORMAT, caps);
+ demux->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+ gst_pad_set_event_function (demux->srcpad,
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_event));
+ gst_pad_set_query_function (demux->srcpad,
+ GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_query));
+ gst_pad_set_active (demux->srcpad, TRUE);
+ gst_pad_use_fixed_caps (demux->srcpad);
+
+ stream_id =
+ gst_pad_create_stream_id (demux->srcpad, GST_ELEMENT_CAST (demux), NULL);
+
+ event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
+ if (event) {
+ if (gst_event_parse_group_id (event, &demux->group_id))
+ demux->have_group_id = TRUE;
+ else
+ demux->have_group_id = FALSE;
+ gst_event_unref (event);
+ } else if (!demux->have_group_id) {
+ demux->have_group_id = TRUE;
+ demux->group_id = gst_util_group_id_next ();
+ }
+
+ event = gst_event_new_stream_start (stream_id);
+ if (demux->have_group_id)
+ gst_event_set_group_id (event, demux->group_id);
+
+ gst_pad_push_event (demux->srcpad, event);
+ g_free (stream_id);
+
+ gst_pad_set_caps (demux->srcpad, caps);
+ codec_name = gst_pb_utils_get_codec_description (caps);
+ gst_caps_unref (caps);
+
+ gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad);
+
+ if (demux->byterate_num > 0 && demux->byterate_denom > 0) {
+ GstFormat bformat = GST_FORMAT_BYTES;
+ gint64 size_bytes = 0;
+
+ GST_INFO_OBJECT (demux, "byte rate = %u/%u = %u bytes/sec",
+ demux->byterate_num, demux->byterate_denom,
+ demux->byterate_num / demux->byterate_denom);
+
+ if (gst_pad_peer_query_duration (demux->sinkpad, bformat, &size_bytes)) {
+ demux->duration =
+ gst_real_demux_get_timestamp_from_offset (demux, size_bytes);
+ demux->upstream_size = size_bytes;
+ GST_INFO_OBJECT (demux, "upstream_size = %" G_GUINT64_FORMAT,
+ demux->upstream_size);
+ GST_INFO_OBJECT (demux, "duration = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->duration));
+ }
+ }
+
+ demux->need_newsegment = TRUE;
+
+ if (codec_name) {
+ if (demux->pending_tags == NULL) {
+ demux->pending_tags = gst_tag_list_new_empty ();
+ gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL);
+ }
+
+ gst_tag_list_add (demux->pending_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_AUDIO_CODEC, codec_name, NULL);
+ g_free (codec_name);
+ }
+
+ gst_adapter_unmap (demux->adapter);
+ gst_adapter_flush (demux->adapter, demux->data_offset - 6);
+
+ demux->state = REAL_AUDIO_DEMUX_STATE_DATA;
+ demux->need_newsegment = TRUE;
+
+ return GST_FLOW_OK;
+
+/* ERRORS */
+unknown_fourcc:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL),
+ ("Unknown fourcc '0x%" G_GINT32_MODIFIER "x'", demux->fourcc));
+ return GST_FLOW_ERROR;
+ }
+broken_file:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL),
+ ("Broken file - invalid sample_rate or other header value"));
+ return GST_FLOW_ERROR;
+ }
+
+}
+
+static GstFlowReturn
+gst_real_audio_demux_parse_data (GstRealAudioDemux * demux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint avail, unit_size;
+
+ avail = gst_adapter_available (demux->adapter);
+
+ if (demux->packet_size > 0)
+ unit_size = demux->packet_size;
+ else
+ unit_size = avail & 0xfffffff0; /* round down to next multiple of 16 */
+
+ GST_LOG_OBJECT (demux, "available = %u, unit_size = %u", avail, unit_size);
+
+ while (ret == GST_FLOW_OK && unit_size > 0 && avail >= unit_size) {
+ GstClockTime ts;
+ GstBuffer *buf;
+
+ buf = gst_adapter_take_buffer (demux->adapter, unit_size);
+ avail -= unit_size;
+
+ if (demux->need_newsegment) {
+ gst_pad_push_event (demux->srcpad,
+ gst_event_new_segment (&demux->segment));
+ demux->need_newsegment = FALSE;
+ }
+
+ if (demux->pending_tags) {
+ gst_pad_push_event (demux->srcpad,
+ gst_event_new_tag (demux->pending_tags));
+ demux->pending_tags = NULL;
+ }
+
+ if (demux->fourcc == GST_RM_AUD_DNET) {
+ buf = gst_rm_utils_descramble_dnet_buffer (buf);
+ }
+
+ ts = gst_real_demux_get_timestamp_from_offset (demux, demux->offset);
+ GST_BUFFER_TIMESTAMP (buf) = ts;
+
+ demux->segment.position = ts;
+
+ ret = gst_pad_push (demux->srcpad, buf);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_real_audio_demux_handle_buffer (GstRealAudioDemux * demux, GstBuffer * buf)
+{
+ GstFlowReturn ret;
+
+ gst_adapter_push (demux->adapter, buf);
+ buf = NULL;
+
+ switch (demux->state) {
+ case REAL_AUDIO_DEMUX_STATE_MARKER:{
+ ret = gst_real_audio_demux_parse_marker (demux);
+ if (ret != GST_FLOW_OK || demux->state != REAL_AUDIO_DEMUX_STATE_HEADER)
+ break;
+ /* otherwise fall through */
+ }
+ case REAL_AUDIO_DEMUX_STATE_HEADER:{
+ ret = gst_real_audio_demux_parse_header (demux);
+ if (ret != GST_FLOW_OK || demux->state != REAL_AUDIO_DEMUX_STATE_DATA)
+ break;
+ /* otherwise fall through */
+ }
+ case REAL_AUDIO_DEMUX_STATE_DATA:{
+ ret = gst_real_audio_demux_parse_data (demux);
+ break;
+ }
+ default:
+ g_return_val_if_reached (GST_FLOW_ERROR);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_real_audio_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstRealAudioDemux *demux;
+
+ demux = GST_REAL_AUDIO_DEMUX (parent);
+
+ return gst_real_audio_demux_handle_buffer (demux, buf);
+}
+
+static void
+gst_real_audio_demux_loop (GstRealAudioDemux * demux)
+{
+ GstFlowReturn ret;
+ GstBuffer *buf;
+ guint bytes_needed;
+
+ /* check how much data we need */
+ switch (demux->state) {
+ case REAL_AUDIO_DEMUX_STATE_MARKER:
+ bytes_needed = 6 + 16; /* 16 are beginning of header */
+ break;
+ case REAL_AUDIO_DEMUX_STATE_HEADER:
+ if (!gst_real_audio_demux_get_data_offset_from_header (demux))
+ goto parse_header_error;
+ bytes_needed = demux->data_offset - (6 + 16);
+ break;
+ case REAL_AUDIO_DEMUX_STATE_DATA:
+ if (demux->packet_size > 0) {
+ /* TODO: should probably take into account width/height as well? */
+ bytes_needed = demux->packet_size;
+ } else {
+ bytes_needed = 1024;
+ }
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ /* now get the data */
+ GST_LOG_OBJECT (demux, "getting data: %5u bytes @ %8" G_GINT64_MODIFIER "u",
+ bytes_needed, demux->offset);
+
+ if (demux->upstream_size > 0 && demux->offset >= demux->upstream_size)
+ goto eos;
+
+ buf = NULL;
+ ret = gst_pad_pull_range (demux->sinkpad, demux->offset, bytes_needed, &buf);
+
+ if (ret != GST_FLOW_OK)
+ goto pull_range_error;
+
+ if (gst_buffer_get_size (buf) != bytes_needed)
+ goto pull_range_short_read;
+
+ ret = gst_real_audio_demux_handle_buffer (demux, buf);
+ if (ret != GST_FLOW_OK)
+ goto handle_flow_error;
+
+ /* TODO: increase this in chain function too (for timestamps)? */
+ demux->offset += bytes_needed;
+
+ /* check for the end of the segment */
+ if (demux->segment.stop != -1 && demux->segment.position != -1 &&
+ demux->segment.position > demux->segment.stop) {
+ GST_DEBUG_OBJECT (demux, "reached end of segment");
+ goto eos;
+ }
+
+ return;
+
+/* ERRORS */
+parse_header_error:
+ {
+ GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), (NULL));
+ goto pause_task;
+ }
+handle_flow_error:
+ {
+ GST_WARNING_OBJECT (demux, "handle_buf flow: %s", gst_flow_get_name (ret));
+ goto pause_task;
+ }
+pull_range_error:
+ {
+ GST_WARNING_OBJECT (demux, "pull range flow: %s", gst_flow_get_name (ret));
+ goto pause_task;
+ }
+pull_range_short_read:
+ {
+ GST_WARNING_OBJECT (demux, "pull range short read: wanted %u bytes, but "
+ "got only %" G_GSIZE_FORMAT " bytes", bytes_needed,
+ gst_buffer_get_size (buf));
+ gst_buffer_unref (buf);
+ goto eos;
+ }
+eos:
+ {
+ if (demux->state != REAL_AUDIO_DEMUX_STATE_DATA) {
+ GST_WARNING_OBJECT (demux, "reached EOS before finished parsing header");
+ goto parse_header_error;
+ }
+ GST_INFO_OBJECT (demux, "EOS");
+ if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) != 0) {
+ gint64 stop;
+
+ /* for segment playback we need to post when (in stream time)
+ * we stopped, this is either stop (when set) or the duration. */
+ if ((stop = demux->segment.stop) == -1)
+ stop = demux->segment.duration;
+
+ GST_DEBUG_OBJECT (demux, "sending segment done, at end of segment");
+ gst_element_post_message (GST_ELEMENT (demux),
+ gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
+ stop));
+ gst_pad_push_event (demux->srcpad,
+ gst_event_new_segment_done (GST_FORMAT_TIME, stop));
+ } else {
+ /* normal playback, send EOS event downstream */
+ GST_DEBUG_OBJECT (demux, "sending EOS event, at end of stream");
+ gst_pad_push_event (demux->srcpad, gst_event_new_eos ());
+ }
+ goto pause_task;
+ }
+pause_task:
+ {
+ demux->segment_running = FALSE;
+ gst_pad_pause_task (demux->sinkpad);
+ GST_DEBUG_OBJECT (demux, "pausing task");
+ return;
+ }
+}
+
+static gboolean
+gst_real_audio_demux_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstRealAudioDemux *demux;
+ gboolean ret;
+
+ demux = GST_REAL_AUDIO_DEMUX (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:{
+ /* FIXME */
+ gst_event_unref (event);
+ demux->need_newsegment = TRUE;
+ ret = TRUE;
+ break;
+ }
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+ return ret;
+}
+
+static gboolean
+gst_real_audio_demux_handle_seek (GstRealAudioDemux * demux, GstEvent * event)
+{
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gboolean flush, update;
+ gdouble rate;
+ guint64 seek_pos;
+ gint64 cur, stop;
+
+ if (!demux->seekable)
+ goto not_seekable;
+
+ if (demux->byterate_num == 0 || demux->byterate_denom == 0)
+ goto no_bitrate;
+
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
+
+ if (format != GST_FORMAT_TIME)
+ goto only_time_format_supported;
+
+ if (rate <= 0.0)
+ goto cannot_do_backwards_playback;
+
+ flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);
+
+ GST_DEBUG_OBJECT (demux, "flush=%d, rate=%g", flush, rate);
+
+ /* unlock streaming thread and make streaming stop */
+ if (flush) {
+ gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
+ gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
+ } else {
+ gst_pad_pause_task (demux->sinkpad);
+ }
+
+ GST_PAD_STREAM_LOCK (demux->sinkpad);
+
+ gst_segment_do_seek (&demux->segment, rate, format, flags,
+ cur_type, cur, stop_type, stop, &update);
+
+ GST_DEBUG_OBJECT (demux, "segment: %" GST_SEGMENT_FORMAT, &demux->segment);
+
+ seek_pos = gst_util_uint64_scale (demux->segment.start,
+ demux->byterate_num, demux->byterate_denom * GST_SECOND);
+ if (demux->packet_size > 0) {
+ seek_pos -= seek_pos % demux->packet_size;
+ }
+ seek_pos += demux->data_offset;
+
+ GST_DEBUG_OBJECT (demux, "seek_pos = %" G_GUINT64_FORMAT, seek_pos);
+
+ /* stop flushing */
+ gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
+ gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop (TRUE));
+
+ demux->offset = seek_pos;
+ demux->need_newsegment = TRUE;
+
+ /* notify start of new segment */
+ if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gst_element_post_message (GST_ELEMENT (demux),
+ gst_message_new_segment_start (GST_OBJECT (demux),
+ GST_FORMAT_TIME, demux->segment.position));
+ }
+
+ demux->segment_running = TRUE;
+ /* restart our task since it might have been stopped when we did the flush */
+ gst_pad_start_task (demux->sinkpad,
+ (GstTaskFunction) gst_real_audio_demux_loop, demux, NULL);
+
+ /* streaming can continue now */
+ GST_PAD_STREAM_UNLOCK (demux->sinkpad);
+
+ return TRUE;
+
+/* ERRORS */
+not_seekable:
+ {
+ GST_DEBUG_OBJECT (demux, "seek failed: cannot seek in streaming mode");
+ return FALSE;
+ }
+no_bitrate:
+ {
+ GST_DEBUG_OBJECT (demux, "seek failed: bitrate unknown");
+ return FALSE;
+ }
+only_time_format_supported:
+ {
+ GST_DEBUG_OBJECT (demux, "can only seek in TIME format");
+ return FALSE;
+ }
+cannot_do_backwards_playback:
+ {
+ GST_DEBUG_OBJECT (demux, "can only seek with positive rate, not %lf", rate);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_real_audio_demux_src_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstRealAudioDemux *demux;
+ gboolean ret = FALSE;
+
+ demux = GST_REAL_AUDIO_DEMUX (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_QOS:
+ gst_event_unref (event);
+ break;
+ case GST_EVENT_SEEK:
+ ret = gst_real_audio_demux_handle_seek (demux, event);
+ gst_event_unref (event);
+ break;
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_real_audio_demux_src_query (GstPad * pad, GstObject * parent,
+ GstQuery * query)
+{
+ GstRealAudioDemux *demux;
+ gboolean ret = FALSE;
+
+ demux = GST_REAL_AUDIO_DEMUX (parent);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_DURATION:{
+ GstFormat format;
+
+ gst_query_parse_duration (query, &format, NULL);
+ if (format == GST_FORMAT_TIME && demux->duration > 0) {
+ gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
+ ret = TRUE;
+ } else if (format == GST_FORMAT_BYTES && demux->upstream_size > 0) {
+ gst_query_set_duration (query, GST_FORMAT_BYTES,
+ demux->upstream_size - demux->data_offset);
+ ret = TRUE;
+ }
+ break;
+ }
+ case GST_QUERY_SEEKING:{
+ GstFormat format;
+ gboolean seekable;
+
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+ seekable = (format == GST_FORMAT_TIME && demux->seekable);
+ gst_query_set_seeking (query, format, seekable, 0,
+ (format == GST_FORMAT_TIME) ? demux->duration : -1);
+ ret = TRUE;
+ break;
+ }
+ case GST_QUERY_SEGMENT:
+ {
+ GstFormat format;
+ gint64 start, stop;
+
+ format = demux->segment.format;
+
+ start =
+ gst_segment_to_stream_time (&demux->segment, format,
+ demux->segment.start);
+ if ((stop = demux->segment.stop) == -1)
+ stop = demux->segment.duration;
+ else
+ stop = gst_segment_to_stream_time (&demux->segment, format, stop);
+
+ gst_query_set_segment (query, demux->segment.rate, format, start, stop);
+ ret = TRUE;
+ break;
+ }
+ default:
+ ret = gst_pad_query_default (pad, parent, query);
+ break;
+ }
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_real_audio_demux_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstRealAudioDemux *demux = GST_REAL_AUDIO_DEMUX (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ demux->state = REAL_AUDIO_DEMUX_STATE_MARKER;
+ demux->segment_running = FALSE;
+ gst_segment_init (&demux->segment, GST_FORMAT_TIME);
+ gst_adapter_clear (demux->adapter);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:{
+ gst_real_audio_demux_reset (demux);
+ gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
+ break;
+ }
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_rademux_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rademux",
+ GST_RANK_SECONDARY, GST_TYPE_REAL_AUDIO_DEMUX);
+}
diff --git a/gst/realmedia/rademux.h b/gst/realmedia/rademux.h
new file mode 100644
index 0000000..8392d15
--- /dev/null
+++ b/gst/realmedia/rademux.h
@@ -0,0 +1,104 @@
+/* GStreamer RealAudio demuxer
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_REAL_AUDIO_DEMUX_H__
+#define __GST_REAL_AUDIO_DEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_REAL_AUDIO_DEMUX \
+ (gst_real_audio_demux_get_type())
+#define GST_REAL_AUDIO_DEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_REAL_AUDIO_DEMUX,GstRealAudioDemux))
+#define GST_REAL_AUDIO_DEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_REAL_AUDIO_DEMUX,GstRealAudioDemuxClass))
+#define GST_IS_REAL_AUDIO_DEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_REAL_AUDIO_DEMUX))
+#define GST_IS_REAL_AUDIO_DEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_REAL_AUDIO_DEMUX))
+
+typedef enum
+{
+ REAL_AUDIO_DEMUX_STATE_MARKER,
+ REAL_AUDIO_DEMUX_STATE_HEADER,
+ REAL_AUDIO_DEMUX_STATE_DATA
+} GstRealAudioDemuxState;
+
+typedef struct _GstRealAudioDemux GstRealAudioDemux;
+typedef struct _GstRealAudioDemuxClass GstRealAudioDemuxClass;
+
+struct _GstRealAudioDemux {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ gboolean have_group_id;
+ guint group_id;
+
+ GstAdapter *adapter;
+ GstRealAudioDemuxState state;
+
+ guint ra_version;
+ guint data_offset;
+
+ guint packet_size;
+ guint leaf_size;
+ guint height;
+ guint flavour;
+
+ guint sample_rate;
+ guint sample_width;
+ guint channels;
+ guint32 fourcc;
+
+ gboolean segment_running;
+
+ gboolean need_newsegment;
+ GstTagList *pending_tags;
+
+ guint byterate_num; /* bytes per second */
+ guint byterate_denom;
+
+ gint64 duration;
+ gint64 upstream_size;
+
+ guint64 offset; /* current read byte offset for
+ * pull_range-based mode */
+
+ /* playback start/stop positions */
+ GstSegment segment;
+
+ gboolean seekable;
+};
+
+struct _GstRealAudioDemuxClass {
+ GstElementClass element_class;
+};
+
+GType gst_real_audio_demux_get_type (void);
+
+gboolean gst_rademux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_REAL_AUDIO_DEMUX_H__ */
diff --git a/gst/realmedia/rdtdepay.c b/gst/realmedia/rdtdepay.c
new file mode 100644
index 0000000..308faec
--- /dev/null
+++ b/gst/realmedia/rdtdepay.c
@@ -0,0 +1,501 @@
+/* GStreamer
+ * Copyright (C) <2006> Lutz Mueller <lutz at topfrose dot de>
+ * <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstrdtbuffer.h"
+#include "rdtdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rdtdepay_debug);
+#define GST_CAT_DEFAULT rdtdepay_debug
+
+/* RDTDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+};
+
+static GstStaticPadTemplate gst_rdt_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/vnd.rn-realmedia")
+ );
+
+static GstStaticPadTemplate gst_rdt_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rdt, "
+ "media = (string) \"application\", "
+ "clock-rate = (int) [1, MAX ], "
+ "encoding-name = (string) \"X-REAL-RDT\""
+ /* All optional parameters
+ *
+ * "config="
+ */
+ )
+ );
+
+#define gst_rdt_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRDTDepay, gst_rdt_depay, GST_TYPE_ELEMENT);
+
+static void gst_rdt_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rdt_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rdt_depay_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static GstFlowReturn gst_rdt_depay_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buf);
+
+static void
+gst_rdt_depay_class_init (GstRDTDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_rdt_depay_finalize;
+
+ gstelement_class->change_state = gst_rdt_depay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rdt_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rdt_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RDT packet parser",
+ "Codec/Depayloader/Network",
+ "Extracts RealMedia from RDT packets",
+ "Lutz Mueller <lutz at topfrose dot de>, "
+ "Wim Taymans <wim@fluendo.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rdtdepay_debug, "rdtdepay",
+ 0, "Depayloader for RDT RealMedia packets");
+}
+
+static void
+gst_rdt_depay_init (GstRDTDepay * rdtdepay)
+{
+ rdtdepay->sinkpad =
+ gst_pad_new_from_static_template (&gst_rdt_depay_sink_template, "sink");
+ gst_pad_set_chain_function (rdtdepay->sinkpad, gst_rdt_depay_chain);
+ gst_pad_set_event_function (rdtdepay->sinkpad, gst_rdt_depay_sink_event);
+ gst_element_add_pad (GST_ELEMENT_CAST (rdtdepay), rdtdepay->sinkpad);
+
+ rdtdepay->srcpad =
+ gst_pad_new_from_static_template (&gst_rdt_depay_src_template, "src");
+ gst_element_add_pad (GST_ELEMENT_CAST (rdtdepay), rdtdepay->srcpad);
+}
+
+static void
+gst_rdt_depay_finalize (GObject * object)
+{
+ GstRDTDepay *rdtdepay;
+
+ rdtdepay = GST_RDT_DEPAY (object);
+
+ if (rdtdepay->header)
+ gst_buffer_unref (rdtdepay->header);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rdt_depay_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRDTDepay *rdtdepay;
+ GstCaps *srccaps;
+ gint clock_rate = 1000; /* default */
+ const GValue *value;
+ GstBuffer *header;
+
+ rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad));
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (gst_structure_has_field (structure, "clock-rate"))
+ gst_structure_get_int (structure, "clock-rate", &clock_rate);
+
+ /* config contains the RealMedia header as a buffer. */
+ value = gst_structure_get_value (structure, "config");
+ if (!value)
+ goto no_header;
+
+ header = gst_value_get_buffer (value);
+ if (!header)
+ goto no_header;
+
+ /* get other values for newsegment */
+ value = gst_structure_get_value (structure, "npt-start");
+ if (value && G_VALUE_HOLDS_UINT64 (value))
+ rdtdepay->npt_start = g_value_get_uint64 (value);
+ else
+ rdtdepay->npt_start = 0;
+ GST_DEBUG_OBJECT (rdtdepay, "NPT start %" G_GUINT64_FORMAT,
+ rdtdepay->npt_start);
+
+ value = gst_structure_get_value (structure, "npt-stop");
+ if (value && G_VALUE_HOLDS_UINT64 (value))
+ rdtdepay->npt_stop = g_value_get_uint64 (value);
+ else
+ rdtdepay->npt_stop = -1;
+
+ GST_DEBUG_OBJECT (rdtdepay, "NPT stop %" G_GUINT64_FORMAT,
+ rdtdepay->npt_stop);
+
+ value = gst_structure_get_value (structure, "play-speed");
+ if (value && G_VALUE_HOLDS_DOUBLE (value))
+ rdtdepay->play_speed = g_value_get_double (value);
+ else
+ rdtdepay->play_speed = 1.0;
+
+ value = gst_structure_get_value (structure, "play-scale");
+ if (value && G_VALUE_HOLDS_DOUBLE (value))
+ rdtdepay->play_scale = g_value_get_double (value);
+ else
+ rdtdepay->play_scale = 1.0;
+
+ /* caps seem good, configure element */
+ rdtdepay->clock_rate = clock_rate;
+
+ /* set caps on pad and on header */
+ srccaps = gst_caps_new_empty_simple ("application/vnd.rn-realmedia");
+ gst_pad_set_caps (rdtdepay->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ if (rdtdepay->header)
+ gst_buffer_unref (rdtdepay->header);
+ rdtdepay->header = gst_buffer_ref (header);
+
+ return TRUE;
+
+ /* ERRORS */
+no_header:
+ {
+ GST_ERROR_OBJECT (rdtdepay, "no header found in caps, no 'config' field");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rdt_depay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstRDTDepay *depay;
+ gboolean res = TRUE;
+
+ depay = GST_RDT_DEPAY (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ res = gst_rdt_depay_setcaps (pad, caps);
+ gst_event_unref (event);
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:
+ res = gst_pad_push_event (depay->srcpad, event);
+
+ gst_segment_init (&depay->segment, GST_FORMAT_UNDEFINED);
+ depay->need_newsegment = TRUE;
+ depay->next_seqnum = -1;
+ break;
+ case GST_EVENT_SEGMENT:
+ {
+ gst_event_copy_segment (event, &depay->segment);
+ /* don't pass the event downstream, we generate our own segment
+ * including the NTP time and other things we receive in caps */
+ gst_event_unref (event);
+ break;
+ }
+ default:
+ /* pass other events forward */
+ res = gst_pad_push_event (depay->srcpad, event);
+ break;
+ }
+ return res;
+}
+
+static GstEvent *
+create_segment_event (GstRDTDepay * depay, gboolean update,
+ GstClockTime position)
+{
+ GstSegment segment;
+
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ segment.rate = depay->play_speed;
+ segment.applied_rate = depay->play_scale;
+ segment.start = position;
+
+ if (depay->npt_stop != -1)
+ segment.stop = depay->npt_stop - depay->npt_start;
+ else
+ segment.stop = -1;
+
+ segment.time = position + depay->npt_start;
+
+ return gst_event_new_segment (&segment);
+}
+
+static GstFlowReturn
+gst_rdt_depay_push (GstRDTDepay * rdtdepay, GstBuffer * buffer)
+{
+ GstFlowReturn ret;
+
+ if (rdtdepay->need_newsegment) {
+ GstEvent *event;
+
+ event = create_segment_event (rdtdepay, FALSE, 0);
+ gst_pad_push_event (rdtdepay->srcpad, event);
+
+ rdtdepay->need_newsegment = FALSE;
+ }
+
+ if (rdtdepay->discont) {
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+ rdtdepay->discont = FALSE;
+ }
+ ret = gst_pad_push (rdtdepay->srcpad, buffer);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime,
+ GstRDTPacket * packet)
+{
+ GstFlowReturn ret;
+ GstBuffer *outbuf;
+ GstMapInfo outmap;
+ guint8 *data, *outdata;
+ guint size;
+ guint16 stream_id;
+ guint32 timestamp;
+ gint gap;
+ guint16 seqnum;
+ guint8 flags;
+ guint16 outflags;
+
+ /* get pointers to the packet data */
+ data = gst_rdt_packet_data_map (packet, &size);
+
+ outbuf = gst_buffer_new_and_alloc (12 + size);
+ GST_BUFFER_TIMESTAMP (outbuf) = outtime;
+
+ GST_DEBUG_OBJECT (rdtdepay, "have size %u", size);
+
+ /* copy over some things */
+ stream_id = gst_rdt_packet_data_get_stream_id (packet);
+ timestamp = gst_rdt_packet_data_get_timestamp (packet);
+ flags = gst_rdt_packet_data_get_flags (packet);
+
+ seqnum = gst_rdt_packet_data_get_seq (packet);
+
+ GST_DEBUG_OBJECT (rdtdepay, "stream_id %u, timestamp %u, seqnum %d, flags %d",
+ stream_id, timestamp, seqnum, flags);
+
+ if (rdtdepay->next_seqnum != -1) {
+ gap = gst_rdt_buffer_compare_seqnum (seqnum, rdtdepay->next_seqnum);
+
+ /* if we have no gap, all is fine */
+ if (G_UNLIKELY (gap != 0)) {
+ GST_LOG_OBJECT (rdtdepay, "got packet %u, expected %u, gap %d", seqnum,
+ rdtdepay->next_seqnum, gap);
+ if (gap < 0) {
+ /* seqnum > next_seqnum, we are missing some packets, this is always a
+ * DISCONT. */
+ GST_LOG_OBJECT (rdtdepay, "%d missing packets", gap);
+ rdtdepay->discont = TRUE;
+ } else {
+ /* seqnum < next_seqnum, we have seen this packet before or the sender
+ * could be restarted. If the packet is not too old, we throw it away as
+ * a duplicate, otherwise we mark discont and continue. 100 misordered
+ * packets is a good threshold. See also RFC 4737. */
+ if (gap < 100)
+ goto dropping;
+
+ GST_LOG_OBJECT (rdtdepay,
+ "%d > 100, packet too old, sender likely restarted", gap);
+ rdtdepay->discont = TRUE;
+ }
+ }
+ }
+ rdtdepay->next_seqnum = (seqnum + 1);
+ if (rdtdepay->next_seqnum == 0xff00)
+ rdtdepay->next_seqnum = 0;
+
+ if ((flags & 1) == 0)
+ outflags = 2;
+ else
+ outflags = 0;
+
+ gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+ outdata = outmap.data;
+ GST_WRITE_UINT16_BE (outdata + 0, 0); /* version */
+ GST_WRITE_UINT16_BE (outdata + 2, size + 12); /* length */
+ GST_WRITE_UINT16_BE (outdata + 4, stream_id); /* stream */
+ GST_WRITE_UINT32_BE (outdata + 6, timestamp); /* timestamp */
+ GST_WRITE_UINT16_BE (outdata + 10, outflags); /* flags */
+ memcpy (outdata + 12, data, size);
+ gst_buffer_unmap (outbuf, &outmap);
+ gst_buffer_resize (outbuf, 0, 12 + size);
+
+ gst_rdt_packet_data_unmap (packet);
+
+ GST_DEBUG_OBJECT (rdtdepay, "Pushing packet, outtime %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (outtime));
+
+ ret = gst_rdt_depay_push (rdtdepay, outbuf);
+
+ return ret;
+
+ /* ERRORS */
+dropping:
+ {
+ GST_WARNING_OBJECT (rdtdepay, "%d <= 100, dropping old packet", gap);
+ return GST_FLOW_OK;
+ }
+}
+
+static GstFlowReturn
+gst_rdt_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstRDTDepay *rdtdepay;
+ GstFlowReturn ret;
+ GstClockTime timestamp;
+ gboolean more;
+ GstRDTPacket packet;
+
+ rdtdepay = GST_RDT_DEPAY (parent);
+
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_LOG_OBJECT (rdtdepay, "received discont");
+ rdtdepay->discont = TRUE;
+ }
+
+ if (rdtdepay->header) {
+ GstBuffer *out;
+
+ out = rdtdepay->header;
+ rdtdepay->header = NULL;
+
+ /* push header data first */
+ gst_rdt_depay_push (rdtdepay, out);
+ }
+
+ /* save timestamp */
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ ret = GST_FLOW_OK;
+
+ GST_LOG_OBJECT (rdtdepay, "received buffer timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+
+ /* data is in RDT format. */
+ more = gst_rdt_buffer_get_first_packet (buf, &packet);
+ while (more) {
+ GstRDTType type;
+
+ type = gst_rdt_packet_get_type (&packet);
+ GST_DEBUG_OBJECT (rdtdepay, "Have packet of type %04x", type);
+
+ if (GST_RDT_IS_DATA_TYPE (type)) {
+ GST_DEBUG_OBJECT (rdtdepay, "We have a data packet");
+ ret = gst_rdt_depay_handle_data (rdtdepay, timestamp, &packet);
+ } else {
+ switch (type) {
+ default:
+ GST_DEBUG_OBJECT (rdtdepay, "Ignoring packet");
+ break;
+ }
+ }
+ if (ret != GST_FLOW_OK)
+ break;
+
+ more = gst_rdt_packet_move_to_next (&packet);
+ }
+
+ gst_buffer_unref (buf);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_rdt_depay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRDTDepay *rdtdepay;
+ GstStateChangeReturn ret;
+
+ rdtdepay = GST_RDT_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_segment_init (&rdtdepay->segment, GST_FORMAT_UNDEFINED);
+ rdtdepay->next_seqnum = -1;
+ rdtdepay->need_newsegment = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ if (rdtdepay->header)
+ gst_buffer_unref (rdtdepay->header);
+ rdtdepay->header = NULL;
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rdt_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rdtdepay",
+ GST_RANK_MARGINAL, GST_TYPE_RDT_DEPAY);
+}
diff --git a/gst/realmedia/rdtdepay.h b/gst/realmedia/rdtdepay.h
new file mode 100644
index 0000000..a4ed291
--- /dev/null
+++ b/gst/realmedia/rdtdepay.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <2006> Lutz Mueller <lutz at topfrose dot de>
+ * <2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RDT_DEPAY_H__
+#define __GST_RDT_DEPAY_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RDT_DEPAY \
+ (gst_rdt_depay_get_type())
+#define GST_RDT_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RDT_DEPAY,GstRDTDepay))
+#define GST_RDT_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RDT_DEPAY,GstRDTDepayClass))
+#define GST_IS_RDT_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RDT_DEPAY))
+#define GST_IS_RDT_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RDT_DEPAY))
+
+typedef struct _GstRDTDepay GstRDTDepay;
+typedef struct _GstRDTDepayClass GstRDTDepayClass;
+
+struct _GstRDTDepay
+{
+ GstElement parent;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ guint clock_rate;
+ GstClockTime npt_start;
+ GstClockTime npt_stop;
+ gdouble play_speed;
+ gdouble play_scale;
+
+ guint32 next_seqnum;
+
+ gboolean discont;
+ gboolean need_newsegment;
+ GstSegment segment;
+ GstBuffer *header;
+};
+
+struct _GstRDTDepayClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_rdt_depay_get_type (void);
+
+gboolean gst_rdt_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RDT_DEPAY_H__ */
diff --git a/gst/realmedia/rdtjitterbuffer.c b/gst/realmedia/rdtjitterbuffer.c
new file mode 100644
index 0000000..4c6b0ae
--- /dev/null
+++ b/gst/realmedia/rdtjitterbuffer.c
@@ -0,0 +1,531 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <string.h>
+#include <stdlib.h>
+
+#include "rdtjitterbuffer.h"
+#include "gstrdtbuffer.h"
+
+GST_DEBUG_CATEGORY_STATIC (rdt_jitter_buffer_debug);
+#define GST_CAT_DEFAULT rdt_jitter_buffer_debug
+
+#define MAX_WINDOW RDT_JITTER_BUFFER_MAX_WINDOW
+#define MAX_TIME (2 * GST_SECOND)
+
+/* signals and args */
+enum
+{
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+/* GObject vmethods */
+static void rdt_jitter_buffer_finalize (GObject * object);
+
+/* static guint rdt_jitter_buffer_signals[LAST_SIGNAL] = { 0 }; */
+
+G_DEFINE_TYPE (RDTJitterBuffer, rdt_jitter_buffer, G_TYPE_OBJECT);
+
+static void
+rdt_jitter_buffer_class_init (RDTJitterBufferClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = rdt_jitter_buffer_finalize;
+
+ GST_DEBUG_CATEGORY_INIT (rdt_jitter_buffer_debug, "rdtjitterbuffer", 0,
+ "RDT Jitter Buffer");
+}
+
+static void
+rdt_jitter_buffer_init (RDTJitterBuffer * jbuf)
+{
+ jbuf->packets = g_queue_new ();
+
+ rdt_jitter_buffer_reset_skew (jbuf);
+}
+
+static void
+rdt_jitter_buffer_finalize (GObject * object)
+{
+ RDTJitterBuffer *jbuf;
+
+ jbuf = RDT_JITTER_BUFFER_CAST (object);
+
+ rdt_jitter_buffer_flush (jbuf);
+ g_queue_free (jbuf->packets);
+
+ G_OBJECT_CLASS (rdt_jitter_buffer_parent_class)->finalize (object);
+}
+
+/**
+ * rdt_jitter_buffer_new:
+ *
+ * Create an #RDTJitterBuffer.
+ *
+ * Returns: a new #RDTJitterBuffer. Use g_object_unref() after usage.
+ */
+RDTJitterBuffer *
+rdt_jitter_buffer_new (void)
+{
+ RDTJitterBuffer *jbuf;
+
+ jbuf = g_object_new (RDT_TYPE_JITTER_BUFFER, NULL);
+
+ return jbuf;
+}
+
+void
+rdt_jitter_buffer_reset_skew (RDTJitterBuffer * jbuf)
+{
+ jbuf->base_time = -1;
+ jbuf->base_rtptime = -1;
+ jbuf->ext_rtptime = -1;
+ jbuf->window_pos = 0;
+ jbuf->window_filling = TRUE;
+ jbuf->window_min = 0;
+ jbuf->skew = 0;
+ jbuf->prev_send_diff = -1;
+}
+
+/* For the clock skew we use a windowed low point averaging algorithm as can be
+ * found in http://www.grame.fr/pub/TR-050601.pdf. The idea is that the jitter is
+ * composed of:
+ *
+ * J = N + n
+ *
+ * N : a constant network delay.
+ * n : random added noise. The noise is concentrated around 0
+ *
+ * In the receiver we can track the elapsed time at the sender with:
+ *
+ * send_diff(i) = (Tsi - Ts0);
+ *
+ * Tsi : The time at the sender at packet i
+ * Ts0 : The time at the sender at the first packet
+ *
+ * This is the difference between the RDT timestamp in the first received packet
+ * and the current packet.
+ *
+ * At the receiver we have to deal with the jitter introduced by the network.
+ *
+ * recv_diff(i) = (Tri - Tr0)
+ *
+ * Tri : The time at the receiver at packet i
+ * Tr0 : The time at the receiver at the first packet
+ *
+ * Both of these values contain a jitter Ji, a jitter for packet i, so we can
+ * write:
+ *
+ * recv_diff(i) = (Cri + D + ni) - (Cr0 + D + n0))
+ *
+ * Cri : The time of the clock at the receiver for packet i
+ * D + ni : The jitter when receiving packet i
+ *
+ * We see that the network delay is irrelevant here as we can elliminate D:
+ *
+ * recv_diff(i) = (Cri + ni) - (Cr0 + n0))
+ *
+ * The drift is now expressed as:
+ *
+ * Drift(i) = recv_diff(i) - send_diff(i);
+ *
+ * We now keep the W latest values of Drift and find the minimum (this is the
+ * one with the lowest network jitter and thus the one which is least affected
+ * by it). We average this lowest value to smooth out the resulting network skew.
+ *
+ * Both the window and the weighting used for averaging influence the accuracy
+ * of the drift estimation. Finding the correct parameters turns out to be a
+ * compromise between accuracy and inertia.
+ *
+ * We use a 2 second window or up to 512 data points, which is statistically big
+ * enough to catch spikes (FIXME, detect spikes).
+ * We also use a rather large weighting factor (125) to smoothly adapt. During
+ * startup, when filling the window, we use a parabolic weighting factor, the
+ * more the window is filled, the faster we move to the detected possible skew.
+ *
+ * Returns: @time adjusted with the clock skew.
+ */
+static GstClockTime
+calculate_skew (RDTJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
+ guint32 clock_rate)
+{
+ guint64 ext_rtptime;
+ guint64 send_diff, recv_diff;
+ gint64 delta;
+ gint64 old;
+ gint pos, i;
+ GstClockTime gstrtptime, out_time;
+
+ //ext_rtptime = gst_rtp_buffer_ext_timestamp (&jbuf->ext_rtptime, rtptime);
+ ext_rtptime = rtptime;
+
+ gstrtptime = gst_util_uint64_scale_int (ext_rtptime, GST_SECOND, clock_rate);
+
+again:
+ /* first time, lock on to time and gstrtptime */
+ if (jbuf->base_time == -1)
+ jbuf->base_time = time;
+ if (jbuf->base_rtptime == -1)
+ jbuf->base_rtptime = gstrtptime;
+
+ if (gstrtptime >= jbuf->base_rtptime)
+ send_diff = gstrtptime - jbuf->base_rtptime;
+ else {
+ /* elapsed time at sender, timestamps can go backwards and thus be smaller
+ * than our base time, take a new base time in that case. */
+ GST_DEBUG ("backward timestamps at server, taking new base time");
+ jbuf->base_rtptime = gstrtptime;
+ jbuf->base_time = time;
+ send_diff = 0;
+ }
+
+ GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
+ GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
+ GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
+ GST_TIME_ARGS (send_diff));
+
+ if (jbuf->prev_send_diff != -1 && time != -1) {
+ gint64 delta_diff;
+
+ if (send_diff > jbuf->prev_send_diff)
+ delta_diff = send_diff - jbuf->prev_send_diff;
+ else
+ delta_diff = jbuf->prev_send_diff - send_diff;
+
+ /* server changed rtp timestamps too quickly, reset skew detection and start
+ * again. This value is sortof arbitrary and can be a bad measurement up if
+ * there are many packets missing because then we get a big gap that is
+ * unrelated to a timestamp switch. */
+ if (delta_diff > GST_SECOND) {
+ GST_DEBUG ("delta changed too quickly %" GST_TIME_FORMAT " reset skew",
+ GST_TIME_ARGS (delta_diff));
+ rdt_jitter_buffer_reset_skew (jbuf);
+ goto again;
+ }
+ }
+ jbuf->prev_send_diff = send_diff;
+
+ /* we don't have an arrival timestamp so we can't do skew detection. we
+ * should still apply a timestamp based on RDT timestamp and base_time */
+ if (time == -1)
+ goto no_skew;
+
+ /* elapsed time at receiver, includes the jitter */
+ recv_diff = time - jbuf->base_time;
+
+ GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", recv_diff %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (time), GST_TIME_ARGS (jbuf->base_time),
+ GST_TIME_ARGS (recv_diff));
+
+ /* measure the diff */
+ delta = ((gint64) recv_diff) - ((gint64) send_diff);
+
+ pos = jbuf->window_pos;
+
+ if (jbuf->window_filling) {
+ /* we are filling the window */
+ GST_DEBUG ("filling %d, delta %" G_GINT64_FORMAT, pos, delta);
+ jbuf->window[pos++] = delta;
+ /* calc the min delta we observed */
+ if (pos == 1 || delta < jbuf->window_min)
+ jbuf->window_min = delta;
+
+ if (send_diff >= MAX_TIME || pos >= MAX_WINDOW) {
+ jbuf->window_size = pos;
+
+ /* window filled */
+ GST_DEBUG ("min %" G_GINT64_FORMAT, jbuf->window_min);
+
+ /* the skew is now the min */
+ jbuf->skew = jbuf->window_min;
+ jbuf->window_filling = FALSE;
+ } else {
+ gint perc_time, perc_window, perc;
+
+ /* figure out how much we filled the window, this depends on the amount of
+ * time we have or the max number of points we keep. */
+ perc_time = send_diff * 100 / MAX_TIME;
+ perc_window = pos * 100 / MAX_WINDOW;
+ perc = MAX (perc_time, perc_window);
+
+ /* make a parabolic function, the closer we get to the MAX, the more value
+ * we give to the scaling factor of the new value */
+ perc = perc * perc;
+
+ /* quickly go to the min value when we are filling up, slowly when we are
+ * just starting because we're not sure it's a good value yet. */
+ jbuf->skew =
+ (perc * jbuf->window_min + ((10000 - perc) * jbuf->skew)) / 10000;
+ jbuf->window_size = pos + 1;
+ }
+ } else {
+ /* pick old value and store new value. We keep the previous value in order
+ * to quickly check if the min of the window changed */
+ old = jbuf->window[pos];
+ jbuf->window[pos++] = delta;
+
+ if (delta <= jbuf->window_min) {
+ /* if the new value we inserted is smaller or equal to the current min,
+ * it becomes the new min */
+ jbuf->window_min = delta;
+ } else if (old == jbuf->window_min) {
+ gint64 min = G_MAXINT64;
+
+ /* if we removed the old min, we have to find a new min */
+ for (i = 0; i < jbuf->window_size; i++) {
+ /* we found another value equal to the old min, we can stop searching now */
+ if (jbuf->window[i] == old) {
+ min = old;
+ break;
+ }
+ if (jbuf->window[i] < min)
+ min = jbuf->window[i];
+ }
+ jbuf->window_min = min;
+ }
+ /* average the min values */
+ jbuf->skew = (jbuf->window_min + (124 * jbuf->skew)) / 125;
+ GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT,
+ delta, jbuf->window_min);
+ }
+ /* wrap around in the window */
+ if (pos >= jbuf->window_size)
+ pos = 0;
+ jbuf->window_pos = pos;
+
+no_skew:
+ /* the output time is defined as the base timestamp plus the RDT time
+ * adjusted for the clock skew .*/
+ out_time = jbuf->base_time + send_diff + jbuf->skew;
+
+ GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
+ jbuf->skew, GST_TIME_ARGS (out_time));
+
+ return out_time;
+}
+
+/**
+ * rdt_jitter_buffer_insert:
+ * @jbuf: an #RDTJitterBuffer
+ * @buf: a buffer
+ * @time: a running_time when this buffer was received in nanoseconds
+ * @clock_rate: the clock-rate of the payload of @buf
+ * @tail: TRUE when the tail element changed.
+ *
+ * Inserts @buf into the packet queue of @jbuf. The sequence number of the
+ * packet will be used to sort the packets. This function takes ownerhip of
+ * @buf when the function returns %TRUE.
+ * @buf should have writable metadata when calling this function.
+ *
+ * Returns: %FALSE if a packet with the same number already existed.
+ */
+gboolean
+rdt_jitter_buffer_insert (RDTJitterBuffer * jbuf, GstBuffer * buf,
+ GstClockTime time, guint32 clock_rate, gboolean * tail)
+{
+ GList *list;
+ guint32 rtptime;
+ guint16 seqnum;
+ GstRDTPacket packet;
+ gboolean more;
+
+ g_return_val_if_fail (jbuf != NULL, FALSE);
+ g_return_val_if_fail (buf != NULL, FALSE);
+
+ more = gst_rdt_buffer_get_first_packet (buf, &packet);
+ /* programmer error */
+ g_return_val_if_fail (more == TRUE, FALSE);
+
+ seqnum = gst_rdt_packet_data_get_seq (&packet);
+ /* do skew calculation by measuring the difference between rtptime and the
+ * receive time, this function will retimestamp @buf with the skew corrected
+ * running time. */
+ rtptime = gst_rdt_packet_data_get_timestamp (&packet);
+
+ /* loop the list to skip strictly smaller seqnum buffers */
+ for (list = jbuf->packets->head; list; list = g_list_next (list)) {
+ guint16 qseq;
+ gint gap;
+
+ more =
+ gst_rdt_buffer_get_first_packet (GST_BUFFER_CAST (list->data), &packet);
+ /* programmer error */
+ g_return_val_if_fail (more == TRUE, FALSE);
+
+ qseq = gst_rdt_packet_data_get_seq (&packet);
+
+ /* compare the new seqnum to the one in the buffer */
+ gap = gst_rdt_buffer_compare_seqnum (seqnum, qseq);
+
+ /* we hit a packet with the same seqnum, notify a duplicate */
+ if (G_UNLIKELY (gap == 0))
+ goto duplicate;
+
+ /* seqnum > qseq, we can stop looking */
+ if (G_LIKELY (gap < 0))
+ break;
+ }
+
+
+ if (clock_rate) {
+ time = calculate_skew (jbuf, rtptime, time, clock_rate);
+ GST_BUFFER_TIMESTAMP (buf) = time;
+ }
+
+ if (list)
+ g_queue_insert_before (jbuf->packets, list, buf);
+ else
+ g_queue_push_tail (jbuf->packets, buf);
+
+ /* tail was changed when we did not find a previous packet, we set the return
+ * flag when requested. */
+ if (tail)
+ *tail = (list == NULL);
+
+ return TRUE;
+
+ /* ERRORS */
+duplicate:
+ {
+ GST_WARNING ("duplicate packet %d found", (gint) seqnum);
+ return FALSE;
+ }
+}
+
+/**
+ * rdt_jitter_buffer_pop:
+ * @jbuf: an #RDTJitterBuffer
+ *
+ * Pops the oldest buffer from the packet queue of @jbuf. The popped buffer will
+ * have its timestamp adjusted with the incomming running_time and the detected
+ * clock skew.
+ *
+ * Returns: a #GstBuffer or %NULL when there was no packet in the queue.
+ */
+GstBuffer *
+rdt_jitter_buffer_pop (RDTJitterBuffer * jbuf)
+{
+ GstBuffer *buf;
+
+ g_return_val_if_fail (jbuf != NULL, FALSE);
+
+ buf = g_queue_pop_tail (jbuf->packets);
+
+ return buf;
+}
+
+/**
+ * rdt_jitter_buffer_peek:
+ * @jbuf: an #RDTJitterBuffer
+ *
+ * Peek the oldest buffer from the packet queue of @jbuf. Register a callback
+ * with rdt_jitter_buffer_set_tail_changed() to be notified when an older packet
+ * was inserted in the queue.
+ *
+ * Returns: a #GstBuffer or %NULL when there was no packet in the queue.
+ */
+GstBuffer *
+rdt_jitter_buffer_peek (RDTJitterBuffer * jbuf)
+{
+ GstBuffer *buf;
+
+ g_return_val_if_fail (jbuf != NULL, FALSE);
+
+ buf = g_queue_peek_tail (jbuf->packets);
+
+ return buf;
+}
+
+/**
+ * rdt_jitter_buffer_flush:
+ * @jbuf: an #RDTJitterBuffer
+ *
+ * Flush all packets from the jitterbuffer.
+ */
+void
+rdt_jitter_buffer_flush (RDTJitterBuffer * jbuf)
+{
+ GstBuffer *buffer;
+
+ g_return_if_fail (jbuf != NULL);
+
+ while ((buffer = g_queue_pop_head (jbuf->packets)))
+ gst_buffer_unref (buffer);
+}
+
+/**
+ * rdt_jitter_buffer_num_packets:
+ * @jbuf: an #RDTJitterBuffer
+ *
+ * Get the number of packets currently in "jbuf.
+ *
+ * Returns: The number of packets in @jbuf.
+ */
+guint
+rdt_jitter_buffer_num_packets (RDTJitterBuffer * jbuf)
+{
+ g_return_val_if_fail (jbuf != NULL, 0);
+
+ return jbuf->packets->length;
+}
+
+/**
+ * rdt_jitter_buffer_get_ts_diff:
+ * @jbuf: an #RDTJitterBuffer
+ *
+ * Get the difference between the timestamps of first and last packet in the
+ * jitterbuffer.
+ *
+ * Returns: The difference expressed in the timestamp units of the packets.
+ */
+guint32
+rdt_jitter_buffer_get_ts_diff (RDTJitterBuffer * jbuf)
+{
+ guint64 high_ts, low_ts;
+ GstBuffer *high_buf, *low_buf;
+ guint32 result;
+
+ g_return_val_if_fail (jbuf != NULL, 0);
+
+ high_buf = g_queue_peek_head (jbuf->packets);
+ low_buf = g_queue_peek_tail (jbuf->packets);
+
+ if (!high_buf || !low_buf || high_buf == low_buf)
+ return 0;
+
+ //high_ts = gst_rtp_buffer_get_timestamp (high_buf);
+ //low_ts = gst_rtp_buffer_get_timestamp (low_buf);
+ high_ts = 0;
+ low_ts = 0;
+
+ /* it needs to work if ts wraps */
+ if (high_ts >= low_ts) {
+ result = (guint32) (high_ts - low_ts);
+ } else {
+ result = (guint32) (high_ts + G_MAXUINT32 + 1 - low_ts);
+ }
+ return result;
+}
diff --git a/gst/realmedia/rdtjitterbuffer.h b/gst/realmedia/rdtjitterbuffer.h
new file mode 100644
index 0000000..7eea5e6
--- /dev/null
+++ b/gst/realmedia/rdtjitterbuffer.h
@@ -0,0 +1,91 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __RDT_JITTER_BUFFER_H__
+#define __RDT_JITTER_BUFFER_H__
+
+#include <gst/gst.h>
+
+typedef struct _RDTJitterBuffer RDTJitterBuffer;
+typedef struct _RDTJitterBufferClass RDTJitterBufferClass;
+
+#define RDT_TYPE_JITTER_BUFFER (rdt_jitter_buffer_get_type())
+#define RDT_JITTER_BUFFER(src) (G_TYPE_CHECK_INSTANCE_CAST((src),RDT_TYPE_JITTER_BUFFER,RDTJitterBuffer))
+#define RDT_JITTER_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RDT_TYPE_JITTER_BUFFER,RDTJitterBufferClass))
+#define RDT_IS_JITTER_BUFFER(src) (G_TYPE_CHECK_INSTANCE_TYPE((src),RDT_TYPE_JITTER_BUFFER))
+#define RDT_IS_JITTER_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RDT_TYPE_JITTER_BUFFER))
+#define RDT_JITTER_BUFFER_CAST(src) ((RDTJitterBuffer *)(src))
+
+/**
+ * RTPTailChanged:
+ * @jbuf: an #RDTJitterBuffer
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when the tail buffer of @jbuf changed.
+ */
+typedef void (*RTPTailChanged) (RDTJitterBuffer *jbuf, gpointer user_data);
+
+#define RDT_JITTER_BUFFER_MAX_WINDOW 512
+/**
+ * RDTJitterBuffer:
+ *
+ * A JitterBuffer in the #RTPSession
+ */
+struct _RDTJitterBuffer {
+ GObject object;
+
+ GQueue *packets;
+
+ /* for calculating skew */
+ GstClockTime base_time;
+ GstClockTime base_rtptime;
+ guint64 ext_rtptime;
+ gint64 window[RDT_JITTER_BUFFER_MAX_WINDOW];
+ guint window_pos;
+ guint window_size;
+ gboolean window_filling;
+ gint64 window_min;
+ gint64 skew;
+ gint64 prev_send_diff;
+};
+
+struct _RDTJitterBufferClass {
+ GObjectClass parent_class;
+};
+
+GType rdt_jitter_buffer_get_type (void);
+
+/* managing lifetime */
+RDTJitterBuffer* rdt_jitter_buffer_new (void);
+
+void rdt_jitter_buffer_reset_skew (RDTJitterBuffer *jbuf);
+
+gboolean rdt_jitter_buffer_insert (RDTJitterBuffer *jbuf, GstBuffer *buf,
+ GstClockTime time,
+ guint32 clock_rate,
+ gboolean *tail);
+GstBuffer * rdt_jitter_buffer_peek (RDTJitterBuffer *jbuf);
+GstBuffer * rdt_jitter_buffer_pop (RDTJitterBuffer *jbuf);
+
+void rdt_jitter_buffer_flush (RDTJitterBuffer *jbuf);
+
+guint rdt_jitter_buffer_num_packets (RDTJitterBuffer *jbuf);
+guint32 rdt_jitter_buffer_get_ts_diff (RDTJitterBuffer *jbuf);
+
+#endif /* __RDT_JITTER_BUFFER_H__ */
diff --git a/gst/realmedia/rdtmanager.c b/gst/realmedia/rdtmanager.c
new file mode 100644
index 0000000..39c74b2
--- /dev/null
+++ b/gst/realmedia/rdtmanager.c
@@ -0,0 +1,1374 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ * <2013> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Element-Checklist-Version: 5 */
+
+/**
+ * SECTION:element-rdtmanager
+ * @see_also: GstRtspSrc
+ *
+ * A simple RTP session manager used internally by rtspsrc.
+ */
+
+/* #define HAVE_RTCP */
+
+#include "gstrdtbuffer.h"
+#include "rdtmanager.h"
+#include "rdtjitterbuffer.h"
+
+#include <gst/glib-compat-private.h>
+
+#include <stdio.h>
+
+GST_DEBUG_CATEGORY_STATIC (rdtmanager_debug);
+#define GST_CAT_DEFAULT (rdtmanager_debug)
+
+/* GstRDTManager signals and args */
+enum
+{
+ SIGNAL_REQUEST_PT_MAP,
+ SIGNAL_CLEAR_PT_MAP,
+
+ SIGNAL_ON_NEW_SSRC,
+ SIGNAL_ON_SSRC_COLLISION,
+ SIGNAL_ON_SSRC_VALIDATED,
+ SIGNAL_ON_SSRC_ACTIVE,
+ SIGNAL_ON_SSRC_SDES,
+ SIGNAL_ON_BYE_SSRC,
+ SIGNAL_ON_BYE_TIMEOUT,
+ SIGNAL_ON_TIMEOUT,
+ SIGNAL_ON_NPT_STOP,
+ LAST_SIGNAL
+};
+
+#define DEFAULT_LATENCY_MS 200
+
+enum
+{
+ PROP_0,
+ PROP_LATENCY
+};
+
+static GstStaticPadTemplate gst_rdt_manager_recv_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS ("application/x-rdt")
+ );
+
+static GstStaticPadTemplate gst_rdt_manager_recv_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS ("application/x-rtcp")
+ );
+
+static GstStaticPadTemplate gst_rdt_manager_recv_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%u_%u_%u",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("application/x-rdt")
+ );
+
+static GstStaticPadTemplate gst_rdt_manager_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
+ GST_PAD_SRC,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS ("application/x-rtcp")
+ );
+
+static void gst_rdt_manager_finalize (GObject * object);
+static void gst_rdt_manager_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_rdt_manager_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rdt_manager_query_src (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static gboolean gst_rdt_manager_src_activate_mode (GstPad * pad,
+ GstObject * parent, GstPadMode mode, gboolean active);
+
+static GstClock *gst_rdt_manager_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_rdt_manager_change_state (GstElement * element,
+ GstStateChange transition);
+static GstPad *gst_rdt_manager_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void gst_rdt_manager_release_pad (GstElement * element, GstPad * pad);
+
+static gboolean gst_rdt_manager_parse_caps (GstRDTManager * rdtmanager,
+ GstRDTManagerSession * session, GstCaps * caps);
+static gboolean gst_rdt_manager_event_rdt (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+
+static GstFlowReturn gst_rdt_manager_chain_rdt (GstPad * pad,
+ GstObject * parent, GstBuffer * buffer);
+static GstFlowReturn gst_rdt_manager_chain_rtcp (GstPad * pad,
+ GstObject * parent, GstBuffer * buffer);
+static void gst_rdt_manager_loop (GstPad * pad);
+
+static guint gst_rdt_manager_signals[LAST_SIGNAL] = { 0 };
+
+#define JBUF_LOCK(sess) (g_mutex_lock (&(sess)->jbuf_lock))
+
+#define JBUF_LOCK_CHECK(sess,label) G_STMT_START { \
+ JBUF_LOCK (sess); \
+ if (sess->srcresult != GST_FLOW_OK) \
+ goto label; \
+} G_STMT_END
+
+#define JBUF_UNLOCK(sess) (g_mutex_unlock (&(sess)->jbuf_lock))
+#define JBUF_WAIT(sess) (g_cond_wait (&(sess)->jbuf_cond, &(sess)->jbuf_lock))
+
+#define JBUF_WAIT_CHECK(sess,label) G_STMT_START { \
+ JBUF_WAIT(sess); \
+ if (sess->srcresult != GST_FLOW_OK) \
+ goto label; \
+} G_STMT_END
+
+#define JBUF_SIGNAL(sess) (g_cond_signal (&(sess)->jbuf_cond))
+
+/* Manages the receiving end of the packets.
+ *
+ * There is one such structure for each RTP session (audio/video/...).
+ * We get the RTP/RTCP packets and stuff them into the session manager.
+ */
+struct _GstRDTManagerSession
+{
+ /* session id */
+ gint id;
+ /* the parent bin */
+ GstRDTManager *dec;
+
+ gboolean active;
+ /* we only support one ssrc and one pt */
+ guint32 ssrc;
+ guint8 pt;
+ gint clock_rate;
+ GstCaps *caps;
+ gint64 clock_base;
+
+ GstSegment segment;
+
+ /* the last seqnum we pushed out */
+ guint32 last_popped_seqnum;
+ /* the next expected seqnum */
+ guint32 next_seqnum;
+ /* last output time */
+ GstClockTime last_out_time;
+
+ /* the pads of the session */
+ GstPad *recv_rtp_sink;
+ GstPad *recv_rtp_src;
+ GstPad *recv_rtcp_sink;
+ GstPad *rtcp_src;
+
+ GstFlowReturn srcresult;
+ gboolean blocked;
+ gboolean eos;
+ gboolean waiting;
+ gboolean discont;
+ GstClockID clock_id;
+
+ /* jitterbuffer, lock and cond */
+ RDTJitterBuffer *jbuf;
+ GMutex jbuf_lock;
+ GCond jbuf_cond;
+
+ /* some accounting */
+ guint64 num_late;
+ guint64 num_duplicates;
+};
+
+/* find a session with the given id */
+static GstRDTManagerSession *
+find_session_by_id (GstRDTManager * rdtmanager, gint id)
+{
+ GSList *walk;
+
+ for (walk = rdtmanager->sessions; walk; walk = g_slist_next (walk)) {
+ GstRDTManagerSession *sess = (GstRDTManagerSession *) walk->data;
+
+ if (sess->id == id)
+ return sess;
+ }
+ return NULL;
+}
+
+/* create a session with the given id */
+static GstRDTManagerSession *
+create_session (GstRDTManager * rdtmanager, gint id)
+{
+ GstRDTManagerSession *sess;
+
+ sess = g_new0 (GstRDTManagerSession, 1);
+ sess->id = id;
+ sess->dec = rdtmanager;
+ sess->jbuf = rdt_jitter_buffer_new ();
+ g_mutex_init (&sess->jbuf_lock);
+ g_cond_init (&sess->jbuf_cond);
+ rdtmanager->sessions = g_slist_prepend (rdtmanager->sessions, sess);
+
+ return sess;
+}
+
+static gboolean
+forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+ GstPad *srcpad = GST_PAD_CAST (user_data);
+
+ gst_pad_push_event (srcpad, gst_event_ref (*event));
+
+ return TRUE;
+}
+
+static gboolean
+activate_session (GstRDTManager * rdtmanager, GstRDTManagerSession * session,
+ guint32 ssrc, guint8 pt)
+{
+ GstPadTemplate *templ;
+ GstElementClass *klass;
+ gchar *name;
+ GstCaps *caps;
+ GValue ret = { 0 };
+ GValue args[3] = { {0}
+ , {0}
+ , {0}
+ };
+
+ GST_DEBUG_OBJECT (rdtmanager, "creating stream");
+
+ session->ssrc = ssrc;
+ session->pt = pt;
+
+ /* get pt map */
+ g_value_init (&args[0], GST_TYPE_ELEMENT);
+ g_value_set_object (&args[0], rdtmanager);
+ g_value_init (&args[1], G_TYPE_UINT);
+ g_value_set_uint (&args[1], session->id);
+ g_value_init (&args[2], G_TYPE_UINT);
+ g_value_set_uint (&args[2], pt);
+
+ g_value_init (&ret, GST_TYPE_CAPS);
+ g_value_set_boxed (&ret, NULL);
+
+ g_signal_emitv (args, gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP], 0,
+ &ret);
+
+ g_value_unset (&args[0]);
+ g_value_unset (&args[1]);
+ g_value_unset (&args[2]);
+ caps = (GstCaps *) g_value_dup_boxed (&ret);
+ g_value_unset (&ret);
+
+ if (caps)
+ gst_rdt_manager_parse_caps (rdtmanager, session, caps);
+
+ name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
+ klass = GST_ELEMENT_GET_CLASS (rdtmanager);
+ templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
+ session->recv_rtp_src = gst_pad_new_from_template (templ, name);
+ g_free (name);
+
+ gst_pad_set_element_private (session->recv_rtp_src, session);
+ gst_pad_set_query_function (session->recv_rtp_src, gst_rdt_manager_query_src);
+ gst_pad_set_activatemode_function (session->recv_rtp_src,
+ gst_rdt_manager_src_activate_mode);
+
+ gst_pad_set_active (session->recv_rtp_src, TRUE);
+
+ gst_pad_sticky_events_foreach (session->recv_rtp_sink, forward_sticky_events,
+ session->recv_rtp_src);
+ gst_pad_set_caps (session->recv_rtp_src, caps);
+ gst_caps_unref (caps);
+
+ gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtp_src);
+
+ return TRUE;
+}
+
+static void
+free_session (GstRDTManagerSession * session)
+{
+ g_object_unref (session->jbuf);
+ g_cond_clear (&session->jbuf_cond);
+ g_mutex_clear (&session->jbuf_lock);
+ g_free (session);
+}
+
+#define gst_rdt_manager_parent_class parent_class
+G_DEFINE_TYPE (GstRDTManager, gst_rdt_manager, GST_TYPE_ELEMENT);
+
+/* BOXED:UINT,UINT */
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+
+static void
+gst_rdt_manager_marshal_BOXED__UINT_UINT (GClosure * closure,
+ GValue * return_value,
+ guint n_param_values,
+ const GValue * param_values,
+ gpointer invocation_hint, gpointer marshal_data)
+{
+ typedef gpointer (*GMarshalFunc_BOXED__UINT_UINT) (gpointer data1,
+ guint arg_1, guint arg_2, gpointer data2);
+ register GMarshalFunc_BOXED__UINT_UINT callback;
+ register GCClosure *cc = (GCClosure *) closure;
+ register gpointer data1, data2;
+ gpointer v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback =
+ (GMarshalFunc_BOXED__UINT_UINT) (marshal_data ? marshal_data :
+ cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2), data2);
+
+ g_value_take_boxed (return_value, v_return);
+}
+
+static void
+gst_rdt_manager_marshal_VOID__UINT_UINT (GClosure * closure,
+ GValue * return_value,
+ guint n_param_values,
+ const GValue * param_values,
+ gpointer invocation_hint, gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
+ guint arg_1, guint arg_2, gpointer data2);
+ register GMarshalFunc_VOID__UINT_UINT callback;
+ register GCClosure *cc = (GCClosure *) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback =
+ (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data :
+ cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2), data2);
+}
+
+static void
+gst_rdt_manager_class_init (GstRDTManagerClass * g_class)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRDTManagerClass *klass;
+
+ klass = (GstRDTManagerClass *) g_class;
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_rdt_manager_finalize;
+ gobject_class->set_property = gst_rdt_manager_set_property;
+ gobject_class->get_property = gst_rdt_manager_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_LATENCY,
+ g_param_spec_uint ("latency", "Buffer latency in ms",
+ "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstRDTManager::request-pt-map:
+ * @rdtmanager: the object which received the signal
+ * @session: the session
+ * @pt: the pt
+ *
+ * Request the payload type as #GstCaps for @pt in @session.
+ */
+ gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP] =
+ g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, request_pt_map),
+ NULL, NULL, gst_rdt_manager_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
+ G_TYPE_UINT, G_TYPE_UINT);
+
+ /**
+ * GstRDTManager::clear-pt-map:
+ * @rtpbin: the object which received the signal
+ *
+ * Clear all previously cached pt-mapping obtained with
+ * GstRDTManager::request-pt-map.
+ */
+ gst_rdt_manager_signals[SIGNAL_CLEAR_PT_MAP] =
+ g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, clear_pt_map),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+ /**
+ * GstRDTManager::on-bye-ssrc:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ * @ssrc: the SSRC
+ *
+ * Notify of an SSRC that became inactive because of a BYE packet.
+ */
+ gst_rdt_manager_signals[SIGNAL_ON_BYE_SSRC] =
+ g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, on_bye_ssrc),
+ NULL, NULL, gst_rdt_manager_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
+ G_TYPE_UINT, G_TYPE_UINT);
+ /**
+ * GstRDTManager::on-bye-timeout:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ * @ssrc: the SSRC
+ *
+ * Notify of an SSRC that has timed out because of BYE
+ */
+ gst_rdt_manager_signals[SIGNAL_ON_BYE_TIMEOUT] =
+ g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, on_bye_timeout),
+ NULL, NULL, gst_rdt_manager_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
+ G_TYPE_UINT, G_TYPE_UINT);
+ /**
+ * GstRDTManager::on-timeout:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ * @ssrc: the SSRC
+ *
+ * Notify of an SSRC that has timed out
+ */
+ gst_rdt_manager_signals[SIGNAL_ON_TIMEOUT] =
+ g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, on_timeout),
+ NULL, NULL, gst_rdt_manager_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
+ G_TYPE_UINT, G_TYPE_UINT);
+
+ /**
+ * GstRDTManager::on-npt-stop:
+ * @rtpbin: the object which received the signal
+ * @session: the session
+ * @ssrc: the SSRC
+ *
+ * Notify that SSRC sender has sent data up to the configured NPT stop time.
+ */
+ gst_rdt_manager_signals[SIGNAL_ON_NPT_STOP] =
+ g_signal_new ("on-npt-stop", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, on_npt_stop),
+ NULL, NULL, gst_rdt_manager_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
+ G_TYPE_UINT, G_TYPE_UINT);
+
+
+ gstelement_class->provide_clock =
+ GST_DEBUG_FUNCPTR (gst_rdt_manager_provide_clock);
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_rdt_manager_change_state);
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_rdt_manager_request_new_pad);
+ gstelement_class->release_pad =
+ GST_DEBUG_FUNCPTR (gst_rdt_manager_release_pad);
+
+ /* sink pads */
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rdt_manager_recv_rtp_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rdt_manager_recv_rtcp_sink_template));
+ /* src pads */
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rdt_manager_recv_rtp_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rdt_manager_rtcp_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP Decoder",
+ "Codec/Parser/Network",
+ "Accepts raw RTP and RTCP packets and sends them forward",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rdtmanager_debug, "rdtmanager", 0, "RTP decoder");
+}
+
+static void
+gst_rdt_manager_init (GstRDTManager * rdtmanager)
+{
+ rdtmanager->provided_clock = gst_system_clock_obtain ();
+ rdtmanager->latency = DEFAULT_LATENCY_MS;
+ GST_OBJECT_FLAG_SET (rdtmanager, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+}
+
+static void
+gst_rdt_manager_finalize (GObject * object)
+{
+ GstRDTManager *rdtmanager;
+
+ rdtmanager = GST_RDT_MANAGER (object);
+
+ g_slist_foreach (rdtmanager->sessions, (GFunc) free_session, NULL);
+ g_slist_free (rdtmanager->sessions);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rdt_manager_query_src (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+ GstRDTManager *rdtmanager;
+ gboolean res;
+
+ rdtmanager = GST_RDT_MANAGER (parent);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ GstClockTime latency;
+
+ latency = rdtmanager->latency * GST_MSECOND;
+
+ /* we pretend to be live with a 3 second latency */
+ gst_query_set_latency (query, TRUE, latency, -1);
+
+ GST_DEBUG_OBJECT (rdtmanager, "reporting %" GST_TIME_FORMAT " of latency",
+ GST_TIME_ARGS (latency));
+ res = TRUE;
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, parent, query);
+ break;
+ }
+ return res;
+}
+
+static gboolean
+gst_rdt_manager_src_activate_mode (GstPad * pad, GstObject * parent,
+ GstPadMode mode, gboolean active)
+{
+ gboolean result;
+ GstRDTManager *rdtmanager;
+ GstRDTManagerSession *session;
+
+ session = gst_pad_get_element_private (pad);
+ rdtmanager = session->dec;
+
+ switch (mode) {
+ case GST_PAD_MODE_PUSH:
+ if (active) {
+ /* allow data processing */
+ JBUF_LOCK (session);
+ GST_DEBUG_OBJECT (rdtmanager, "Enabling pop on queue");
+ /* Mark as non flushing */
+ session->srcresult = GST_FLOW_OK;
+ gst_segment_init (&session->segment, GST_FORMAT_TIME);
+ session->last_popped_seqnum = -1;
+ session->last_out_time = -1;
+ session->next_seqnum = -1;
+ session->eos = FALSE;
+ JBUF_UNLOCK (session);
+
+ /* start pushing out buffers */
+ GST_DEBUG_OBJECT (rdtmanager, "Starting task on srcpad");
+ result =
+ gst_pad_start_task (pad, (GstTaskFunction) gst_rdt_manager_loop,
+ pad, NULL);
+ } else {
+ /* make sure all data processing stops ASAP */
+ JBUF_LOCK (session);
+ /* mark ourselves as flushing */
+ session->srcresult = GST_FLOW_FLUSHING;
+ GST_DEBUG_OBJECT (rdtmanager, "Disabling pop on queue");
+ /* this unblocks any waiting pops on the src pad task */
+ JBUF_SIGNAL (session);
+ /* unlock clock, we just unschedule, the entry will be released by
+ * the locking streaming thread. */
+ if (session->clock_id)
+ gst_clock_id_unschedule (session->clock_id);
+ JBUF_UNLOCK (session);
+
+ /* NOTE this will hardlock if the state change is called from the src pad
+ * task thread because we will _join() the thread. */
+ GST_DEBUG_OBJECT (rdtmanager, "Stopping task on srcpad");
+ result = gst_pad_stop_task (pad);
+ }
+ break;
+ default:
+ result = FALSE;
+ break;
+ }
+ return result;
+}
+
+static GstFlowReturn
+gst_rdt_manager_handle_data_packet (GstRDTManagerSession * session,
+ GstClockTime timestamp, GstRDTPacket * packet)
+{
+ GstRDTManager *rdtmanager;
+ guint16 seqnum;
+ gboolean tail;
+ GstFlowReturn res;
+ GstBuffer *buffer;
+
+ rdtmanager = session->dec;
+
+ res = GST_FLOW_OK;
+
+ seqnum = 0;
+ GST_DEBUG_OBJECT (rdtmanager,
+ "Received packet #%d at time %" GST_TIME_FORMAT, seqnum,
+ GST_TIME_ARGS (timestamp));
+
+ buffer = gst_rdt_packet_to_buffer (packet);
+
+ JBUF_LOCK_CHECK (session, out_flushing);
+
+ /* insert the packet into the queue now, FIXME, use seqnum */
+ if (!rdt_jitter_buffer_insert (session->jbuf, buffer, timestamp,
+ session->clock_rate, &tail))
+ goto duplicate;
+
+ /* signal addition of new buffer when the _loop is waiting. */
+ if (session->waiting)
+ JBUF_SIGNAL (session);
+
+finished:
+ JBUF_UNLOCK (session);
+
+ return res;
+
+ /* ERRORS */
+out_flushing:
+ {
+ res = session->srcresult;
+ GST_DEBUG_OBJECT (rdtmanager, "flushing %s", gst_flow_get_name (res));
+ gst_buffer_unref (buffer);
+ goto finished;
+ }
+duplicate:
+ {
+ GST_WARNING_OBJECT (rdtmanager, "Duplicate packet #%d detected, dropping",
+ seqnum);
+ session->num_duplicates++;
+ gst_buffer_unref (buffer);
+ goto finished;
+ }
+}
+
+static gboolean
+gst_rdt_manager_parse_caps (GstRDTManager * rdtmanager,
+ GstRDTManagerSession * session, GstCaps * caps)
+{
+ GstStructure *caps_struct;
+ guint val;
+
+ /* first parse the caps */
+ caps_struct = gst_caps_get_structure (caps, 0);
+
+ GST_DEBUG_OBJECT (rdtmanager, "got caps");
+
+ /* we need a clock-rate to convert the rtp timestamps to GStreamer time and to
+ * measure the amount of data in the buffer */
+ if (!gst_structure_get_int (caps_struct, "clock-rate", &session->clock_rate))
+ session->clock_rate = 1000;
+
+ if (session->clock_rate <= 0)
+ goto wrong_rate;
+
+ GST_DEBUG_OBJECT (rdtmanager, "got clock-rate %d", session->clock_rate);
+
+ /* gah, clock-base is uint. If we don't have a base, we will use the first
+ * buffer timestamp as the base time. This will screw up sync but it's better
+ * than nothing. */
+ if (gst_structure_get_uint (caps_struct, "clock-base", &val))
+ session->clock_base = val;
+ else
+ session->clock_base = -1;
+
+ GST_DEBUG_OBJECT (rdtmanager, "got clock-base %" G_GINT64_FORMAT,
+ session->clock_base);
+
+ /* first expected seqnum */
+ if (gst_structure_get_uint (caps_struct, "seqnum-base", &val))
+ session->next_seqnum = val;
+ else
+ session->next_seqnum = -1;
+
+ GST_DEBUG_OBJECT (rdtmanager, "got seqnum-base %d", session->next_seqnum);
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_rate:
+ {
+ GST_DEBUG_OBJECT (rdtmanager, "Invalid clock-rate %d", session->clock_rate);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rdt_manager_event_rdt (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstRDTManager *rdtmanager;
+ GstRDTManagerSession *session;
+ gboolean res;
+
+ rdtmanager = GST_RDT_MANAGER (parent);
+ /* find session */
+ session = gst_pad_get_element_private (pad);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ res = gst_rdt_manager_parse_caps (rdtmanager, session, caps);
+ gst_event_unref (event);
+ break;
+ }
+ default:
+ res = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+ return res;
+}
+
+static GstFlowReturn
+gst_rdt_manager_chain_rdt (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+ GstFlowReturn res;
+ GstRDTManager *rdtmanager;
+ GstRDTManagerSession *session;
+ GstClockTime timestamp;
+ GstRDTPacket packet;
+ guint32 ssrc;
+ guint8 pt;
+ gboolean more;
+
+ rdtmanager = GST_RDT_MANAGER (parent);
+
+ GST_DEBUG_OBJECT (rdtmanager, "got RDT packet");
+
+ ssrc = 0;
+ pt = 0;
+
+ GST_DEBUG_OBJECT (rdtmanager, "SSRC %08x, PT %d", ssrc, pt);
+
+ /* find session */
+ session = gst_pad_get_element_private (pad);
+
+ /* see if we have the pad */
+ if (!session->active) {
+ activate_session (rdtmanager, session, ssrc, pt);
+ session->active = TRUE;
+ }
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ GST_DEBUG_OBJECT (rdtmanager, "received discont");
+ session->discont = TRUE;
+ }
+
+ res = GST_FLOW_OK;
+
+ /* take the timestamp of the buffer. This is the time when the packet was
+ * received and is used to calculate jitter and clock skew. We will adjust
+ * this timestamp with the smoothed value after processing it in the
+ * jitterbuffer. */
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ /* bring to running time */
+ timestamp = gst_segment_to_running_time (&session->segment, GST_FORMAT_TIME,
+ timestamp);
+
+ more = gst_rdt_buffer_get_first_packet (buffer, &packet);
+ while (more) {
+ GstRDTType type;
+
+ type = gst_rdt_packet_get_type (&packet);
+ GST_DEBUG_OBJECT (rdtmanager, "Have packet of type %04x", type);
+
+ if (GST_RDT_IS_DATA_TYPE (type)) {
+ GST_DEBUG_OBJECT (rdtmanager, "We have a data packet");
+ res = gst_rdt_manager_handle_data_packet (session, timestamp, &packet);
+ } else {
+ switch (type) {
+ default:
+ GST_DEBUG_OBJECT (rdtmanager, "Ignoring packet");
+ break;
+ }
+ }
+ if (res != GST_FLOW_OK)
+ break;
+
+ more = gst_rdt_packet_move_to_next (&packet);
+ }
+
+ gst_buffer_unref (buffer);
+
+ return res;
+}
+
+/* push packets from the queue to the downstream demuxer */
+static void
+gst_rdt_manager_loop (GstPad * pad)
+{
+ GstRDTManager *rdtmanager;
+ GstRDTManagerSession *session;
+ GstBuffer *buffer;
+ GstFlowReturn result;
+
+ rdtmanager = GST_RDT_MANAGER (GST_PAD_PARENT (pad));
+
+ session = gst_pad_get_element_private (pad);
+
+ JBUF_LOCK_CHECK (session, flushing);
+ GST_DEBUG_OBJECT (rdtmanager, "Peeking item");
+ while (TRUE) {
+ /* always wait if we are blocked */
+ if (!session->blocked) {
+ /* if we have a packet, we can exit the loop and grab it */
+ if (rdt_jitter_buffer_num_packets (session->jbuf) > 0)
+ break;
+ /* no packets but we are EOS, do eos logic */
+ if (session->eos)
+ goto do_eos;
+ }
+ /* underrun, wait for packets or flushing now */
+ session->waiting = TRUE;
+ JBUF_WAIT_CHECK (session, flushing);
+ session->waiting = FALSE;
+ }
+
+ buffer = rdt_jitter_buffer_pop (session->jbuf);
+
+ GST_DEBUG_OBJECT (rdtmanager, "Got item %p", buffer);
+
+ if (session->discont) {
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+ session->discont = FALSE;
+ }
+
+ JBUF_UNLOCK (session);
+
+ result = gst_pad_push (session->recv_rtp_src, buffer);
+ if (result != GST_FLOW_OK)
+ goto pause;
+
+ return;
+
+ /* ERRORS */
+flushing:
+ {
+ GST_DEBUG_OBJECT (rdtmanager, "we are flushing");
+ gst_pad_pause_task (session->recv_rtp_src);
+ JBUF_UNLOCK (session);
+ return;
+ }
+do_eos:
+ {
+ /* store result, we are flushing now */
+ GST_DEBUG_OBJECT (rdtmanager, "We are EOS, pushing EOS downstream");
+ session->srcresult = GST_FLOW_EOS;
+ gst_pad_pause_task (session->recv_rtp_src);
+ gst_pad_push_event (session->recv_rtp_src, gst_event_new_eos ());
+ JBUF_UNLOCK (session);
+ return;
+ }
+pause:
+ {
+ GST_DEBUG_OBJECT (rdtmanager, "pausing task, reason %s",
+ gst_flow_get_name (result));
+
+ JBUF_LOCK (session);
+ /* store result */
+ session->srcresult = result;
+ /* we don't post errors or anything because upstream will do that for us
+ * when we pass the return value upstream. */
+ gst_pad_pause_task (session->recv_rtp_src);
+ JBUF_UNLOCK (session);
+ return;
+ }
+}
+
+static GstFlowReturn
+gst_rdt_manager_chain_rtcp (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer)
+{
+ GstRDTManager *src;
+
+#ifdef HAVE_RTCP
+ gboolean valid;
+ GstRTCPPacket packet;
+ gboolean more;
+#endif
+
+ src = GST_RDT_MANAGER (parent);
+
+ GST_DEBUG_OBJECT (src, "got rtcp packet");
+
+#ifdef HAVE_RTCP
+ valid = gst_rtcp_buffer_validate (buffer);
+ if (!valid)
+ goto bad_packet;
+
+ /* position on first packet */
+ more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
+ while (more) {
+ switch (gst_rtcp_packet_get_type (&packet)) {
+ case GST_RTCP_TYPE_SR:
+ {
+ guint32 ssrc, rtptime, packet_count, octet_count;
+ guint64 ntptime;
+ guint count, i;
+
+ gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
+ &packet_count, &octet_count);
+
+ GST_DEBUG_OBJECT (src,
+ "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
+ ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
+ octet_count);
+
+ count = gst_rtcp_packet_get_rb_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+ guint8 fractionlost;
+ gint32 packetslost;
+
+ gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+ &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+ GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+ ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+ packetslost, exthighestseq, jitter, lsr, dlsr);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_RR:
+ {
+ guint32 ssrc;
+ guint count, i;
+
+ ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
+
+ GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
+
+ count = gst_rtcp_packet_get_rb_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+ guint8 fractionlost;
+ gint32 packetslost;
+
+ gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+ &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+ GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+ ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+ packetslost, exthighestseq, jitter, lsr, dlsr);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_SDES:
+ {
+ guint chunks, i, j;
+ gboolean more_chunks, more_items;
+
+ chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
+ GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
+
+ more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
+ i = 0;
+ while (more_chunks) {
+ guint32 ssrc;
+
+ ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
+
+ GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
+
+ more_items = gst_rtcp_packet_sdes_first_item (&packet);
+ j = 0;
+ while (more_items) {
+ GstRTCPSDESType type;
+ guint8 len;
+ gchar *data;
+
+ gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
+
+ GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
+ type, len, data);
+
+ more_items = gst_rtcp_packet_sdes_next_item (&packet);
+ j++;
+ }
+ more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
+ i++;
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_BYE:
+ {
+ guint count, i;
+ gchar *reason;
+
+ reason = gst_rtcp_packet_bye_get_reason (&packet);
+ GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
+ GST_STR_NULL (reason));
+ g_free (reason);
+
+ count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc;
+
+
+ ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
+
+ GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_APP:
+ GST_DEBUG_OBJECT (src, "got APP packet");
+ break;
+ default:
+ GST_WARNING_OBJECT (src, "got unknown RTCP packet");
+ break;
+ }
+ more = gst_rtcp_packet_move_to_next (&packet);
+ }
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+
+bad_packet:
+ {
+ GST_WARNING_OBJECT (src, "got invalid RTCP packet");
+ return GST_FLOW_OK;
+ }
+#else
+ return GST_FLOW_OK;
+#endif
+}
+
+static void
+gst_rdt_manager_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRDTManager *src;
+
+ src = GST_RDT_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_LATENCY:
+ src->latency = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rdt_manager_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstRDTManager *src;
+
+ src = GST_RDT_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_LATENCY:
+ g_value_set_uint (value, src->latency);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstClock *
+gst_rdt_manager_provide_clock (GstElement * element)
+{
+ GstRDTManager *rdtmanager;
+
+ rdtmanager = GST_RDT_MANAGER (element);
+
+ return GST_CLOCK_CAST (gst_object_ref (rdtmanager->provided_clock));
+}
+
+static GstStateChangeReturn
+gst_rdt_manager_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ /* we're NO_PREROLL when going to PAUSED */
+ ret = GST_STATE_CHANGE_NO_PREROLL;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Create a pad for receiving RTP for the session in @name
+ */
+static GstPad *
+create_recv_rtp (GstRDTManager * rdtmanager, GstPadTemplate * templ,
+ const gchar * name)
+{
+ guint sessid;
+ GstRDTManagerSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
+ goto no_name;
+
+ GST_DEBUG_OBJECT (rdtmanager, "finding session %d", sessid);
+
+ /* get or create session */
+ session = find_session_by_id (rdtmanager, sessid);
+ if (!session) {
+ GST_DEBUG_OBJECT (rdtmanager, "creating session %d", sessid);
+ /* create session now */
+ session = create_session (rdtmanager, sessid);
+ if (session == NULL)
+ goto create_error;
+ }
+ /* check if pad was requested */
+ if (session->recv_rtp_sink != NULL)
+ goto existed;
+
+ GST_DEBUG_OBJECT (rdtmanager, "getting RTP sink pad");
+
+ session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (session->recv_rtp_sink, session);
+ gst_pad_set_event_function (session->recv_rtp_sink,
+ gst_rdt_manager_event_rdt);
+ gst_pad_set_chain_function (session->recv_rtp_sink,
+ gst_rdt_manager_chain_rdt);
+ gst_pad_set_active (session->recv_rtp_sink, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtp_sink);
+
+ return session->recv_rtp_sink;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rdtmanager: invalid name given");
+ return NULL;
+ }
+create_error:
+ {
+ /* create_session already warned */
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rdtmanager: recv_rtp pad already requested for session %d",
+ sessid);
+ return NULL;
+ }
+}
+
+/* Create a pad for receiving RTCP for the session in @name
+ */
+static GstPad *
+create_recv_rtcp (GstRDTManager * rdtmanager, GstPadTemplate * templ,
+ const gchar * name)
+{
+ guint sessid;
+ GstRDTManagerSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
+ goto no_name;
+
+ GST_DEBUG_OBJECT (rdtmanager, "finding session %d", sessid);
+
+ /* get the session, it must exist or we error */
+ session = find_session_by_id (rdtmanager, sessid);
+ if (!session)
+ goto no_session;
+
+ /* check if pad was requested */
+ if (session->recv_rtcp_sink != NULL)
+ goto existed;
+
+ GST_DEBUG_OBJECT (rdtmanager, "getting RTCP sink pad");
+
+ session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (session->recv_rtp_sink, session);
+ gst_pad_set_chain_function (session->recv_rtcp_sink,
+ gst_rdt_manager_chain_rtcp);
+ gst_pad_set_active (session->recv_rtcp_sink, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtcp_sink);
+
+ return session->recv_rtcp_sink;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rdtmanager: invalid name given");
+ return NULL;
+ }
+no_session:
+ {
+ g_warning ("rdtmanager: no session with id %d", sessid);
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rdtmanager: recv_rtcp pad already requested for session %d",
+ sessid);
+ return NULL;
+ }
+}
+
+/* Create a pad for sending RTCP for the session in @name
+ */
+static GstPad *
+create_rtcp (GstRDTManager * rdtmanager, GstPadTemplate * templ,
+ const gchar * name)
+{
+ guint sessid;
+ GstRDTManagerSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "rtcp_src_%u", &sessid) != 1)
+ goto no_name;
+
+ /* get or create session */
+ session = find_session_by_id (rdtmanager, sessid);
+ if (!session)
+ goto no_session;
+
+ /* check if pad was requested */
+ if (session->rtcp_src != NULL)
+ goto existed;
+
+ session->rtcp_src = gst_pad_new_from_template (templ, name);
+ gst_pad_set_active (session->rtcp_src, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->rtcp_src);
+
+ return session->rtcp_src;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rdtmanager: invalid name given");
+ return NULL;
+ }
+no_session:
+ {
+ g_warning ("rdtmanager: session with id %d does not exist", sessid);
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rdtmanager: rtcp_src pad already requested for session %d",
+ sessid);
+ return NULL;
+ }
+}
+
+/*
+ */
+static GstPad *
+gst_rdt_manager_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+ GstRDTManager *rdtmanager;
+ GstElementClass *klass;
+ GstPad *result;
+
+ g_return_val_if_fail (templ != NULL, NULL);
+ g_return_val_if_fail (GST_IS_RDT_MANAGER (element), NULL);
+
+ rdtmanager = GST_RDT_MANAGER (element);
+ klass = GST_ELEMENT_GET_CLASS (element);
+
+ /* figure out the template */
+ if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
+ result = create_recv_rtp (rdtmanager, templ, name);
+ } else if (templ == gst_element_class_get_pad_template (klass,
+ "recv_rtcp_sink_%u")) {
+ result = create_recv_rtcp (rdtmanager, templ, name);
+ } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%u")) {
+ result = create_rtcp (rdtmanager, templ, name);
+ } else
+ goto wrong_template;
+
+ return result;
+
+ /* ERRORS */
+wrong_template:
+ {
+ g_warning ("rdtmanager: this is not our template");
+ return NULL;
+ }
+}
+
+static void
+gst_rdt_manager_release_pad (GstElement * element, GstPad * pad)
+{
+}
+
+gboolean
+gst_rdt_manager_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rdtmanager",
+ GST_RANK_NONE, GST_TYPE_RDT_MANAGER);
+}
diff --git a/gst/realmedia/rdtmanager.h b/gst/realmedia/rdtmanager.h
new file mode 100644
index 0000000..053953c
--- /dev/null
+++ b/gst/realmedia/rdtmanager.h
@@ -0,0 +1,93 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RDT_MANAGER_H__
+#define __GST_RDT_MANAGER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RDT_MANAGER (gst_rdt_manager_get_type())
+#define GST_IS_RDT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RDT_MANAGER))
+#define GST_IS_RDT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RDT_MANAGER))
+#define GST_RDT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RDT_MANAGER, GstRDTManager))
+#define GST_RDT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RDT_MANAGER, GstRDTManagerClass))
+
+typedef struct _GstRDTManager GstRDTManager;
+typedef struct _GstRDTManagerClass GstRDTManagerClass;
+typedef struct _GstRDTManagerSession GstRDTManagerSession;
+
+struct _GstRDTManager {
+ GstElement element;
+
+ guint latency;
+ GSList *sessions;
+ GstClock *provided_clock;
+};
+
+struct _GstRDTManagerClass {
+ GstElementClass parent_class;
+
+ /* get the caps for pt */
+ GstCaps* (*request_pt_map) (GstRDTManager *rtpdec, guint session, guint pt);
+
+ void (*clear_pt_map) (GstRDTManager *rtpdec);
+
+ void (*on_new_ssrc) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_ssrc_collision) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_ssrc_validated) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_ssrc_active) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_ssrc_sdes) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_bye_ssrc) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_bye_timeout) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_timeout) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+ void (*on_npt_stop) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
+};
+
+GType gst_rdt_manager_get_type(void);
+
+gboolean gst_rdt_manager_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RDT_MANAGER_H__ */
diff --git a/gst/realmedia/realhash.c b/gst/realmedia/realhash.c
new file mode 100644
index 0000000..294f204
--- /dev/null
+++ b/gst/realmedia/realhash.c
@@ -0,0 +1,321 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* Element-Checklist-Version: 5 */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "_stdint.h"
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "realhash.h"
+
+void rtsp_ext_real_calc_response_and_checksum (char *response,
+ char *chksum, char *challenge);
+
+/*
+ * The following code has been copied from
+ * xine-lib-1.1.1/src/input/libreal/real.c.
+ */
+
+static const unsigned char xor_table[] = {
+ 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
+ 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
+ 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
+ 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
+ 0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00
+};
+
+#define LE_32(x) GST_READ_UINT32_LE(x)
+#define BE_32C(x,y) GST_WRITE_UINT32_BE(x,y)
+#define LE_32C(x,y) GST_WRITE_UINT32_LE(x,y)
+
+static void
+hash (char *field, char *param)
+{
+ uint32_t a, b, c, d;
+
+ /* fill variables */
+ a = LE_32 (field);
+ b = LE_32 (field + 4);
+ c = LE_32 (field + 8);
+ d = LE_32 (field + 12);
+
+ a = ((b & c) | (~b & d)) + LE_32 ((param + 0x00)) + a - 0x28955B88;
+ a = ((a << 0x07) | (a >> 0x19)) + b;
+ d = ((a & b) | (~a & c)) + LE_32 ((param + 0x04)) + d - 0x173848AA;
+ d = ((d << 0x0c) | (d >> 0x14)) + a;
+ c = ((d & a) | (~d & b)) + LE_32 ((param + 0x08)) + c + 0x242070DB;
+ c = ((c << 0x11) | (c >> 0x0f)) + d;
+ b = ((c & d) | (~c & a)) + LE_32 ((param + 0x0c)) + b - 0x3E423112;
+ b = ((b << 0x16) | (b >> 0x0a)) + c;
+ a = ((b & c) | (~b & d)) + LE_32 ((param + 0x10)) + a - 0x0A83F051;
+ a = ((a << 0x07) | (a >> 0x19)) + b;
+ d = ((a & b) | (~a & c)) + LE_32 ((param + 0x14)) + d + 0x4787C62A;
+ d = ((d << 0x0c) | (d >> 0x14)) + a;
+ c = ((d & a) | (~d & b)) + LE_32 ((param + 0x18)) + c - 0x57CFB9ED;
+ c = ((c << 0x11) | (c >> 0x0f)) + d;
+ b = ((c & d) | (~c & a)) + LE_32 ((param + 0x1c)) + b - 0x02B96AFF;
+ b = ((b << 0x16) | (b >> 0x0a)) + c;
+ a = ((b & c) | (~b & d)) + LE_32 ((param + 0x20)) + a + 0x698098D8;
+ a = ((a << 0x07) | (a >> 0x19)) + b;
+ d = ((a & b) | (~a & c)) + LE_32 ((param + 0x24)) + d - 0x74BB0851;
+ d = ((d << 0x0c) | (d >> 0x14)) + a;
+ c = ((d & a) | (~d & b)) + LE_32 ((param + 0x28)) + c - 0x0000A44F;
+ c = ((c << 0x11) | (c >> 0x0f)) + d;
+ b = ((c & d) | (~c & a)) + LE_32 ((param + 0x2C)) + b - 0x76A32842;
+ b = ((b << 0x16) | (b >> 0x0a)) + c;
+ a = ((b & c) | (~b & d)) + LE_32 ((param + 0x30)) + a + 0x6B901122;
+ a = ((a << 0x07) | (a >> 0x19)) + b;
+ d = ((a & b) | (~a & c)) + LE_32 ((param + 0x34)) + d - 0x02678E6D;
+ d = ((d << 0x0c) | (d >> 0x14)) + a;
+ c = ((d & a) | (~d & b)) + LE_32 ((param + 0x38)) + c - 0x5986BC72;
+ c = ((c << 0x11) | (c >> 0x0f)) + d;
+ b = ((c & d) | (~c & a)) + LE_32 ((param + 0x3c)) + b + 0x49B40821;
+ b = ((b << 0x16) | (b >> 0x0a)) + c;
+
+ a = ((b & d) | (~d & c)) + LE_32 ((param + 0x04)) + a - 0x09E1DA9E;
+ a = ((a << 0x05) | (a >> 0x1b)) + b;
+ d = ((a & c) | (~c & b)) + LE_32 ((param + 0x18)) + d - 0x3FBF4CC0;
+ d = ((d << 0x09) | (d >> 0x17)) + a;
+ c = ((d & b) | (~b & a)) + LE_32 ((param + 0x2c)) + c + 0x265E5A51;
+ c = ((c << 0x0e) | (c >> 0x12)) + d;
+ b = ((c & a) | (~a & d)) + LE_32 ((param + 0x00)) + b - 0x16493856;
+ b = ((b << 0x14) | (b >> 0x0c)) + c;
+ a = ((b & d) | (~d & c)) + LE_32 ((param + 0x14)) + a - 0x29D0EFA3;
+ a = ((a << 0x05) | (a >> 0x1b)) + b;
+ d = ((a & c) | (~c & b)) + LE_32 ((param + 0x28)) + d + 0x02441453;
+ d = ((d << 0x09) | (d >> 0x17)) + a;
+ c = ((d & b) | (~b & a)) + LE_32 ((param + 0x3c)) + c - 0x275E197F;
+ c = ((c << 0x0e) | (c >> 0x12)) + d;
+ b = ((c & a) | (~a & d)) + LE_32 ((param + 0x10)) + b - 0x182C0438;
+ b = ((b << 0x14) | (b >> 0x0c)) + c;
+ a = ((b & d) | (~d & c)) + LE_32 ((param + 0x24)) + a + 0x21E1CDE6;
+ a = ((a << 0x05) | (a >> 0x1b)) + b;
+ d = ((a & c) | (~c & b)) + LE_32 ((param + 0x38)) + d - 0x3CC8F82A;
+ d = ((d << 0x09) | (d >> 0x17)) + a;
+ c = ((d & b) | (~b & a)) + LE_32 ((param + 0x0c)) + c - 0x0B2AF279;
+ c = ((c << 0x0e) | (c >> 0x12)) + d;
+ b = ((c & a) | (~a & d)) + LE_32 ((param + 0x20)) + b + 0x455A14ED;
+ b = ((b << 0x14) | (b >> 0x0c)) + c;
+ a = ((b & d) | (~d & c)) + LE_32 ((param + 0x34)) + a - 0x561C16FB;
+ a = ((a << 0x05) | (a >> 0x1b)) + b;
+ d = ((a & c) | (~c & b)) + LE_32 ((param + 0x08)) + d - 0x03105C08;
+ d = ((d << 0x09) | (d >> 0x17)) + a;
+ c = ((d & b) | (~b & a)) + LE_32 ((param + 0x1c)) + c + 0x676F02D9;
+ c = ((c << 0x0e) | (c >> 0x12)) + d;
+ b = ((c & a) | (~a & d)) + LE_32 ((param + 0x30)) + b - 0x72D5B376;
+ b = ((b << 0x14) | (b >> 0x0c)) + c;
+
+ a = (b ^ c ^ d) + LE_32 ((param + 0x14)) + a - 0x0005C6BE;
+ a = ((a << 0x04) | (a >> 0x1c)) + b;
+ d = (a ^ b ^ c) + LE_32 ((param + 0x20)) + d - 0x788E097F;
+ d = ((d << 0x0b) | (d >> 0x15)) + a;
+ c = (d ^ a ^ b) + LE_32 ((param + 0x2c)) + c + 0x6D9D6122;
+ c = ((c << 0x10) | (c >> 0x10)) + d;
+ b = (c ^ d ^ a) + LE_32 ((param + 0x38)) + b - 0x021AC7F4;
+ b = ((b << 0x17) | (b >> 0x09)) + c;
+ a = (b ^ c ^ d) + LE_32 ((param + 0x04)) + a - 0x5B4115BC;
+ a = ((a << 0x04) | (a >> 0x1c)) + b;
+ d = (a ^ b ^ c) + LE_32 ((param + 0x10)) + d + 0x4BDECFA9;
+ d = ((d << 0x0b) | (d >> 0x15)) + a;
+ c = (d ^ a ^ b) + LE_32 ((param + 0x1c)) + c - 0x0944B4A0;
+ c = ((c << 0x10) | (c >> 0x10)) + d;
+ b = (c ^ d ^ a) + LE_32 ((param + 0x28)) + b - 0x41404390;
+ b = ((b << 0x17) | (b >> 0x09)) + c;
+ a = (b ^ c ^ d) + LE_32 ((param + 0x34)) + a + 0x289B7EC6;
+ a = ((a << 0x04) | (a >> 0x1c)) + b;
+ d = (a ^ b ^ c) + LE_32 ((param + 0x00)) + d - 0x155ED806;
+ d = ((d << 0x0b) | (d >> 0x15)) + a;
+ c = (d ^ a ^ b) + LE_32 ((param + 0x0c)) + c - 0x2B10CF7B;
+ c = ((c << 0x10) | (c >> 0x10)) + d;
+ b = (c ^ d ^ a) + LE_32 ((param + 0x18)) + b + 0x04881D05;
+ b = ((b << 0x17) | (b >> 0x09)) + c;
+ a = (b ^ c ^ d) + LE_32 ((param + 0x24)) + a - 0x262B2FC7;
+ a = ((a << 0x04) | (a >> 0x1c)) + b;
+ d = (a ^ b ^ c) + LE_32 ((param + 0x30)) + d - 0x1924661B;
+ d = ((d << 0x0b) | (d >> 0x15)) + a;
+ c = (d ^ a ^ b) + LE_32 ((param + 0x3c)) + c + 0x1fa27cf8;
+ c = ((c << 0x10) | (c >> 0x10)) + d;
+ b = (c ^ d ^ a) + LE_32 ((param + 0x08)) + b - 0x3B53A99B;
+ b = ((b << 0x17) | (b >> 0x09)) + c;
+
+ a = ((~d | b) ^ c) + LE_32 ((param + 0x00)) + a - 0x0BD6DDBC;
+ a = ((a << 0x06) | (a >> 0x1a)) + b;
+ d = ((~c | a) ^ b) + LE_32 ((param + 0x1c)) + d + 0x432AFF97;
+ d = ((d << 0x0a) | (d >> 0x16)) + a;
+ c = ((~b | d) ^ a) + LE_32 ((param + 0x38)) + c - 0x546BDC59;
+ c = ((c << 0x0f) | (c >> 0x11)) + d;
+ b = ((~a | c) ^ d) + LE_32 ((param + 0x14)) + b - 0x036C5FC7;
+ b = ((b << 0x15) | (b >> 0x0b)) + c;
+ a = ((~d | b) ^ c) + LE_32 ((param + 0x30)) + a + 0x655B59C3;
+ a = ((a << 0x06) | (a >> 0x1a)) + b;
+ d = ((~c | a) ^ b) + LE_32 ((param + 0x0C)) + d - 0x70F3336E;
+ d = ((d << 0x0a) | (d >> 0x16)) + a;
+ c = ((~b | d) ^ a) + LE_32 ((param + 0x28)) + c - 0x00100B83;
+ c = ((c << 0x0f) | (c >> 0x11)) + d;
+ b = ((~a | c) ^ d) + LE_32 ((param + 0x04)) + b - 0x7A7BA22F;
+ b = ((b << 0x15) | (b >> 0x0b)) + c;
+ a = ((~d | b) ^ c) + LE_32 ((param + 0x20)) + a + 0x6FA87E4F;
+ a = ((a << 0x06) | (a >> 0x1a)) + b;
+ d = ((~c | a) ^ b) + LE_32 ((param + 0x3c)) + d - 0x01D31920;
+ d = ((d << 0x0a) | (d >> 0x16)) + a;
+ c = ((~b | d) ^ a) + LE_32 ((param + 0x18)) + c - 0x5CFEBCEC;
+ c = ((c << 0x0f) | (c >> 0x11)) + d;
+ b = ((~a | c) ^ d) + LE_32 ((param + 0x34)) + b + 0x4E0811A1;
+ b = ((b << 0x15) | (b >> 0x0b)) + c;
+ a = ((~d | b) ^ c) + LE_32 ((param + 0x10)) + a - 0x08AC817E;
+ a = ((a << 0x06) | (a >> 0x1a)) + b;
+ d = ((~c | a) ^ b) + LE_32 ((param + 0x2c)) + d - 0x42C50DCB;
+ d = ((d << 0x0a) | (d >> 0x16)) + a;
+ c = ((~b | d) ^ a) + LE_32 ((param + 0x08)) + c + 0x2AD7D2BB;
+ c = ((c << 0x0f) | (c >> 0x11)) + d;
+ b = ((~a | c) ^ d) + LE_32 ((param + 0x24)) + b - 0x14792C6F;
+ b = ((b << 0x15) | (b >> 0x0b)) + c;
+
+ a += LE_32 (field);
+ b += LE_32 (field + 4);
+ c += LE_32 (field + 8);
+ d += LE_32 (field + 12);
+
+ LE_32C (field, a);
+ LE_32C (field + 4, b);
+ LE_32C (field + 8, c);
+ LE_32C (field + 12, d);
+}
+
+static void
+call_hash (char *key, char *challenge, int len)
+{
+ uint8_t *ptr1, *ptr2;
+ uint32_t a, b, c, d, tmp;
+
+ ptr1 = (uint8_t *) (key + 16);
+ ptr2 = (uint8_t *) (key + 20);
+
+ a = LE_32 (ptr1);
+ b = (a >> 3) & 0x3f;
+ a += len * 8;
+ LE_32C (ptr1, a);
+
+ if (a < (len << 3))
+ ptr2 += 4;
+
+ tmp = LE_32 (ptr2) + (len >> 0x1d);
+ LE_32C (ptr2, tmp);
+ a = 64 - b;
+ c = 0;
+ if (a <= len) {
+
+ memcpy (key + b + 24, challenge, a);
+ hash (key, key + 24);
+ c = a;
+ d = c + 0x3f;
+
+ while (d < len) {
+ hash (key, challenge + d - 0x3f);
+ d += 64;
+ c += 64;
+ }
+ b = 0;
+ }
+
+ memcpy (key + b + 24, challenge + c, len - c);
+}
+
+void
+gst_rtsp_ext_real_calc_response_and_checksum (char *response, char *chksum,
+ char *challenge)
+{
+ int ch_len, table_len, resp_len;
+ int i;
+ char *ptr;
+ char buf[128];
+ char field[128];
+ char zres[20];
+ char buf1[128];
+ char buf2[128];
+
+ /* initialize return values */
+ memset (response, 0, 64);
+ memset (chksum, 0, 34);
+
+ /* initialize buffer */
+ memset (buf, 0, 128);
+ ptr = buf;
+ BE_32C (ptr, 0xa1e9149d);
+ ptr += 4;
+ BE_32C (ptr, 0x0e6b3b59);
+ ptr += 4;
+
+ if ((ch_len = MIN (strlen (challenge), 56)) == 40) {
+ challenge[32] = 0;
+ ch_len = 32;
+ }
+ memcpy (ptr, challenge, ch_len);
+
+ /* xor challenge bytewise with xor_table */
+ table_len = MIN (strlen ((char *) xor_table), 56);
+ for (i = 0; i < table_len; i++)
+ ptr[i] = ptr[i] ^ xor_table[i];
+
+ /* initialize our field */
+ BE_32C (field, 0x01234567);
+ BE_32C (field + 4, 0x89ABCDEF);
+ BE_32C (field + 8, 0xFEDCBA98);
+ BE_32C (field + 12, 0x76543210);
+ BE_32C (field + 16, 0x00000000);
+ BE_32C (field + 20, 0x00000000);
+
+ /* calculate response */
+ call_hash (field, buf, 64);
+ memset (buf1, 0, 64);
+ *buf1 = 128;
+ memcpy (buf2, field + 16, 8);
+ i = (LE_32 ((buf2)) >> 3) & 0x3f;
+ if (i < 56)
+ i = 56 - i;
+ else
+ i = 120 - i;
+ call_hash (field, buf1, i);
+ call_hash (field, buf2, 8);
+ memcpy (zres, field, 16);
+
+ /* convert zres to ascii string */
+ for (i = 0; i < 16; i++) {
+ char a, b;
+
+ a = (zres[i] >> 4) & 15;
+ b = zres[i] & 15;
+
+ response[i * 2] = ((a < 10) ? (a + 48) : (a + 87)) & 255;
+ response[i * 2 + 1] = ((b < 10) ? (b + 48) : (b + 87)) & 255;
+ }
+
+ /* add tail */
+ resp_len = strlen (response);
+ strcpy (&response[resp_len], "01d0a8e3");
+
+ /* calculate checksum */
+ for (i = 0; i < resp_len / 4; i++)
+ chksum[i] = response[i * 4];
+}
diff --git a/gst/realmedia/realhash.h b/gst/realmedia/realhash.h
new file mode 100644
index 0000000..40b6500
--- /dev/null
+++ b/gst/realmedia/realhash.h
@@ -0,0 +1,31 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_HASH_H__
+#define __GST_RTSP_HASH_H__
+
+G_BEGIN_DECLS
+
+void
+gst_rtsp_ext_real_calc_response_and_checksum (char *response, char *chksum,
+ char *challenge);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_HASH_H__ */
diff --git a/gst/realmedia/realmedia.c b/gst/realmedia/realmedia.c
new file mode 100644
index 0000000..2b05f54
--- /dev/null
+++ b/gst/realmedia/realmedia.c
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rmdemux.h"
+#include "rademux.h"
+#include "rdtdepay.h"
+#include "rdtmanager.h"
+#include "rtspreal.h"
+#include "pnmsrc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_rmdemux_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rademux_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rdt_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rdt_manager_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtsp_real_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_pnm_src_plugin_init (plugin))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ realmedia,
+ "RealMedia support plugins",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/realmedia/rmdemux.c b/gst/realmedia/rmdemux.c
new file mode 100644
index 0000000..d4afae4
--- /dev/null
+++ b/gst/realmedia/rmdemux.c
@@ -0,0 +1,2586 @@
+/* GStreamer RealMedia demuxer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
+ * Copyright (C) <2004> Stephane Loeuillet <gstreamer@leroutier.net>
+ * Copyright (C) <2005> Owen Fraser-Green <owen@discobabe.net>
+ * Copyright (C) <2005> Michael Smith <fluendo.com>
+ * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rmdemux.h"
+#include "rmutils.h"
+
+#include <string.h>
+#include <ctype.h>
+
+#define RMDEMUX_GUINT32_GET(a) GST_READ_UINT32_BE(a)
+#define RMDEMUX_GUINT16_GET(a) GST_READ_UINT16_BE(a)
+#define RMDEMUX_FOURCC_GET(a) GST_READ_UINT32_LE(a)
+#define HEADER_SIZE 10
+#define DATA_SIZE 8
+
+#define MAX_FRAGS 256
+
+static const guint8 sipr_subpk_size[4] = { 29, 19, 37, 20 };
+
+typedef struct _GstRMDemuxIndex GstRMDemuxIndex;
+
+struct _GstRMDemuxStream
+{
+ guint32 subtype;
+ guint32 fourcc;
+ guint32 subformat;
+ guint32 format;
+
+ int id;
+ GstPad *pad;
+ gboolean discont;
+ int timescale;
+
+ int sample_index;
+ GstRMDemuxIndex *index;
+ int index_length;
+ gint framerate_numerator;
+ gint framerate_denominator;
+ guint32 seek_offset;
+
+ guint16 width;
+ guint16 height;
+ guint16 flavor;
+ guint16 rate; /* samplerate */
+ guint16 n_channels; /* channels */
+ guint16 sample_width; /* bits_per_sample */
+ guint16 leaf_size; /* subpacket_size */
+ guint32 packet_size; /* coded_frame_size */
+ guint16 version;
+ guint32 extra_data_size; /* codec_data_length */
+ guint8 *extra_data; /* extras */
+ guint32 bitrate;
+
+ gboolean needs_descrambling;
+ guint subpackets_needed; /* subpackets needed for descrambling */
+ GPtrArray *subpackets; /* array containing subpacket GstBuffers */
+
+ /* Variables needed for fixing timestamps. */
+ GstClockTime next_ts, last_ts;
+ guint16 next_seq, last_seq;
+
+ gint frag_seqnum;
+ gint frag_subseq;
+ guint frag_length;
+ guint frag_current;
+ guint frag_count;
+ guint frag_offset[MAX_FRAGS];
+ GstAdapter *adapter;
+
+ GstTagList *pending_tags;
+};
+
+struct _GstRMDemuxIndex
+{
+ guint32 offset;
+ GstClockTime timestamp;
+};
+
+static GstStaticPadTemplate gst_rmdemux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/vnd.rn-realmedia")
+ );
+
+static GstStaticPadTemplate gst_rmdemux_videosrc_template =
+GST_STATIC_PAD_TEMPLATE ("video_%u",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_rmdemux_audiosrc_template =
+GST_STATIC_PAD_TEMPLATE ("audio_%u",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (rmdemux_debug);
+#define GST_CAT_DEFAULT rmdemux_debug
+
+static GstElementClass *parent_class = NULL;
+
+static void gst_rmdemux_class_init (GstRMDemuxClass * klass);
+static void gst_rmdemux_base_init (GstRMDemuxClass * klass);
+static void gst_rmdemux_init (GstRMDemux * rmdemux);
+static void gst_rmdemux_finalize (GObject * object);
+static GstStateChangeReturn gst_rmdemux_change_state (GstElement * element,
+ GstStateChange transition);
+static GstFlowReturn gst_rmdemux_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+static void gst_rmdemux_loop (GstPad * pad);
+static gboolean gst_rmdemux_sink_activate (GstPad * sinkpad,
+ GstObject * parent);
+static gboolean gst_rmdemux_sink_activate_mode (GstPad * sinkpad,
+ GstObject * parent, GstPadMode mode, gboolean active);
+static gboolean gst_rmdemux_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static gboolean gst_rmdemux_src_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static void gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event);
+static gboolean gst_rmdemux_src_query (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static gboolean gst_rmdemux_perform_seek (GstRMDemux * rmdemux,
+ GstEvent * event);
+
+static void gst_rmdemux_parse__rmf (GstRMDemux * rmdemux, const guint8 * data,
+ int length);
+static void gst_rmdemux_parse_prop (GstRMDemux * rmdemux, const guint8 * data,
+ int length);
+static void gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux,
+ const guint8 * data, int length);
+static guint gst_rmdemux_parse_indx (GstRMDemux * rmdemux, const guint8 * data,
+ int length);
+static void gst_rmdemux_parse_data (GstRMDemux * rmdemux, const guint8 * data,
+ int length);
+static void gst_rmdemux_parse_cont (GstRMDemux * rmdemux, const guint8 * data,
+ int length);
+static GstFlowReturn gst_rmdemux_parse_packet (GstRMDemux * rmdemux,
+ GstBuffer * in, guint16 version);
+static void gst_rmdemux_parse_indx_data (GstRMDemux * rmdemux,
+ const guint8 * data, int length);
+static void gst_rmdemux_stream_clear_cached_subpackets (GstRMDemux * rmdemux,
+ GstRMDemuxStream * stream);
+static GstRMDemuxStream *gst_rmdemux_get_stream_by_id (GstRMDemux * rmdemux,
+ int id);
+
+static GType
+gst_rmdemux_get_type (void)
+{
+ static GType rmdemux_type = 0;
+
+ if (!rmdemux_type) {
+ static const GTypeInfo rmdemux_info = {
+ sizeof (GstRMDemuxClass),
+ (GBaseInitFunc) gst_rmdemux_base_init, NULL,
+ (GClassInitFunc) gst_rmdemux_class_init,
+ NULL, NULL, sizeof (GstRMDemux), 0,
+ (GInstanceInitFunc) gst_rmdemux_init,
+ };
+
+ rmdemux_type =
+ g_type_register_static (GST_TYPE_ELEMENT, "GstRMDemux", &rmdemux_info,
+ 0);
+ }
+ return rmdemux_type;
+}
+
+static void
+gst_rmdemux_base_init (GstRMDemuxClass * klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rmdemux_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rmdemux_videosrc_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rmdemux_audiosrc_template));
+ gst_element_class_set_static_metadata (element_class, "RealMedia Demuxer",
+ "Codec/Demuxer",
+ "Demultiplex a RealMedia file into audio and video streams",
+ "David Schleef <ds@schleef.org>");
+}
+
+static void
+gst_rmdemux_class_init (GstRMDemuxClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rmdemux_change_state);
+
+ GST_DEBUG_CATEGORY_INIT (rmdemux_debug, "rmdemux",
+ 0, "Demuxer for Realmedia streams");
+
+ gobject_class->finalize = gst_rmdemux_finalize;
+}
+
+static void
+gst_rmdemux_finalize (GObject * object)
+{
+ GstRMDemux *rmdemux = GST_RMDEMUX (object);
+
+ if (rmdemux->adapter) {
+ g_object_unref (rmdemux->adapter);
+ rmdemux->adapter = NULL;
+ }
+ if (rmdemux->flowcombiner) {
+ gst_flow_combiner_free (rmdemux->flowcombiner);
+ rmdemux->flowcombiner = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+gst_rmdemux_init (GstRMDemux * rmdemux)
+{
+ rmdemux->sinkpad =
+ gst_pad_new_from_static_template (&gst_rmdemux_sink_template, "sink");
+ gst_pad_set_event_function (rmdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rmdemux_sink_event));
+ gst_pad_set_chain_function (rmdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rmdemux_chain));
+ gst_pad_set_activate_function (rmdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rmdemux_sink_activate));
+ gst_pad_set_activatemode_function (rmdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rmdemux_sink_activate_mode));
+
+ gst_element_add_pad (GST_ELEMENT (rmdemux), rmdemux->sinkpad);
+
+ rmdemux->adapter = gst_adapter_new ();
+ rmdemux->first_ts = GST_CLOCK_TIME_NONE;
+ rmdemux->base_ts = GST_CLOCK_TIME_NONE;
+ rmdemux->need_newsegment = TRUE;
+ rmdemux->have_group_id = FALSE;
+ rmdemux->group_id = G_MAXUINT;
+ rmdemux->flowcombiner = gst_flow_combiner_new ();
+
+ gst_rm_utils_run_tests ();
+}
+
+static gboolean
+gst_rmdemux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ gboolean ret;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+ return ret;
+}
+
+static gboolean
+gst_rmdemux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ gboolean ret = TRUE;
+
+ GstRMDemux *rmdemux = GST_RMDEMUX (parent);
+
+ GST_LOG_OBJECT (rmdemux, "handling src event");
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ {
+ gboolean running;
+
+ GST_LOG_OBJECT (rmdemux, "Event on src: SEEK");
+ /* can't seek if we are not seekable, FIXME could pass the
+ * seek query upstream after converting it to bytes using
+ * the average bitrate of the stream. */
+ if (!rmdemux->seekable) {
+ ret = FALSE;
+ GST_DEBUG ("seek on non seekable stream");
+ goto done_unref;
+ }
+
+ GST_OBJECT_LOCK (rmdemux);
+ /* check if we can do the seek now */
+ running = rmdemux->running;
+ GST_OBJECT_UNLOCK (rmdemux);
+
+ /* now do the seek */
+ if (running) {
+ ret = gst_rmdemux_perform_seek (rmdemux, event);
+ } else
+ ret = TRUE;
+
+ gst_event_unref (event);
+ break;
+ }
+ default:
+ GST_LOG_OBJECT (rmdemux, "Event on src: type=%d", GST_EVENT_TYPE (event));
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+
+done_unref:
+ GST_DEBUG ("error handling event");
+ gst_event_unref (event);
+ return ret;
+}
+
+/* Validate that this looks like a reasonable point to seek to */
+static gboolean
+gst_rmdemux_validate_offset (GstRMDemux * rmdemux)
+{
+ GstBuffer *buffer;
+ GstFlowReturn flowret;
+ guint16 version, length;
+ gboolean ret = TRUE;
+ GstMapInfo map;
+
+ buffer = NULL;
+ flowret = gst_pad_pull_range (rmdemux->sinkpad, rmdemux->offset, 4, &buffer);
+
+ if (flowret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (rmdemux, "Failed to pull data at offset %d",
+ rmdemux->offset);
+ return FALSE;
+ }
+ /* TODO: Can we also be seeking to a 'DATA' chunk header? Check this.
+ * Also, for the case we currently handle, can we check any more? It's pretty
+ * sucky to not be validating a little more heavily than this... */
+ /* This should now be the start of a data packet header. That begins with
+ * a 2-byte 'version' field, which has to be 0 or 1, then a length. I'm not
+ * certain what values are valid for length, but it must always be at least
+ * 4 bytes, and we can check that it won't take us past our known total size
+ */
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ version = RMDEMUX_GUINT16_GET (map.data);
+ if (version != 0 && version != 1) {
+ GST_DEBUG_OBJECT (rmdemux, "Expected version 0 or 1, got %d",
+ (int) version);
+ ret = FALSE;
+ }
+
+ length = RMDEMUX_GUINT16_GET (map.data + 2);
+ /* TODO: Also check against total stream length */
+ if (length < 4) {
+ GST_DEBUG_OBJECT (rmdemux, "Expected length >= 4, got %d", (int) length);
+ ret = FALSE;
+ }
+ gst_buffer_unmap (buffer, &map);
+
+ if (ret) {
+ rmdemux->offset += 4;
+ gst_adapter_clear (rmdemux->adapter);
+ gst_adapter_push (rmdemux->adapter, buffer);
+ } else {
+ GST_WARNING_OBJECT (rmdemux, "Failed to validate seek offset at %d",
+ rmdemux->offset);
+ gst_buffer_unref (buffer);
+ }
+
+ return ret;
+}
+
+static gboolean
+find_seek_offset_bytes (GstRMDemux * rmdemux, guint target)
+{
+ int i;
+ GSList *cur;
+ gboolean ret = FALSE;
+
+ for (cur = rmdemux->streams; cur; cur = cur->next) {
+ GstRMDemuxStream *stream = cur->data;
+
+ /* Search backwards through this stream's index until we find the first
+ * timestamp before our target time */
+ for (i = stream->index_length - 1; i >= 0; i--) {
+ if (stream->index[i].offset <= target) {
+ /* Set the seek_offset for the stream so we don't bother parsing it
+ * until we've passed that point */
+ stream->seek_offset = stream->index[i].offset;
+ rmdemux->offset = stream->index[i].offset;
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+static gboolean
+find_seek_offset_time (GstRMDemux * rmdemux, GstClockTime time)
+{
+ int i, n_stream;
+ gboolean ret = FALSE;
+ GSList *cur;
+ GstClockTime earliest = GST_CLOCK_TIME_NONE;
+
+ n_stream = 0;
+ for (cur = rmdemux->streams; cur; cur = cur->next, n_stream++) {
+ GstRMDemuxStream *stream = cur->data;
+
+ /* Search backwards through this stream's index until we find the first
+ * timestamp before our target time */
+ for (i = stream->index_length - 1; i >= 0; i--) {
+ if (stream->index[i].timestamp <= time) {
+ /* Set the seek_offset for the stream so we don't bother parsing it
+ * until we've passed that point */
+ stream->seek_offset = stream->index[i].offset;
+
+ /* If it's also the earliest timestamp we've seen of all streams, then
+ * that's our target!
+ */
+ if (earliest == GST_CLOCK_TIME_NONE ||
+ stream->index[i].timestamp < earliest) {
+ earliest = stream->index[i].timestamp;
+ rmdemux->offset = stream->index[i].offset;
+ GST_DEBUG_OBJECT (rmdemux,
+ "We're looking for %" GST_TIME_FORMAT
+ " and we found that stream %d has the latest index at %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment.start), n_stream,
+ GST_TIME_ARGS (earliest));
+ }
+
+ ret = TRUE;
+
+ break;
+ }
+ }
+ stream->discont = TRUE;
+ }
+ return ret;
+}
+
+static gboolean
+gst_rmdemux_perform_seek (GstRMDemux * rmdemux, GstEvent * event)
+{
+ gboolean validated;
+ gboolean ret = TRUE;
+ gboolean flush;
+ GstFormat format;
+ gdouble rate;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
+ gboolean update;
+
+ if (event) {
+ GST_DEBUG_OBJECT (rmdemux, "seek with event");
+
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
+
+ /* we can only seek on time */
+ if (format != GST_FORMAT_TIME) {
+ GST_DEBUG_OBJECT (rmdemux, "can only seek on TIME");
+ goto error;
+ }
+ /* cannot yet do backwards playback */
+ if (rate <= 0.0) {
+ GST_DEBUG_OBJECT (rmdemux, "can only seek with positive rate, not %lf",
+ rate);
+ goto error;
+ }
+ } else {
+ GST_DEBUG_OBJECT (rmdemux, "seek without event");
+
+ flags = 0;
+ rate = 1.0;
+ }
+
+ GST_DEBUG_OBJECT (rmdemux, "seek, rate %g", rate);
+
+ flush = flags & GST_SEEK_FLAG_FLUSH;
+
+ /* first step is to unlock the streaming thread if it is
+ * blocked in a chain call, we do this by starting the flush. */
+ if (flush) {
+ gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_start ());
+ gst_rmdemux_send_event (rmdemux, gst_event_new_flush_start ());
+ } else {
+ gst_pad_pause_task (rmdemux->sinkpad);
+ }
+
+ GST_LOG_OBJECT (rmdemux, "Done starting flushes");
+
+ /* now grab the stream lock so that streaming cannot continue, for
+ * non flushing seeks when the element is in PAUSED this could block
+ * forever. */
+ GST_PAD_STREAM_LOCK (rmdemux->sinkpad);
+
+ GST_LOG_OBJECT (rmdemux, "Took streamlock");
+
+ if (event) {
+ gst_segment_do_seek (&rmdemux->segment, rate, format, flags,
+ cur_type, cur, stop_type, stop, &update);
+ }
+
+ GST_DEBUG_OBJECT (rmdemux, "segment positions set to %" GST_TIME_FORMAT "-%"
+ GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment.start),
+ GST_TIME_ARGS (rmdemux->segment.stop));
+
+ /* we need to stop flushing on the sinkpad as we're going to use it
+ * next. We can do this as we have the STREAM lock now. */
+ gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_stop (TRUE));
+
+ GST_LOG_OBJECT (rmdemux, "Pushed FLUSH_STOP event");
+
+ /* For each stream, find the first index offset equal to or before our seek
+ * target. Of these, find the smallest offset. That's where we seek to.
+ *
+ * Then we pull 4 bytes from that offset, and validate that we've seeked to a
+ * what looks like a plausible packet.
+ * If that fails, restart, with the seek target set to one less than the
+ * offset we just tried. If we run out of places to try, treat that as a fatal
+ * error.
+ */
+ if (!find_seek_offset_time (rmdemux, rmdemux->segment.position)) {
+ GST_LOG_OBJECT (rmdemux, "Failed to find seek offset by time");
+ ret = FALSE;
+ goto done;
+ }
+
+ GST_LOG_OBJECT (rmdemux, "Validating offset %u", rmdemux->offset);
+ validated = gst_rmdemux_validate_offset (rmdemux);
+ while (!validated) {
+ GST_INFO_OBJECT (rmdemux, "Failed to validate offset at %u",
+ rmdemux->offset);
+ if (!find_seek_offset_bytes (rmdemux, rmdemux->offset - 1)) {
+ ret = FALSE;
+ goto done;
+ }
+ validated = gst_rmdemux_validate_offset (rmdemux);
+ }
+
+ GST_LOG_OBJECT (rmdemux, "Found final offset. Excellent!");
+
+ /* now we have a new position, prepare for streaming again */
+ {
+ /* Reset the demuxer state */
+ rmdemux->state = RMDEMUX_STATE_DATA_PACKET;
+
+ if (flush)
+ gst_rmdemux_send_event (rmdemux, gst_event_new_flush_stop (TRUE));
+
+ /* must send newsegment event from streaming thread, so just set flag */
+ rmdemux->need_newsegment = TRUE;
+
+ /* notify start of new segment */
+ if (rmdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gst_element_post_message (GST_ELEMENT_CAST (rmdemux),
+ gst_message_new_segment_start (GST_OBJECT_CAST (rmdemux),
+ GST_FORMAT_TIME, rmdemux->segment.position));
+ }
+
+ /* restart our task since it might have been stopped when we did the
+ * flush. */
+ gst_pad_start_task (rmdemux->sinkpad, (GstTaskFunction) gst_rmdemux_loop,
+ rmdemux->sinkpad, NULL);
+ }
+
+done:
+ /* streaming can continue now */
+ GST_PAD_STREAM_UNLOCK (rmdemux->sinkpad);
+
+ return ret;
+
+error:
+ {
+ GST_DEBUG_OBJECT (rmdemux, "seek failed");
+ return FALSE;
+ }
+}
+
+
+static gboolean
+gst_rmdemux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+ gboolean res = FALSE;
+ GstRMDemux *rmdemux;
+
+ rmdemux = GST_RMDEMUX (parent);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_POSITION:
+ GST_DEBUG_OBJECT (rmdemux, "Position query: no idea from demuxer!");
+ break;
+ case GST_QUERY_DURATION:{
+ GstFormat fmt;
+
+ gst_query_parse_duration (query, &fmt, NULL);
+ if (fmt == GST_FORMAT_TIME) {
+ GST_OBJECT_LOCK (rmdemux);
+ if (G_LIKELY (rmdemux->running)) {
+ gst_query_set_duration (query, GST_FORMAT_TIME, rmdemux->duration);
+ GST_DEBUG_OBJECT (rmdemux, "duration set to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (rmdemux->duration));
+ res = TRUE;
+ }
+ GST_OBJECT_UNLOCK (rmdemux);
+ }
+ break;
+ }
+ case GST_QUERY_SEEKING:{
+ GstFormat fmt;
+
+ gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+ if (fmt == GST_FORMAT_TIME) {
+ GST_OBJECT_LOCK (rmdemux);
+ if (G_LIKELY (rmdemux->running)) {
+ gst_query_set_seeking (query, GST_FORMAT_TIME, rmdemux->seekable,
+ 0, rmdemux->duration);
+ res = TRUE;
+ }
+ GST_OBJECT_UNLOCK (rmdemux);
+ }
+ break;
+ }
+ case GST_QUERY_SEGMENT:
+ {
+ GstFormat format;
+ gint64 start, stop;
+
+ format = rmdemux->segment.format;
+
+ start =
+ gst_segment_to_stream_time (&rmdemux->segment, format,
+ rmdemux->segment.start);
+ if ((stop = rmdemux->segment.stop) == -1)
+ stop = rmdemux->segment.duration;
+ else
+ stop = gst_segment_to_stream_time (&rmdemux->segment, format, stop);
+
+ gst_query_set_segment (query, rmdemux->segment.rate, format, start, stop);
+ res = TRUE;
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, parent, query);
+ break;
+ }
+
+ return res;
+}
+
+static void
+gst_rmdemux_reset (GstRMDemux * rmdemux)
+{
+ GSList *cur;
+
+ GST_OBJECT_LOCK (rmdemux);
+ rmdemux->running = FALSE;
+ GST_OBJECT_UNLOCK (rmdemux);
+
+ for (cur = rmdemux->streams; cur; cur = cur->next) {
+ GstRMDemuxStream *stream = cur->data;
+
+ g_object_unref (stream->adapter);
+ gst_rmdemux_stream_clear_cached_subpackets (rmdemux, stream);
+ gst_flow_combiner_remove_pad (rmdemux->flowcombiner, stream->pad);
+ gst_element_remove_pad (GST_ELEMENT (rmdemux), stream->pad);
+ if (stream->pending_tags)
+ gst_tag_list_unref (stream->pending_tags);
+ if (stream->subpackets)
+ g_ptr_array_free (stream->subpackets, TRUE);
+ g_free (stream->index);
+ g_free (stream);
+ }
+ g_slist_free (rmdemux->streams);
+ rmdemux->streams = NULL;
+ rmdemux->n_audio_streams = 0;
+ rmdemux->n_video_streams = 0;
+
+ if (rmdemux->pending_tags != NULL) {
+ gst_tag_list_unref (rmdemux->pending_tags);
+ rmdemux->pending_tags = NULL;
+ }
+
+ gst_adapter_clear (rmdemux->adapter);
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ rmdemux->have_pads = FALSE;
+
+ gst_segment_init (&rmdemux->segment, GST_FORMAT_UNDEFINED);
+ rmdemux->first_ts = GST_CLOCK_TIME_NONE;
+ rmdemux->base_ts = GST_CLOCK_TIME_NONE;
+ rmdemux->need_newsegment = TRUE;
+
+ rmdemux->have_group_id = FALSE;
+ rmdemux->group_id = G_MAXUINT;
+}
+
+static GstStateChangeReturn
+gst_rmdemux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRMDemux *rmdemux = GST_RMDEMUX (element);
+ GstStateChangeReturn res;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ rmdemux->have_pads = FALSE;
+ gst_segment_init (&rmdemux->segment, GST_FORMAT_TIME);
+ rmdemux->running = FALSE;
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:{
+ gst_rmdemux_reset (rmdemux);
+ break;
+ }
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+/* this function is called when the pad is activated and should start
+ * processing data.
+ *
+ * We check if we can do random access to decide if we work push or
+ * pull based.
+ */
+static gboolean
+gst_rmdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
+{
+ GstQuery *query;
+ gboolean pull_mode;
+
+ query = gst_query_new_scheduling ();
+
+ if (!gst_pad_peer_query (sinkpad, query)) {
+ gst_query_unref (query);
+ goto activate_push;
+ }
+
+ pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+ GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
+ gst_query_unref (query);
+
+ if (!pull_mode)
+ goto activate_push;
+
+ GST_DEBUG_OBJECT (sinkpad, "activating pull");
+ return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
+
+activate_push:
+ {
+ GST_DEBUG_OBJECT (sinkpad, "activating push");
+ return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
+ }
+}
+
+static gboolean
+gst_rmdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
+ GstPadMode mode, gboolean active)
+{
+ gboolean res;
+ GstRMDemux *demux;
+
+ demux = GST_RMDEMUX (parent);
+
+ switch (mode) {
+ case GST_PAD_MODE_PUSH:
+ demux->seekable = FALSE;
+ demux->running = active;
+ res = TRUE;
+ break;
+ case GST_PAD_MODE_PULL:
+ if (active) {
+ demux->seekable = TRUE;
+ demux->offset = 0;
+ demux->loop_state = RMDEMUX_LOOP_STATE_HEADER;
+ demux->data_offset = G_MAXUINT;
+ res =
+ gst_pad_start_task (sinkpad, (GstTaskFunction) gst_rmdemux_loop,
+ sinkpad, NULL);
+ } else {
+ res = gst_pad_stop_task (sinkpad);
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
+
+/* random access mode - just pass over to our chain function */
+static void
+gst_rmdemux_loop (GstPad * pad)
+{
+ GstRMDemux *rmdemux;
+ GstBuffer *buffer;
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint size;
+
+ rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
+
+ GST_LOG_OBJECT (rmdemux, "loop with state=%d and offset=0x%x",
+ rmdemux->loop_state, rmdemux->offset);
+
+ switch (rmdemux->state) {
+ case RMDEMUX_STATE_HEADER:
+ size = HEADER_SIZE;
+ break;
+ case RMDEMUX_STATE_HEADER_DATA:
+ size = DATA_SIZE;
+ break;
+ case RMDEMUX_STATE_DATA_PACKET:
+ size = rmdemux->avg_packet_size;
+ break;
+ case RMDEMUX_STATE_EOS:
+ GST_LOG_OBJECT (rmdemux, "At EOS, pausing task");
+ ret = GST_FLOW_EOS;
+ goto need_pause;
+ default:
+ GST_LOG_OBJECT (rmdemux, "Default: requires %d bytes (state is %d)",
+ (int) rmdemux->size, rmdemux->state);
+ size = rmdemux->size;
+ }
+
+ buffer = NULL;
+ ret = gst_pad_pull_range (pad, rmdemux->offset, size, &buffer);
+ if (ret != GST_FLOW_OK) {
+ if (rmdemux->offset == rmdemux->index_offset) {
+ /* The index isn't available so forget about it */
+ rmdemux->loop_state = RMDEMUX_LOOP_STATE_DATA;
+ rmdemux->offset = rmdemux->data_offset;
+ GST_OBJECT_LOCK (rmdemux);
+ rmdemux->running = TRUE;
+ rmdemux->seekable = FALSE;
+ GST_OBJECT_UNLOCK (rmdemux);
+ return;
+ } else {
+ GST_DEBUG_OBJECT (rmdemux, "Unable to pull %d bytes at offset 0x%08x "
+ "(pull_range returned flow %s, state is %d)", (gint) size,
+ rmdemux->offset, gst_flow_get_name (ret), GST_STATE (rmdemux));
+ goto need_pause;
+ }
+ }
+
+ size = gst_buffer_get_size (buffer);
+
+ /* Defer to the chain function */
+ ret = gst_rmdemux_chain (pad, GST_OBJECT_CAST (rmdemux), buffer);
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (rmdemux, "Chain flow failed at offset 0x%08x",
+ rmdemux->offset);
+ goto need_pause;
+ }
+
+ rmdemux->offset += size;
+
+ switch (rmdemux->loop_state) {
+ case RMDEMUX_LOOP_STATE_HEADER:
+ if (rmdemux->offset >= rmdemux->data_offset) {
+ /* It's the end of the header */
+ rmdemux->loop_state = RMDEMUX_LOOP_STATE_INDEX;
+ rmdemux->offset = rmdemux->index_offset;
+ }
+ break;
+ case RMDEMUX_LOOP_STATE_INDEX:
+ if (rmdemux->state == RMDEMUX_STATE_HEADER) {
+ if (rmdemux->index_offset == 0) {
+ /* We've read the last index */
+ rmdemux->loop_state = RMDEMUX_LOOP_STATE_DATA;
+ rmdemux->offset = rmdemux->data_offset;
+ GST_OBJECT_LOCK (rmdemux);
+ rmdemux->running = TRUE;
+ GST_OBJECT_UNLOCK (rmdemux);
+ } else {
+ /* Get the next index */
+ rmdemux->offset = rmdemux->index_offset;
+ }
+ }
+ break;
+ case RMDEMUX_LOOP_STATE_DATA:
+ break;
+ }
+
+ return;
+
+ /* ERRORS */
+need_pause:
+ {
+ const gchar *reason = gst_flow_get_name (ret);
+
+ GST_LOG_OBJECT (rmdemux, "pausing task, reason %s", reason);
+ rmdemux->segment_running = FALSE;
+ gst_pad_pause_task (rmdemux->sinkpad);
+
+ if (ret == GST_FLOW_EOS) {
+ /* perform EOS logic */
+ if (rmdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gint64 stop;
+
+ /* for segment playback we need to post when (in stream time)
+ * we stopped, this is either stop (when set) or the duration. */
+ if ((stop = rmdemux->segment.stop) == -1)
+ stop = rmdemux->segment.duration;
+
+ GST_LOG_OBJECT (rmdemux, "Sending segment done, at end of segment");
+ gst_element_post_message (GST_ELEMENT (rmdemux),
+ gst_message_new_segment_done (GST_OBJECT (rmdemux),
+ GST_FORMAT_TIME, stop));
+ gst_rmdemux_send_event (rmdemux,
+ gst_event_new_segment_done (GST_FORMAT_TIME, stop));
+ } else {
+ /* normal playback, send EOS to all linked pads */
+ GST_LOG_OBJECT (rmdemux, "Sending EOS, at end of stream");
+ gst_rmdemux_send_event (rmdemux, gst_event_new_eos ());
+ }
+ } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
+ GST_ELEMENT_ERROR (rmdemux, STREAM, FAILED,
+ (NULL), ("stream stopped, reason %s", reason));
+ gst_rmdemux_send_event (rmdemux, gst_event_new_eos ());
+ }
+ return;
+ }
+}
+
+static gboolean
+gst_rmdemux_fourcc_isplausible (guint32 fourcc)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (!isprint ((int) ((unsigned char *) (&fourcc))[i])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_rmdemux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ const guint8 *data;
+ guint16 version;
+ guint avail;
+
+ GstRMDemux *rmdemux = GST_RMDEMUX (parent);
+
+ if (rmdemux->base_ts == -1) {
+ if (GST_BUFFER_DTS_IS_VALID (buffer))
+ rmdemux->base_ts = GST_BUFFER_DTS (buffer);
+ else
+ rmdemux->base_ts = GST_BUFFER_PTS (buffer);
+
+ GST_LOG_OBJECT (rmdemux, "base_ts %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (rmdemux->base_ts));
+ }
+
+ gst_adapter_push (rmdemux->adapter, buffer);
+
+ GST_LOG_OBJECT (rmdemux, "Chaining buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (buffer));
+
+ while (TRUE) {
+ avail = gst_adapter_available (rmdemux->adapter);
+
+ GST_LOG_OBJECT (rmdemux, "looping in chain, avail %u", avail);
+ switch (rmdemux->state) {
+ case RMDEMUX_STATE_HEADER:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < HEADER_SIZE)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, HEADER_SIZE);
+
+ rmdemux->object_id = RMDEMUX_FOURCC_GET (data + 0);
+ rmdemux->size = RMDEMUX_GUINT32_GET (data + 4) - HEADER_SIZE;
+ rmdemux->object_version = RMDEMUX_GUINT16_GET (data + 8);
+
+ /* Sanity-check. We assume that the FOURCC is printable ASCII */
+ if (!gst_rmdemux_fourcc_isplausible (rmdemux->object_id)) {
+ /* Failed. Remain in HEADER state, try again... We flush only
+ * the actual FOURCC, not the entire header, because we could
+ * need to resync anywhere at all... really, this should never
+ * happen. */
+ GST_WARNING_OBJECT (rmdemux, "Bogus looking header, unprintable "
+ "FOURCC");
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, 4);
+
+ break;
+ }
+
+ GST_LOG_OBJECT (rmdemux, "header found with object_id=%"
+ GST_FOURCC_FORMAT
+ " size=%08x object_version=%d",
+ GST_FOURCC_ARGS (rmdemux->object_id), rmdemux->size,
+ rmdemux->object_version);
+
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, HEADER_SIZE);
+
+ switch (rmdemux->object_id) {
+ case GST_MAKE_FOURCC ('.', 'R', 'M', 'F'):
+ rmdemux->state = RMDEMUX_STATE_HEADER_RMF;
+ break;
+ case GST_MAKE_FOURCC ('P', 'R', 'O', 'P'):
+ rmdemux->state = RMDEMUX_STATE_HEADER_PROP;
+ break;
+ case GST_MAKE_FOURCC ('M', 'D', 'P', 'R'):
+ rmdemux->state = RMDEMUX_STATE_HEADER_MDPR;
+ break;
+ case GST_MAKE_FOURCC ('I', 'N', 'D', 'X'):
+ rmdemux->state = RMDEMUX_STATE_HEADER_INDX;
+ break;
+ case GST_MAKE_FOURCC ('D', 'A', 'T', 'A'):
+ rmdemux->state = RMDEMUX_STATE_HEADER_DATA;
+ break;
+ case GST_MAKE_FOURCC ('C', 'O', 'N', 'T'):
+ rmdemux->state = RMDEMUX_STATE_HEADER_CONT;
+ break;
+ default:
+ rmdemux->state = RMDEMUX_STATE_HEADER_UNKNOWN;
+ break;
+ }
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_UNKNOWN:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ GST_WARNING_OBJECT (rmdemux, "Unknown object_id %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (rmdemux->object_id));
+
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_RMF:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ if ((rmdemux->object_version == 0) || (rmdemux->object_version == 1)) {
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ gst_rmdemux_parse__rmf (rmdemux, data, rmdemux->size);
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+ } else {
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+ }
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_PROP:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ gst_rmdemux_parse_prop (rmdemux, data, rmdemux->size);
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_MDPR:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ gst_rmdemux_parse_mdpr (rmdemux, data, rmdemux->size);
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_CONT:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ gst_rmdemux_parse_cont (rmdemux, data, rmdemux->size);
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_DATA:
+ {
+ /* If we haven't already done so then signal there are no more pads */
+ if (!rmdemux->have_pads) {
+ GST_LOG_OBJECT (rmdemux, "no more pads");
+ gst_element_no_more_pads (GST_ELEMENT (rmdemux));
+ rmdemux->have_pads = TRUE;
+ }
+
+ /* The actual header is only 8 bytes */
+ rmdemux->size = DATA_SIZE;
+ GST_LOG_OBJECT (rmdemux, "data available %" G_GSIZE_FORMAT,
+ gst_adapter_available (rmdemux->adapter));
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ gst_rmdemux_parse_data (rmdemux, data, rmdemux->size);
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+
+ rmdemux->state = RMDEMUX_STATE_DATA_PACKET;
+ break;
+ }
+ case RMDEMUX_STATE_HEADER_INDX:
+ {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ rmdemux->size = gst_rmdemux_parse_indx (rmdemux, data, rmdemux->size);
+ /* Only flush the header */
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, HEADER_SIZE);
+
+ rmdemux->state = RMDEMUX_STATE_INDX_DATA;
+ break;
+ }
+ case RMDEMUX_STATE_INDX_DATA:
+ {
+ /* There's not always an data to get... */
+ if (rmdemux->size > 0) {
+ if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
+ goto unlock;
+
+ data = gst_adapter_map (rmdemux->adapter, rmdemux->size);
+ gst_rmdemux_parse_indx_data (rmdemux, data, rmdemux->size);
+ gst_adapter_unmap (rmdemux->adapter);
+ gst_adapter_flush (rmdemux->adapter, rmdemux->size);
+ }
+
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ break;
+ }
+ case RMDEMUX_STATE_DATA_PACKET:
+ {
+ guint8 header[4];
+
+ if (gst_adapter_available (rmdemux->adapter) < 2)
+ goto unlock;
+
+ gst_adapter_copy (rmdemux->adapter, header, 0, 2);
+ version = RMDEMUX_GUINT16_GET (header);
+ GST_LOG_OBJECT (rmdemux, "Data packet with version=%d", version);
+
+ if (version == 0 || version == 1) {
+ guint16 length;
+
+ if (gst_adapter_available (rmdemux->adapter) < 4)
+ goto unlock;
+
+ gst_adapter_copy (rmdemux->adapter, header, 0, 4);
+
+ length = RMDEMUX_GUINT16_GET (header + 2);
+ GST_LOG_OBJECT (rmdemux, "Got length %d", length);
+
+ if (length < 4) {
+ GST_LOG_OBJECT (rmdemux, "length too small, dropping");
+ /* Invalid, just drop it */
+ gst_adapter_flush (rmdemux->adapter, 4);
+ } else {
+ GstBuffer *buffer;
+
+ avail = gst_adapter_available (rmdemux->adapter);
+ if (avail < length)
+ goto unlock;
+
+ GST_LOG_OBJECT (rmdemux, "we have %u available and we needed %d",
+ avail, length);
+
+ /* flush version and length */
+ gst_adapter_flush (rmdemux->adapter, 4);
+ length -= 4;
+
+ buffer = gst_adapter_take_buffer (rmdemux->adapter, length);
+
+ ret = gst_rmdemux_parse_packet (rmdemux, buffer, version);
+ rmdemux->chunk_index++;
+ }
+
+ if (rmdemux->chunk_index == rmdemux->n_chunks || length == 0)
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ } else {
+ /* Stream done */
+ gst_adapter_flush (rmdemux->adapter, 2);
+
+ if (rmdemux->data_offset == 0) {
+ GST_LOG_OBJECT (rmdemux,
+ "No further data, internal demux state EOS");
+ rmdemux->state = RMDEMUX_STATE_EOS;
+ } else
+ rmdemux->state = RMDEMUX_STATE_HEADER;
+ }
+ break;
+ }
+ case RMDEMUX_STATE_EOS:
+ gst_rmdemux_send_event (rmdemux, gst_event_new_eos ());
+ goto unlock;
+ default:
+ GST_WARNING_OBJECT (rmdemux, "Unhandled state %d", rmdemux->state);
+ goto unlock;
+ }
+ }
+
+unlock:
+ return ret;
+}
+
+static GstRMDemuxStream *
+gst_rmdemux_get_stream_by_id (GstRMDemux * rmdemux, int id)
+{
+ GSList *cur;
+
+ for (cur = rmdemux->streams; cur; cur = cur->next) {
+ GstRMDemuxStream *stream = cur->data;
+
+ if (stream->id == id) {
+ return stream;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event)
+{
+ GSList *cur;
+
+ for (cur = rmdemux->streams; cur; cur = cur->next) {
+ GstRMDemuxStream *stream = cur->data;
+
+ GST_DEBUG_OBJECT (rmdemux, "Pushing %s event on pad %s",
+ GST_EVENT_TYPE_NAME (event), GST_PAD_NAME (stream->pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ stream->last_ts = -1;
+ stream->next_ts = -1;
+ stream->last_seq = -1;
+ stream->next_seq = -1;
+ break;
+ default:
+ break;
+ }
+ gst_event_ref (event);
+ gst_pad_push_event (stream->pad, event);
+ }
+ gst_event_unref (event);
+}
+
+static void
+gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
+{
+ GstCaps *stream_caps = NULL;
+ const gchar *codec_tag = NULL;
+ gchar *codec_name = NULL;
+ gchar *stream_id;
+ int version = 0;
+
+ if (stream->subtype == GST_RMDEMUX_STREAM_VIDEO) {
+ char *name = g_strdup_printf ("video_%u", rmdemux->n_video_streams);
+
+ stream->pad =
+ gst_pad_new_from_static_template (&gst_rmdemux_videosrc_template, name);
+ g_free (name);
+
+ codec_tag = GST_TAG_VIDEO_CODEC;
+
+ switch (stream->fourcc) {
+ case GST_RM_VDO_RV10:
+ version = 1;
+ break;
+ case GST_RM_VDO_RV20:
+ version = 2;
+ break;
+ case GST_RM_VDO_RV30:
+ version = 3;
+ break;
+ case GST_RM_VDO_RV40:
+ version = 4;
+ break;
+ default:
+ stream_caps = gst_caps_new_simple ("video/x-unknown-fourcc",
+ "fourcc", G_TYPE_UINT, stream->fourcc, NULL);
+ GST_WARNING_OBJECT (rmdemux,
+ "Unknown video FOURCC code \"%" GST_FOURCC_FORMAT "\" (%08x)",
+ GST_FOURCC_ARGS (stream->fourcc), stream->fourcc);
+ }
+
+ if (version) {
+ stream_caps =
+ gst_caps_new_simple ("video/x-pn-realvideo", "rmversion", G_TYPE_INT,
+ (int) version,
+ "format", G_TYPE_INT,
+ (int) stream->format,
+ "subformat", G_TYPE_INT, (int) stream->subformat, NULL);
+ }
+
+ if (stream_caps) {
+ gst_caps_set_simple (stream_caps,
+ "width", G_TYPE_INT, stream->width,
+ "height", G_TYPE_INT, stream->height,
+ "framerate", GST_TYPE_FRACTION, stream->framerate_numerator,
+ stream->framerate_denominator, NULL);
+ }
+ rmdemux->n_video_streams++;
+
+ } else if (stream->subtype == GST_RMDEMUX_STREAM_AUDIO) {
+ char *name = g_strdup_printf ("audio_%u", rmdemux->n_audio_streams);
+
+ stream->pad =
+ gst_pad_new_from_static_template (&gst_rmdemux_audiosrc_template, name);
+ GST_LOG_OBJECT (rmdemux, "Created audio pad \"%s\"", name);
+ g_free (name);
+
+ codec_tag = GST_TAG_AUDIO_CODEC;
+
+ switch (stream->fourcc) {
+ /* Older RealAudio Codecs */
+ case GST_RM_AUD_14_4:
+ version = 1;
+ break;
+
+ case GST_RM_AUD_28_8:
+ version = 2;
+ break;
+
+ /* DolbyNet (Dolby AC3, low bitrate) */
+ case GST_RM_AUD_DNET:
+ stream_caps =
+ gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT,
+ (int) stream->rate, NULL);
+ stream->needs_descrambling = TRUE;
+ stream->subpackets_needed = 1;
+ stream->subpackets = NULL;
+ break;
+
+ /* MPEG-4 based */
+ case GST_RM_AUD_RAAC:
+ case GST_RM_AUD_RACP:
+ stream_caps =
+ gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT,
+ (int) 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+ if (stream->extra_data_size > 0) {
+ /* strip off an unknown byte in the extra data */
+ stream->extra_data_size--;
+ stream->extra_data++;
+ }
+ stream->needs_descrambling = TRUE;
+ stream->subpackets_needed = 1;
+ stream->subpackets = NULL;
+ break;
+
+ /* Sony ATRAC3 */
+ case GST_RM_AUD_ATRC:
+ stream_caps = gst_caps_new_empty_simple ("audio/x-vnd.sony.atrac3");
+ stream->needs_descrambling = TRUE;
+ stream->subpackets_needed = stream->height;
+ stream->subpackets = NULL;
+ break;
+
+ /* RealAudio G2 audio */
+ case GST_RM_AUD_COOK:
+ version = 8;
+ stream->needs_descrambling = TRUE;
+ stream->subpackets_needed = stream->height;
+ stream->subpackets = NULL;
+ break;
+
+ /* RALF is lossless */
+ case GST_RM_AUD_RALF:
+ GST_DEBUG_OBJECT (rmdemux, "RALF");
+ stream_caps = gst_caps_new_empty_simple ("audio/x-ralf-mpeg4-generic");
+ break;
+
+ case GST_RM_AUD_SIPR:
+
+ if (stream->flavor > 3) {
+ GST_WARNING_OBJECT (rmdemux, "bad SIPR flavor %d, freeing it",
+ stream->flavor);
+ g_free (stream);
+ goto beach;
+ }
+
+ GST_DEBUG_OBJECT (rmdemux, "SIPR");
+ stream_caps = gst_caps_new_empty_simple ("audio/x-sipro");
+ stream->needs_descrambling = TRUE;
+ stream->subpackets_needed = stream->height;
+ stream->subpackets = NULL;
+ stream->leaf_size = sipr_subpk_size[stream->flavor];
+
+ break;
+
+ default:
+ stream_caps = gst_caps_new_simple ("video/x-unknown-fourcc",
+ "fourcc", G_TYPE_UINT, stream->fourcc, NULL);
+ GST_WARNING_OBJECT (rmdemux,
+ "Unknown audio FOURCC code \"%" GST_FOURCC_FORMAT "\" (%08x)",
+ GST_FOURCC_ARGS (stream->fourcc), stream->fourcc);
+ break;
+ }
+
+ if (version) {
+ stream_caps =
+ gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT,
+ (int) version, NULL);
+ }
+
+ if (stream_caps) {
+ gst_caps_set_simple (stream_caps,
+ "flavor", G_TYPE_INT, (int) stream->flavor,
+ "rate", G_TYPE_INT, (int) stream->rate,
+ "channels", G_TYPE_INT, (int) stream->n_channels,
+ "width", G_TYPE_INT, (int) stream->sample_width,
+ "leaf_size", G_TYPE_INT, (int) stream->leaf_size,
+ "packet_size", G_TYPE_INT, (int) stream->packet_size,
+ "bitrate", G_TYPE_INT, (int) stream->bitrate,
+ "height", G_TYPE_INT, (int) stream->height, NULL);
+ }
+ rmdemux->n_audio_streams++;
+ } else {
+ GST_WARNING_OBJECT (rmdemux, "not adding stream of type %d, freeing it",
+ stream->subtype);
+ g_free (stream);
+ goto beach;
+ }
+
+ GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
+ rmdemux->streams = g_slist_append (rmdemux->streams, stream);
+ GST_LOG_OBJECT (rmdemux, "n_streams is now %d",
+ g_slist_length (rmdemux->streams));
+
+ GST_LOG ("stream->pad = %p, stream_caps = %" GST_PTR_FORMAT, stream->pad,
+ stream_caps);
+
+ if (stream->pad && stream_caps) {
+ GstEvent *event;
+
+ GST_LOG_OBJECT (rmdemux, "%d bytes of extra data for stream %s",
+ stream->extra_data_size, GST_PAD_NAME (stream->pad));
+
+ /* add codec_data if there is any */
+ if (stream->extra_data_size > 0) {
+ GstBuffer *buffer;
+
+ buffer = gst_buffer_new_and_alloc (stream->extra_data_size);
+ gst_buffer_fill (buffer, 0, stream->extra_data, stream->extra_data_size);
+
+ gst_caps_set_simple (stream_caps, "codec_data", GST_TYPE_BUFFER,
+ buffer, NULL);
+
+ gst_buffer_unref (buffer);
+ }
+
+ gst_pad_use_fixed_caps (stream->pad);
+
+ gst_pad_set_event_function (stream->pad,
+ GST_DEBUG_FUNCPTR (gst_rmdemux_src_event));
+ gst_pad_set_query_function (stream->pad,
+ GST_DEBUG_FUNCPTR (gst_rmdemux_src_query));
+
+ GST_DEBUG_OBJECT (rmdemux, "adding pad %s with caps %" GST_PTR_FORMAT
+ ", stream_id=%d", GST_PAD_NAME (stream->pad), stream_caps, stream->id);
+ gst_pad_set_active (stream->pad, TRUE);
+
+ stream_id =
+ gst_pad_create_stream_id_printf (stream->pad,
+ GST_ELEMENT_CAST (rmdemux), "%03u", stream->id);
+
+ event =
+ gst_pad_get_sticky_event (rmdemux->sinkpad, GST_EVENT_STREAM_START, 0);
+ if (event) {
+ if (gst_event_parse_group_id (event, &rmdemux->group_id))
+ rmdemux->have_group_id = TRUE;
+ else
+ rmdemux->have_group_id = FALSE;
+ gst_event_unref (event);
+ } else if (!rmdemux->have_group_id) {
+ rmdemux->have_group_id = TRUE;
+ rmdemux->group_id = gst_util_group_id_next ();
+ }
+
+ event = gst_event_new_stream_start (stream_id);
+ if (rmdemux->have_group_id)
+ gst_event_set_group_id (event, rmdemux->group_id);
+
+ gst_pad_push_event (stream->pad, event);
+ g_free (stream_id);
+
+ gst_pad_set_caps (stream->pad, stream_caps);
+
+ codec_name = gst_pb_utils_get_codec_description (stream_caps);
+
+ /* save for later, we must send the tags after the newsegment event */
+ if (codec_tag != NULL && codec_name != NULL) {
+ if (stream->pending_tags == NULL)
+ stream->pending_tags = gst_tag_list_new_empty ();
+ gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_KEEP,
+ codec_tag, codec_name, NULL);
+ g_free (codec_name);
+ }
+ gst_element_add_pad (GST_ELEMENT_CAST (rmdemux), stream->pad);
+ gst_flow_combiner_add_pad (rmdemux->flowcombiner, stream->pad);
+ }
+
+beach:
+
+ if (stream_caps)
+ gst_caps_unref (stream_caps);
+}
+
+static int
+re_skip_pascal_string (const guint8 * ptr)
+{
+ int length;
+
+ length = ptr[0];
+
+ return length + 1;
+}
+
+static void
+gst_rmdemux_parse__rmf (GstRMDemux * rmdemux, const guint8 * data, int length)
+{
+ GST_LOG_OBJECT (rmdemux, "file_version: %d", RMDEMUX_GUINT32_GET (data));
+ GST_LOG_OBJECT (rmdemux, "num_headers: %d", RMDEMUX_GUINT32_GET (data + 4));
+}
+
+static void
+gst_rmdemux_parse_prop (GstRMDemux * rmdemux, const guint8 * data, int length)
+{
+ GST_LOG_OBJECT (rmdemux, "max bitrate: %d", RMDEMUX_GUINT32_GET (data));
+ GST_LOG_OBJECT (rmdemux, "avg bitrate: %d", RMDEMUX_GUINT32_GET (data + 4));
+ GST_LOG_OBJECT (rmdemux, "max packet size: %d",
+ RMDEMUX_GUINT32_GET (data + 8));
+ rmdemux->avg_packet_size = RMDEMUX_GUINT32_GET (data + 12);
+ GST_LOG_OBJECT (rmdemux, "avg packet size: %d", rmdemux->avg_packet_size);
+ rmdemux->num_packets = RMDEMUX_GUINT32_GET (data + 16);
+ GST_LOG_OBJECT (rmdemux, "number of packets: %d", rmdemux->num_packets);
+
+ GST_LOG_OBJECT (rmdemux, "duration: %d", RMDEMUX_GUINT32_GET (data + 20));
+ rmdemux->duration = RMDEMUX_GUINT32_GET (data + 20) * GST_MSECOND;
+
+ GST_LOG_OBJECT (rmdemux, "preroll: %d", RMDEMUX_GUINT32_GET (data + 24));
+ rmdemux->index_offset = RMDEMUX_GUINT32_GET (data + 28);
+ GST_LOG_OBJECT (rmdemux, "offset of INDX section: 0x%08x",
+ rmdemux->index_offset);
+ rmdemux->data_offset = RMDEMUX_GUINT32_GET (data + 32);
+ GST_LOG_OBJECT (rmdemux, "offset of DATA section: 0x%08x",
+ rmdemux->data_offset);
+ GST_LOG_OBJECT (rmdemux, "n streams: %d", RMDEMUX_GUINT16_GET (data + 36));
+ GST_LOG_OBJECT (rmdemux, "flags: 0x%04x", RMDEMUX_GUINT16_GET (data + 38));
+}
+
+static void
+gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux, const guint8 * data, int length)
+{
+ GstRMDemuxStream *stream;
+ char *stream1_type_string;
+ char *stream2_type_string;
+ guint str_len = 0;
+ int stream_type;
+ int offset;
+ guint32 max_bitrate;
+ guint32 avg_bitrate;
+
+ stream = g_new0 (GstRMDemuxStream, 1);
+
+ stream->id = RMDEMUX_GUINT16_GET (data);
+ stream->index = NULL;
+ stream->seek_offset = 0;
+ stream->last_ts = -1;
+ stream->next_ts = -1;
+ stream->discont = TRUE;
+ stream->adapter = gst_adapter_new ();
+ GST_LOG_OBJECT (rmdemux, "stream_number=%d", stream->id);
+
+ /* parse the bitrates */
+ max_bitrate = RMDEMUX_GUINT32_GET (data + 2);
+ avg_bitrate = RMDEMUX_GUINT32_GET (data + 6);
+ stream->bitrate = avg_bitrate;
+ GST_LOG_OBJECT (rmdemux, "Stream max bitrate=%u", max_bitrate);
+ GST_LOG_OBJECT (rmdemux, "Stream avg bitrate=%u", avg_bitrate);
+ if (max_bitrate != 0) {
+ if (stream->pending_tags == NULL)
+ stream->pending_tags = gst_tag_list_new_empty ();
+ gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
+ }
+ if (avg_bitrate != 0) {
+ if (stream->pending_tags == NULL)
+ stream->pending_tags = gst_tag_list_new_empty ();
+ gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_BITRATE, avg_bitrate, NULL);
+ }
+
+ offset = 30;
+ stream1_type_string = gst_rm_utils_read_string8 (data + offset,
+ length - offset, &str_len);
+ offset += str_len;
+ stream2_type_string = gst_rm_utils_read_string8 (data + offset,
+ length - offset, &str_len);
+ offset += str_len;
+
+ /* stream1_type_string for audio and video stream is a "put_whatever_you_want" field :
+ * observed values :
+ * - "[The ]Video/Audio Stream" (File produced by an official Real encoder)
+ * - "RealVideoPremierePlugIn-VIDEO/AUDIO" (File produced by Abobe Premiere)
+ *
+ * so, we should not rely on it to know which stream type it is
+ */
+
+ GST_LOG_OBJECT (rmdemux, "stream type: %s", stream1_type_string);
+ GST_LOG_OBJECT (rmdemux, "MIME type=%s", stream2_type_string);
+
+ if (strcmp (stream2_type_string, "video/x-pn-realvideo") == 0) {
+ stream_type = GST_RMDEMUX_STREAM_VIDEO;
+ } else if (strcmp (stream2_type_string,
+ "video/x-pn-multirate-realvideo") == 0) {
+ stream_type = GST_RMDEMUX_STREAM_VIDEO;
+ } else if (strcmp (stream2_type_string, "audio/x-pn-realaudio") == 0) {
+ stream_type = GST_RMDEMUX_STREAM_AUDIO;
+ } else if (strcmp (stream2_type_string,
+ "audio/x-pn-multirate-realaudio") == 0) {
+ stream_type = GST_RMDEMUX_STREAM_AUDIO;
+ } else if (strcmp (stream2_type_string,
+ "audio/x-pn-multirate-realaudio-live") == 0) {
+ stream_type = GST_RMDEMUX_STREAM_AUDIO;
+ } else if (strcmp (stream2_type_string, "audio/x-ralf-mpeg4-generic") == 0) {
+ /* Another audio type found in the real testsuite */
+ stream_type = GST_RMDEMUX_STREAM_AUDIO;
+ } else if (strcmp (stream1_type_string, "") == 0 &&
+ strcmp (stream2_type_string, "logical-fileinfo") == 0) {
+ stream_type = GST_RMDEMUX_STREAM_FILEINFO;
+ } else {
+ stream_type = GST_RMDEMUX_STREAM_UNKNOWN;
+ GST_WARNING_OBJECT (rmdemux, "unknown stream type \"%s\",\"%s\"",
+ stream1_type_string, stream2_type_string);
+ }
+ g_free (stream1_type_string);
+ g_free (stream2_type_string);
+
+ offset += 4;
+
+ stream->subtype = stream_type;
+ switch (stream_type) {
+
+ case GST_RMDEMUX_STREAM_VIDEO:
+ /* RV10/RV20/RV30/RV40 => video/x-pn-realvideo, version=1,2,3,4 */
+ stream->fourcc = RMDEMUX_FOURCC_GET (data + offset + 8);
+ stream->width = RMDEMUX_GUINT16_GET (data + offset + 12);
+ stream->height = RMDEMUX_GUINT16_GET (data + offset + 14);
+ stream->rate = RMDEMUX_GUINT16_GET (data + offset + 16);
+ stream->subformat = RMDEMUX_GUINT32_GET (data + offset + 26);
+ stream->format = RMDEMUX_GUINT32_GET (data + offset + 30);
+ stream->extra_data_size = length - (offset + 26);
+ stream->extra_data = (guint8 *) data + offset + 26;
+ /* Natural way to represent framerates here requires unsigned 32 bit
+ * numerator, which we don't have. For the nasty case, approximate...
+ */
+ {
+ guint32 numerator = RMDEMUX_GUINT16_GET (data + offset + 22) * 65536 +
+ RMDEMUX_GUINT16_GET (data + offset + 24);
+ if (numerator > G_MAXINT) {
+ stream->framerate_numerator = (gint) (numerator >> 1);
+ stream->framerate_denominator = 32768;
+ } else {
+ stream->framerate_numerator = (gint) numerator;
+ stream->framerate_denominator = 65536;
+ }
+ }
+
+ GST_DEBUG_OBJECT (rmdemux,
+ "Video stream with fourcc=%" GST_FOURCC_FORMAT
+ " width=%d height=%d rate=%d framerate=%d/%d subformat=%x format=%x extra_data_size=%d",
+ GST_FOURCC_ARGS (stream->fourcc), stream->width, stream->height,
+ stream->rate, stream->framerate_numerator,
+ stream->framerate_denominator, stream->subformat, stream->format,
+ stream->extra_data_size);
+ break;
+ case GST_RMDEMUX_STREAM_AUDIO:{
+ stream->version = RMDEMUX_GUINT16_GET (data + offset + 4);
+ GST_INFO ("stream version = %u", stream->version);
+ switch (stream->version) {
+ case 3:
+ stream->fourcc = GST_RM_AUD_14_4;
+ stream->packet_size = 20;
+ stream->rate = 8000;
+ stream->n_channels = 1;
+ stream->sample_width = 16;
+ stream->flavor = 1;
+ stream->leaf_size = 0;
+ stream->height = 0;
+ break;
+ case 4:
+ stream->flavor = RMDEMUX_GUINT16_GET (data + offset + 22);
+ stream->packet_size = RMDEMUX_GUINT32_GET (data + offset + 24);
+ /* stream->frame_size = RMDEMUX_GUINT32_GET (data + offset + 42); */
+ stream->leaf_size = RMDEMUX_GUINT16_GET (data + offset + 44);
+ stream->height = RMDEMUX_GUINT16_GET (data + offset + 40);
+ stream->rate = RMDEMUX_GUINT16_GET (data + offset + 48);
+ stream->sample_width = RMDEMUX_GUINT16_GET (data + offset + 52);
+ stream->n_channels = RMDEMUX_GUINT16_GET (data + offset + 54);
+ stream->fourcc = RMDEMUX_FOURCC_GET (data + offset + 62);
+ stream->extra_data_size = RMDEMUX_GUINT32_GET (data + offset + 69);
+ GST_DEBUG_OBJECT (rmdemux, "%u bytes of extra codec data",
+ stream->extra_data_size);
+ if (length - (offset + 73) >= stream->extra_data_size) {
+ stream->extra_data = (guint8 *) data + offset + 73;
+ } else {
+ GST_WARNING_OBJECT (rmdemux, "codec data runs beyond MDPR chunk");
+ stream->extra_data_size = 0;
+ }
+ break;
+ case 5:
+ stream->flavor = RMDEMUX_GUINT16_GET (data + offset + 22);
+ stream->packet_size = RMDEMUX_GUINT32_GET (data + offset + 24);
+ /* stream->frame_size = RMDEMUX_GUINT32_GET (data + offset + 42); */
+ stream->leaf_size = RMDEMUX_GUINT16_GET (data + offset + 44);
+ stream->height = RMDEMUX_GUINT16_GET (data + offset + 40);
+ stream->rate = RMDEMUX_GUINT16_GET (data + offset + 54);
+ stream->sample_width = RMDEMUX_GUINT16_GET (data + offset + 58);
+ stream->n_channels = RMDEMUX_GUINT16_GET (data + offset + 60);
+ stream->fourcc = RMDEMUX_FOURCC_GET (data + offset + 66);
+ stream->extra_data_size = RMDEMUX_GUINT32_GET (data + offset + 74);
+ GST_DEBUG_OBJECT (rmdemux, "%u bytes of extra codec data",
+ stream->extra_data_size);
+ if (length - (offset + 78) >= stream->extra_data_size) {
+ stream->extra_data = (guint8 *) data + offset + 78;
+ } else {
+ GST_WARNING_OBJECT (rmdemux, "codec data runs beyond MDPR chunk");
+ stream->extra_data_size = 0;
+ }
+ break;
+ default:{
+ GST_WARNING_OBJECT (rmdemux, "Unhandled audio stream version %d",
+ stream->version);
+ break;
+ }
+ }
+ /* 14_4, 28_8, cook, dnet, sipr, raac, racp, ralf, atrc */
+ GST_DEBUG_OBJECT (rmdemux,
+ "Audio stream with rate=%d sample_width=%d n_channels=%d",
+ stream->rate, stream->sample_width, stream->n_channels);
+
+ break;
+ }
+ case GST_RMDEMUX_STREAM_FILEINFO:
+ {
+ int element_nb;
+
+ /* Length of this section */
+ GST_DEBUG_OBJECT (rmdemux, "length2: 0x%08x",
+ RMDEMUX_GUINT32_GET (data + offset));
+ offset += 4;
+
+ /* Unknown : 00 00 00 00 */
+ offset += 4;
+
+ /* Number of variables that would follow (loop iterations) */
+ element_nb = RMDEMUX_GUINT32_GET (data + offset);
+ offset += 4;
+
+ while (element_nb) {
+ /* Category Id : 00 00 00 XX 00 00 */
+ offset += 6;
+
+ /* Variable Name */
+ offset += re_skip_pascal_string (data + offset);
+
+ /* Variable Value Type */
+ /* 00 00 00 00 00 => integer/boolean, preceded by length */
+ /* 00 00 00 02 00 => pascal string, preceded by length, no trailing \0 */
+ offset += 5;
+
+ /* Variable Value */
+ offset += re_skip_pascal_string (data + offset);
+
+ element_nb--;
+ }
+ }
+ break;
+ case GST_RMDEMUX_STREAM_UNKNOWN:
+ default:
+ break;
+ }
+
+ gst_rmdemux_add_stream (rmdemux, stream);
+}
+
+static guint
+gst_rmdemux_parse_indx (GstRMDemux * rmdemux, const guint8 * data, int length)
+{
+ int n;
+ int id;
+
+ n = RMDEMUX_GUINT32_GET (data);
+ id = RMDEMUX_GUINT16_GET (data + 4);
+ rmdemux->index_offset = RMDEMUX_GUINT32_GET (data + 6);
+
+ GST_DEBUG_OBJECT (rmdemux, "Number of indices=%d Stream ID=%d length=%d", n,
+ id, length);
+
+ /* Point to the next index_stream */
+ rmdemux->index_stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
+
+ /* Return the length of the index */
+ return 14 * n;
+}
+
+static void
+gst_rmdemux_parse_indx_data (GstRMDemux * rmdemux, const guint8 * data,
+ int length)
+{
+ int i;
+ int n;
+ GstRMDemuxIndex *index;
+
+ /* The number of index records */
+ n = length / 14;
+
+ if (rmdemux->index_stream == NULL)
+ return;
+
+ /* don't parse the index a second time when operating pull-based and
+ * reaching the end of the file */
+ if (rmdemux->index_stream->index_length > 0) {
+ GST_DEBUG_OBJECT (rmdemux, "Already have an index for this stream");
+ return;
+ }
+
+ index = g_malloc (sizeof (GstRMDemuxIndex) * n);
+ rmdemux->index_stream->index = index;
+ rmdemux->index_stream->index_length = n;
+
+ for (i = 0; i < n; i++) {
+ index[i].timestamp = RMDEMUX_GUINT32_GET (data + 2) * GST_MSECOND;
+ index[i].offset = RMDEMUX_GUINT32_GET (data + 6);
+
+ GST_DEBUG_OBJECT (rmdemux, "Index found for timestamp=%f (at offset=%x)",
+ gst_guint64_to_gdouble (index[i].timestamp) / GST_SECOND,
+ index[i].offset);
+ data += 14;
+ }
+}
+
+static void
+gst_rmdemux_parse_data (GstRMDemux * rmdemux, const guint8 * data, int length)
+{
+ rmdemux->n_chunks = RMDEMUX_GUINT32_GET (data);
+ rmdemux->data_offset = RMDEMUX_GUINT32_GET (data + 4);
+ rmdemux->chunk_index = 0;
+ GST_DEBUG_OBJECT (rmdemux, "Data chunk found with %d packets "
+ "(next data at 0x%08x)", rmdemux->n_chunks, rmdemux->data_offset);
+}
+
+static void
+gst_rmdemux_parse_cont (GstRMDemux * rmdemux, const guint8 * data, int length)
+{
+ GstTagList *tags;
+
+ tags = gst_rm_utils_read_tags (data, length, gst_rm_utils_read_string16);
+
+ GST_LOG_OBJECT (rmdemux, "tags: %" GST_PTR_FORMAT, tags);
+
+ rmdemux->pending_tags =
+ gst_tag_list_merge (rmdemux->pending_tags, tags, GST_TAG_MERGE_APPEND);
+}
+
+static void
+gst_rmdemux_stream_clear_cached_subpackets (GstRMDemux * rmdemux,
+ GstRMDemuxStream * stream)
+{
+ if (stream->subpackets == NULL || stream->subpackets->len == 0)
+ return;
+
+ GST_DEBUG_OBJECT (rmdemux, "discarding %u previously collected subpackets",
+ stream->subpackets->len);
+ g_ptr_array_foreach (stream->subpackets, (GFunc) gst_mini_object_unref, NULL);
+ g_ptr_array_set_size (stream->subpackets, 0);
+}
+
+static GstFlowReturn
+gst_rmdemux_descramble_audio (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
+{
+ GstFlowReturn ret = GST_FLOW_ERROR;
+ GstBuffer *outbuf;
+ GstMapInfo outmap;
+ guint packet_size = stream->packet_size;
+ guint height = stream->subpackets->len;
+ guint leaf_size = stream->leaf_size;
+ guint p, x;
+
+ g_assert (stream->height == height);
+
+ GST_LOG ("packet_size = %u, leaf_size = %u, height= %u", packet_size,
+ leaf_size, height);
+
+ outbuf = gst_buffer_new_and_alloc (height * packet_size);
+ gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+
+ for (p = 0; p < height; ++p) {
+ GstBuffer *b = g_ptr_array_index (stream->subpackets, p);
+ GstMapInfo map;
+
+ gst_buffer_map (b, &map, GST_MAP_READ);
+
+ if (p == 0) {
+ GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (b);
+ GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (b);
+ }
+
+ for (x = 0; x < packet_size / leaf_size; ++x) {
+ guint idx;
+
+ idx = height * x + ((height + 1) / 2) * (p % 2) + (p / 2);
+
+ /* GST_LOG ("%3u => %3u", (height * p) + x, idx); */
+ memcpy (outmap.data + leaf_size * idx, map.data + leaf_size * x,
+ leaf_size);
+ }
+ gst_buffer_unmap (b, &map);
+ }
+ gst_buffer_unmap (outbuf, &outmap);
+
+ /* some decoders, such as realaudiodec, need to be fed in packet units */
+ for (p = 0; p < height; ++p) {
+ GstBuffer *subbuf;
+
+ subbuf =
+ gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, p * packet_size,
+ packet_size);
+
+ GST_LOG_OBJECT (rmdemux, "pushing buffer dts %" GST_TIME_FORMAT ", pts %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DTS (subbuf)),
+ GST_TIME_ARGS (GST_BUFFER_PTS (subbuf)));
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (subbuf, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+
+ ret = gst_pad_push (stream->pad, subbuf);
+ if (ret != GST_FLOW_OK)
+ break;
+ }
+
+ gst_buffer_unref (outbuf);
+
+ gst_rmdemux_stream_clear_cached_subpackets (rmdemux, stream);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rmdemux_descramble_dnet_audio (GstRMDemux * rmdemux,
+ GstRMDemuxStream * stream)
+{
+ GstBuffer *buf;
+
+ buf = g_ptr_array_index (stream->subpackets, 0);
+ g_ptr_array_index (stream->subpackets, 0) = NULL;
+ g_ptr_array_set_size (stream->subpackets, 0);
+
+ buf = gst_rm_utils_descramble_dnet_buffer (buf);
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+ return gst_pad_push (stream->pad, buf);
+}
+
+static GstFlowReturn
+gst_rmdemux_descramble_mp4a_audio (GstRMDemux * rmdemux,
+ GstRMDemuxStream * stream)
+{
+ GstFlowReturn res;
+ GstBuffer *buf, *outbuf;
+ guint frames, index, i;
+ GstMapInfo map;
+ GstClockTime timestamp;
+
+ res = GST_FLOW_OK;
+
+ buf = g_ptr_array_index (stream->subpackets, 0);
+ g_ptr_array_index (stream->subpackets, 0) = NULL;
+ g_ptr_array_set_size (stream->subpackets, 0);
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ timestamp = GST_BUFFER_PTS (buf);
+
+ frames = (map.data[1] & 0xf0) >> 4;
+ index = 2 * frames + 2;
+
+ for (i = 0; i < frames; i++) {
+ guint len = (map.data[i * 2 + 2] << 8) | map.data[i * 2 + 3];
+
+ outbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, index, len);
+ if (i == 0) {
+ GST_BUFFER_PTS (outbuf) = timestamp;
+ GST_BUFFER_DTS (outbuf) = timestamp;
+ }
+
+ index += len;
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+ res = gst_pad_push (stream->pad, outbuf);
+ if (res != GST_FLOW_OK)
+ break;
+ }
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+ return res;
+}
+
+static GstFlowReturn
+gst_rmdemux_descramble_sipr_audio (GstRMDemux * rmdemux,
+ GstRMDemuxStream * stream)
+{
+ GstFlowReturn ret;
+ GstBuffer *outbuf;
+ GstMapInfo outmap;
+ guint packet_size = stream->packet_size;
+ guint height = stream->subpackets->len;
+ guint p;
+
+ g_assert (stream->height == height);
+
+ GST_LOG ("packet_size = %u, leaf_size = %u, height= %u", packet_size,
+ stream->leaf_size, height);
+
+ outbuf = gst_buffer_new_and_alloc (height * packet_size);
+ gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+
+ for (p = 0; p < height; ++p) {
+ GstBuffer *b = g_ptr_array_index (stream->subpackets, p);
+
+ if (p == 0) {
+ GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (b);
+ GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (b);
+ }
+
+ gst_buffer_extract (b, 0, outmap.data + packet_size * p, packet_size);
+ }
+ gst_buffer_unmap (outbuf, &outmap);
+
+ GST_LOG_OBJECT (rmdemux, "pushing buffer dts %" GST_TIME_FORMAT ", pts %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
+ GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)));
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+
+ outbuf = gst_rm_utils_descramble_sipr_buffer (outbuf);
+
+ ret = gst_pad_push (stream->pad, outbuf);
+
+ gst_rmdemux_stream_clear_cached_subpackets (rmdemux, stream);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rmdemux_handle_scrambled_packet (GstRMDemux * rmdemux,
+ GstRMDemuxStream * stream, GstBuffer * buf, gboolean keyframe)
+{
+ GstFlowReturn ret;
+
+ if (stream->subpackets == NULL)
+ stream->subpackets = g_ptr_array_sized_new (stream->subpackets_needed);
+
+ GST_LOG ("Got subpacket %u/%u, len=%" G_GSIZE_FORMAT ", key=%d",
+ stream->subpackets->len + 1, stream->subpackets_needed,
+ gst_buffer_get_size (buf), keyframe);
+
+ if (keyframe && stream->subpackets->len > 0) {
+ gst_rmdemux_stream_clear_cached_subpackets (rmdemux, stream);
+ }
+
+ g_ptr_array_add (stream->subpackets, buf);
+
+ if (stream->subpackets->len < stream->subpackets_needed)
+ return GST_FLOW_OK;
+
+ g_assert (stream->subpackets->len >= 1);
+
+ switch (stream->fourcc) {
+ case GST_RM_AUD_DNET:
+ ret = gst_rmdemux_descramble_dnet_audio (rmdemux, stream);
+ break;
+ case GST_RM_AUD_COOK:
+ case GST_RM_AUD_ATRC:
+ ret = gst_rmdemux_descramble_audio (rmdemux, stream);
+ break;
+ case GST_RM_AUD_RAAC:
+ case GST_RM_AUD_RACP:
+ ret = gst_rmdemux_descramble_mp4a_audio (rmdemux, stream);
+ break;
+ case GST_RM_AUD_SIPR:
+ ret = gst_rmdemux_descramble_sipr_audio (rmdemux, stream);
+ break;
+ default:
+ ret = GST_FLOW_ERROR;
+ g_assert_not_reached ();
+ }
+
+ return ret;
+}
+
+#define PARSE_NUMBER(data, size, number, label) \
+G_STMT_START { \
+ if (size < 2) \
+ goto label; \
+ number = GST_READ_UINT16_BE (data); \
+ if (!(number & 0xc000)) { \
+ if (size < 4) \
+ goto label; \
+ number = GST_READ_UINT32_BE (data); \
+ data += 4; \
+ size -= 4; \
+ } else { \
+ number &= 0x3fff; \
+ data += 2; \
+ size -= 2; \
+ } \
+} G_STMT_END
+
+static GstFlowReturn
+gst_rmdemux_parse_video_packet (GstRMDemux * rmdemux, GstRMDemuxStream * stream,
+ GstBuffer * in, guint offset, guint16 version,
+ GstClockTime timestamp, gboolean key)
+{
+ GstFlowReturn ret;
+ GstMapInfo map;
+ const guint8 *data;
+ gsize size;
+
+ gst_buffer_map (in, &map, GST_MAP_READ);
+
+ data = map.data + offset;
+ size = map.size - offset;
+
+ /* if size <= 2, we want this method to return the same GstFlowReturn as it
+ * was previously for that given stream. */
+ ret = GST_PAD_LAST_FLOW_RETURN (stream->pad);
+
+ while (size > 2) {
+ guint8 pkg_header;
+ guint pkg_offset;
+ guint pkg_length;
+ guint pkg_subseq = 0, pkg_seqnum = G_MAXUINT;
+ guint fragment_size;
+ GstBuffer *fragment;
+
+ pkg_header = *data++;
+ size--;
+
+ /* packet header
+ * bit 7: 1=last block in block chain
+ * bit 6: 1=short header (only one block?)
+ */
+ if ((pkg_header & 0xc0) == 0x40) {
+ /* skip unknown byte */
+ data++;
+ size--;
+ pkg_offset = 0;
+ pkg_length = size;
+ } else {
+ if ((pkg_header & 0x40) == 0) {
+ pkg_subseq = (*data++) & 0x7f;
+ size--;
+ } else {
+ pkg_subseq = 0;
+ }
+
+ /* length */
+ PARSE_NUMBER (data, size, pkg_length, not_enough_data);
+
+ /* offset */
+ PARSE_NUMBER (data, size, pkg_offset, not_enough_data);
+
+ /* seqnum */
+ if (size < 1)
+ goto not_enough_data;
+
+ pkg_seqnum = *data++;
+ size--;
+ }
+
+ GST_DEBUG_OBJECT (rmdemux,
+ "seq %d, subseq %d, offset %d, length %d, size %" G_GSIZE_FORMAT
+ ", header %02x", pkg_seqnum, pkg_subseq, pkg_offset, pkg_length, size,
+ pkg_header);
+
+ /* calc size of fragment */
+ if ((pkg_header & 0xc0) == 0x80) {
+ fragment_size = pkg_offset;
+ } else {
+ if ((pkg_header & 0xc0) == 0)
+ fragment_size = size;
+ else
+ fragment_size = pkg_length;
+ }
+ GST_DEBUG_OBJECT (rmdemux, "fragment size %d", fragment_size);
+
+ /* get the fragment */
+ fragment =
+ gst_buffer_copy_region (in, GST_BUFFER_COPY_ALL, data - map.data,
+ fragment_size);
+
+ if (pkg_subseq == 1) {
+ GST_DEBUG_OBJECT (rmdemux, "start new fragment");
+ gst_adapter_clear (stream->adapter);
+ stream->frag_current = 0;
+ stream->frag_count = 0;
+ stream->frag_length = pkg_length;
+ } else if (pkg_subseq == 0) {
+ GST_DEBUG_OBJECT (rmdemux, "non fragmented packet");
+ stream->frag_current = 0;
+ stream->frag_count = 0;
+ stream->frag_length = fragment_size;
+ }
+
+ /* put fragment in adapter */
+ gst_adapter_push (stream->adapter, fragment);
+ stream->frag_offset[stream->frag_count] = stream->frag_current;
+ stream->frag_current += fragment_size;
+ stream->frag_count++;
+
+ if (stream->frag_count > MAX_FRAGS)
+ goto too_many_fragments;
+
+ GST_DEBUG_OBJECT (rmdemux, "stored fragment in adapter %d/%d",
+ stream->frag_current, stream->frag_length);
+
+ /* flush fragment when complete */
+ if (stream->frag_current >= stream->frag_length) {
+ GstBuffer *out;
+ GstMapInfo outmap;
+ guint8 *outdata;
+ guint header_size;
+ gint i, avail;
+
+ /* calculate header size, which is:
+ * 1 byte for the number of fragments - 1
+ * for each fragment:
+ * 4 bytes 0x00000001 little endian
+ * 4 bytes fragment offset
+ *
+ * This is also the matroska header for realvideo, the decoder needs the
+ * fragment offsets, both in ffmpeg and real .so, so we just give it that
+ * in front of the data.
+ */
+ header_size = 1 + (8 * (stream->frag_count));
+
+ GST_DEBUG_OBJECT (rmdemux,
+ "fragmented completed. count %d, header_size %u", stream->frag_count,
+ header_size);
+
+ avail = gst_adapter_available (stream->adapter);
+
+ out = gst_buffer_new_and_alloc (header_size + avail);
+ gst_buffer_map (out, &outmap, GST_MAP_WRITE);
+ outdata = outmap.data;
+
+ /* create header */
+ *outdata++ = stream->frag_count - 1;
+ for (i = 0; i < stream->frag_count; i++) {
+ GST_WRITE_UINT32_LE (outdata, 0x00000001);
+ outdata += 4;
+ GST_WRITE_UINT32_LE (outdata, stream->frag_offset[i]);
+ outdata += 4;
+ }
+
+ /* copy packet data after the header now */
+ gst_adapter_copy (stream->adapter, outdata, 0, avail);
+ gst_adapter_flush (stream->adapter, avail);
+
+ stream->frag_current = 0;
+ stream->frag_count = 0;
+ stream->frag_length = 0;
+
+ if (timestamp != -1) {
+ if (rmdemux->first_ts != -1 && timestamp > rmdemux->first_ts)
+ timestamp -= rmdemux->first_ts;
+ else
+ timestamp = 0;
+
+ if (rmdemux->base_ts != -1)
+ timestamp += rmdemux->base_ts;
+ }
+ gst_buffer_unmap (out, &outmap);
+
+ /* video has DTS */
+ GST_BUFFER_DTS (out) = timestamp;
+ GST_BUFFER_PTS (out) = GST_CLOCK_TIME_NONE;
+
+ GST_LOG_OBJECT (rmdemux, "pushing timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+
+ if (!key) {
+ GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ ret = gst_pad_push (stream->pad, out);
+ ret = gst_flow_combiner_update_flow (rmdemux->flowcombiner, ret);
+ if (ret != GST_FLOW_OK)
+ break;
+
+ timestamp = GST_CLOCK_TIME_NONE;
+ }
+ data += fragment_size;
+ size -= fragment_size;
+ }
+ GST_DEBUG_OBJECT (rmdemux, "%" G_GSIZE_FORMAT " bytes left", size);
+
+done:
+ gst_buffer_unmap (in, &map);
+ gst_buffer_unref (in);
+
+ return ret;
+
+ /* ERRORS */
+not_enough_data:
+ {
+ GST_ELEMENT_WARNING (rmdemux, STREAM, DECODE, ("Skipping bad packet."),
+ (NULL));
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+too_many_fragments:
+ {
+ GST_ELEMENT_ERROR (rmdemux, STREAM, DECODE,
+ ("Got more fragments (%u) than can be handled (%u)",
+ stream->frag_count, MAX_FRAGS), (NULL));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+}
+
+static GstFlowReturn
+gst_rmdemux_parse_audio_packet (GstRMDemux * rmdemux, GstRMDemuxStream * stream,
+ GstBuffer * in, guint offset, guint16 version,
+ GstClockTime timestamp, gboolean key)
+{
+ GstFlowReturn ret;
+ GstBuffer *buffer;
+
+ buffer = gst_buffer_copy_region (in, GST_BUFFER_COPY_MEMORY, offset, -1);
+
+ if (rmdemux->first_ts != -1 && timestamp > rmdemux->first_ts)
+ timestamp -= rmdemux->first_ts;
+ else
+ timestamp = 0;
+
+ if (rmdemux->base_ts != -1)
+ timestamp += rmdemux->base_ts;
+
+ GST_BUFFER_PTS (buffer) = timestamp;
+ GST_BUFFER_DTS (buffer) = timestamp;
+
+ if (stream->needs_descrambling) {
+ GST_LOG_OBJECT (rmdemux, "descramble timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ ret = gst_rmdemux_handle_scrambled_packet (rmdemux, stream, buffer, key);
+ } else {
+ GST_LOG_OBJECT (rmdemux,
+ "Pushing buffer of size %" G_GSIZE_FORMAT ", timestamp %"
+ GST_TIME_FORMAT "to pad %s", gst_buffer_get_size (buffer),
+ GST_TIME_ARGS (timestamp), GST_PAD_NAME (stream->pad));
+
+ if (stream->discont) {
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+ stream->discont = FALSE;
+ }
+ ret = gst_pad_push (stream->pad, buffer);
+ }
+
+ gst_buffer_unref (in);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rmdemux_parse_packet (GstRMDemux * rmdemux, GstBuffer * in, guint16 version)
+{
+ guint16 id;
+ GstRMDemuxStream *stream;
+ gsize size, offset;
+ GstFlowReturn cret, ret;
+ GstClockTime timestamp;
+ gboolean key;
+ GstMapInfo map;
+ guint8 *data;
+ guint8 flags;
+ guint32 ts;
+
+ gst_buffer_map (in, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ /* stream number */
+ id = RMDEMUX_GUINT16_GET (data);
+
+ stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
+ if (!stream || !stream->pad)
+ goto unknown_stream;
+
+ /* timestamp in Msec */
+ ts = RMDEMUX_GUINT32_GET (data + 2);
+ timestamp = ts * GST_MSECOND;
+
+ rmdemux->segment.position = timestamp;
+
+ GST_LOG_OBJECT (rmdemux, "Parsing a packet for stream=%d, timestamp=%"
+ GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT ", version=%d, ts=%u", id,
+ GST_TIME_ARGS (timestamp), size, version, ts);
+
+ if (rmdemux->first_ts == GST_CLOCK_TIME_NONE) {
+ GST_DEBUG_OBJECT (rmdemux, "First timestamp: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ rmdemux->first_ts = timestamp;
+ }
+
+ /* skip stream_id and timestamp */
+ data += (2 + 4);
+ size -= (2 + 4);
+
+ /* get flags */
+ flags = GST_READ_UINT8 (data + 1);
+
+ data += 2;
+ size -= 2;
+
+ /* version 1 has an extra byte */
+ if (version == 1) {
+ data += 1;
+ size -= 1;
+ }
+ offset = data - map.data;
+ gst_buffer_unmap (in, &map);
+
+ key = (flags & 0x02) != 0;
+ GST_DEBUG_OBJECT (rmdemux, "flags %d, Keyframe %d", flags, key);
+
+ if (rmdemux->need_newsegment) {
+ GstEvent *event;
+
+ event = gst_event_new_segment (&rmdemux->segment);
+
+ GST_DEBUG_OBJECT (rmdemux, "sending NEWSEGMENT event, segment.start= %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment.start));
+
+ gst_rmdemux_send_event (rmdemux, event);
+ rmdemux->need_newsegment = FALSE;
+
+ if (rmdemux->pending_tags != NULL) {
+ gst_rmdemux_send_event (rmdemux,
+ gst_event_new_tag (rmdemux->pending_tags));
+ rmdemux->pending_tags = NULL;
+ }
+ }
+
+ if (stream->pending_tags != NULL) {
+ GST_LOG_OBJECT (stream->pad, "tags %" GST_PTR_FORMAT, stream->pending_tags);
+ gst_pad_push_event (stream->pad, gst_event_new_tag (stream->pending_tags));
+ stream->pending_tags = NULL;
+ }
+
+ if ((rmdemux->offset + size) <= stream->seek_offset) {
+ GST_DEBUG_OBJECT (rmdemux,
+ "Stream %d is skipping: seek_offset=%d, offset=%d, size=%"
+ G_GSIZE_FORMAT, stream->id, stream->seek_offset, rmdemux->offset, size);
+ cret = GST_FLOW_OK;
+ gst_buffer_unref (in);
+ goto beach;
+ }
+
+ /* do special headers */
+ if (stream->subtype == GST_RMDEMUX_STREAM_VIDEO) {
+ ret =
+ gst_rmdemux_parse_video_packet (rmdemux, stream, in, offset,
+ version, timestamp, key);
+ } else if (stream->subtype == GST_RMDEMUX_STREAM_AUDIO) {
+ ret =
+ gst_rmdemux_parse_audio_packet (rmdemux, stream, in, offset,
+ version, timestamp, key);
+ } else {
+ gst_buffer_unref (in);
+ ret = GST_FLOW_OK;
+ }
+
+ cret = gst_flow_combiner_update_flow (rmdemux->flowcombiner, ret);
+
+beach:
+ return cret;
+
+ /* ERRORS */
+unknown_stream:
+ {
+ GST_WARNING_OBJECT (rmdemux, "No stream for stream id %d in parsing "
+ "data packet", id);
+ gst_buffer_unmap (in, &map);
+ gst_buffer_unref (in);
+ return GST_FLOW_OK;
+ }
+}
+
+gboolean
+gst_rmdemux_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rmdemux",
+ GST_RANK_PRIMARY, GST_TYPE_RMDEMUX);
+}
diff --git a/gst/realmedia/rmdemux.h b/gst/realmedia/rmdemux.h
new file mode 100644
index 0000000..68a1700
--- /dev/null
+++ b/gst/realmedia/rmdemux.h
@@ -0,0 +1,165 @@
+/* GStreamer RealMedia demuxer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RMDEMUX_H__
+#define __GST_RMDEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
+#include <gst/pbutils/descriptions.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RMDEMUX \
+ (gst_rmdemux_get_type())
+#define GST_RMDEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RMDEMUX,GstRMDemux))
+#define GST_RMDEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RMDEMUX,GstRMDemuxClass))
+#define GST_IS_RMDEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RMDEMUX))
+#define GST_IS_RMDEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RMDEMUX))
+
+typedef enum
+{
+ RMDEMUX_STATE_NULL,
+ RMDEMUX_STATE_HEADER,
+ RMDEMUX_STATE_HEADER_UNKNOWN,
+ RMDEMUX_STATE_HEADER_RMF,
+ RMDEMUX_STATE_HEADER_PROP,
+ RMDEMUX_STATE_HEADER_MDPR,
+ RMDEMUX_STATE_HEADER_INDX,
+ RMDEMUX_STATE_HEADER_DATA,
+ RMDEMUX_STATE_HEADER_CONT,
+ RMDEMUX_STATE_HEADER_SEEKING,
+ RMDEMUX_STATE_SEEKING,
+ RMDEMUX_STATE_DATA_PACKET,
+ RMDEMUX_STATE_SEEKING_EOS,
+ RMDEMUX_STATE_EOS,
+ RMDEMUX_STATE_INDX_DATA
+} GstRMDemuxState;
+
+typedef enum
+{
+ RMDEMUX_LOOP_STATE_HEADER,
+ RMDEMUX_LOOP_STATE_INDEX,
+ RMDEMUX_LOOP_STATE_DATA
+} GstRMDemuxLoopState;
+
+typedef enum
+{
+ GST_RMDEMUX_STREAM_UNKNOWN,
+ GST_RMDEMUX_STREAM_VIDEO,
+ GST_RMDEMUX_STREAM_AUDIO,
+ GST_RMDEMUX_STREAM_FILEINFO
+} GstRMDemuxStreamType;
+
+typedef struct _GstRMDemux GstRMDemux;
+typedef struct _GstRMDemuxClass GstRMDemuxClass;
+typedef struct _GstRMDemuxStream GstRMDemuxStream;
+
+struct _GstRMDemux {
+ GstElement element;
+
+ /* pads */
+ GstPad *sinkpad;
+
+ gboolean have_group_id;
+ guint group_id;
+
+ GSList *streams;
+ guint n_video_streams;
+ guint n_audio_streams;
+ GstAdapter *adapter;
+ gboolean have_pads;
+
+ GstFlowCombiner *flowcombiner;
+
+ guint32 timescale;
+ guint64 duration;
+ guint32 avg_packet_size;
+ guint32 index_offset;
+ guint32 data_offset;
+ guint32 num_packets;
+
+ guint offset;
+ gboolean seekable;
+
+ GstRMDemuxState state;
+ GstRMDemuxLoopState loop_state;
+ GstRMDemuxStream *index_stream;
+
+ /* playback start/stop positions */
+ GstSegment segment;
+ gboolean segment_running;
+ gboolean running;
+
+ /* Whether we need to send a newsegment event */
+ gboolean need_newsegment;
+
+ /* Current timestamp */
+ GstClockTime cur_timestamp;
+
+ /* First timestamp */
+ GstClockTime base_ts;
+ GstClockTime first_ts;
+
+ int n_chunks;
+ int chunk_index;
+
+ guint32 object_id;
+ guint32 size;
+ guint16 object_version;
+
+ /* container tags for all streams */
+ GstTagList *pending_tags;
+};
+
+struct _GstRMDemuxClass {
+ GstElementClass parent_class;
+};
+
+/* RealMedia VideoCodec FOURCC codes */
+#define GST_RM_VDO_RV10 GST_MAKE_FOURCC('R','V','1','0') // RealVideo 1
+#define GST_RM_VDO_RV20 GST_MAKE_FOURCC('R','V','2','0') // RealVideo G2
+#define GST_RM_VDO_RV30 GST_MAKE_FOURCC('R','V','3','0') // RealVideo 8
+#define GST_RM_VDO_RV40 GST_MAKE_FOURCC('R','V','4','0') // RealVideo 9+10
+
+/* RealMedia AudioCodec FOURCC codes */
+#define GST_RM_AUD_14_4 GST_MAKE_FOURCC('1','4','_','4') // 14.4 Audio Codec
+#define GST_RM_AUD_28_8 GST_MAKE_FOURCC('2','8','_','8') // 28.8 Audio Codec
+#define GST_RM_AUD_COOK GST_MAKE_FOURCC('c','o','o','k') // Cooker G2 Audio Codec
+#define GST_RM_AUD_DNET GST_MAKE_FOURCC('d','n','e','t') // DolbyNet Audio Codec (low bitrate Dolby AC3)
+#define GST_RM_AUD_SIPR GST_MAKE_FOURCC('s','i','p','r') // Sipro/ACELP.NET Voice Codec
+#define GST_RM_AUD_RAAC GST_MAKE_FOURCC('r','a','a','c') // LE-AAC Audio Codec
+#define GST_RM_AUD_RACP GST_MAKE_FOURCC('r','a','c','p') // HE-AAC Audio Codec
+#define GST_RM_AUD_RALF GST_MAKE_FOURCC('r','a','l','f') // RealAudio Lossless
+#define GST_RM_AUD_ATRC GST_MAKE_FOURCC('a','t','r','c') // Sony ATRAC3 Audio Codec
+
+#define GST_RM_AUD_xRA4 GST_MAKE_FOURCC('.','r','a','4') // Not a real audio codec
+#define GST_RM_AUD_xRA5 GST_MAKE_FOURCC('.','r','a','5') // Not a real audio codec
+
+gboolean gst_rmdemux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RMDEMUX_H__ */
diff --git a/gst/realmedia/rmutils.c b/gst/realmedia/rmutils.c
new file mode 100644
index 0000000..c9bc098
--- /dev/null
+++ b/gst/realmedia/rmutils.c
@@ -0,0 +1,294 @@
+/* GStreamer RealMedia utility functions
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "rmutils.h"
+
+gchar *
+gst_rm_utils_read_string8 (const guint8 * data, guint datalen,
+ guint * p_total_len)
+{
+ gint length;
+
+ if (p_total_len)
+ *p_total_len = 0;
+
+ if (datalen < 1)
+ return NULL;
+
+ length = GST_READ_UINT8 (data);
+ if (datalen < (1 + length))
+ return NULL;
+
+ if (p_total_len)
+ *p_total_len = 1 + length;
+
+ return g_strndup ((gchar *) data + 1, length);
+}
+
+gchar *
+gst_rm_utils_read_string16 (const guint8 * data, guint datalen,
+ guint * p_total_len)
+{
+ gint length;
+
+ if (p_total_len)
+ *p_total_len = 0;
+
+ if (datalen < 2)
+ return NULL;
+
+ length = GST_READ_UINT16_BE (data);
+ if (datalen < (2 + length))
+ return NULL;
+
+ if (p_total_len)
+ *p_total_len = 2 + length;
+
+ return g_strndup ((gchar *) data + 2, length);
+}
+
+GstTagList *
+gst_rm_utils_read_tags (const guint8 * data, guint datalen,
+ GstRmUtilsStringReadFunc read_string_func)
+{
+ const gchar *gst_tags[] = { GST_TAG_TITLE, GST_TAG_ARTIST,
+ GST_TAG_COPYRIGHT, GST_TAG_COMMENT
+ };
+ GstTagList *tags;
+ guint i;
+
+ g_assert (read_string_func != NULL);
+
+ GST_DEBUG ("File Content : (CONT) len = %d", datalen);
+
+ tags = gst_tag_list_new_empty ();
+
+ for (i = 0; i < G_N_ELEMENTS (gst_tags); ++i) {
+ gchar *str = NULL;
+ guint total_length = 0;
+
+ str = read_string_func (data, datalen, &total_length);
+ data += total_length;
+ datalen -= total_length;
+
+ if (str != NULL && !g_utf8_validate (str, -1, NULL)) {
+ const gchar *encoding;
+ gchar *tmp;
+
+ encoding = g_getenv ("GST_TAG_ENCODING");
+ if (encoding == NULL || *encoding == '\0') {
+ if (g_get_charset (&encoding))
+ encoding = "ISO-8859-15";
+ }
+ GST_DEBUG ("converting tag from %s to UTF-8", encoding);
+ tmp = g_convert_with_fallback (str, -1, "UTF-8", encoding, (gchar *) "*",
+ NULL, NULL, NULL);
+ g_free (str);
+ str = tmp;
+ }
+
+ GST_DEBUG ("%s = %s", gst_tags[i], GST_STR_NULL (str));
+ if (str != NULL && *str != '\0') {
+ gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, gst_tags[i], str, NULL);
+ }
+ g_free (str);
+ }
+
+ if (gst_tag_list_n_tags (tags) > 0)
+ return tags;
+
+ gst_tag_list_unref (tags);
+ return NULL;
+}
+
+GstBuffer *
+gst_rm_utils_descramble_dnet_buffer (GstBuffer * buf)
+{
+ GstMapInfo map;
+ guint8 *data, *end, tmp;
+
+ buf = gst_buffer_make_writable (buf);
+
+ /* dnet = byte-order swapped AC3 */
+ gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+ data = map.data;
+ end = data + map.size;
+ while ((data + 1) < end) {
+ /* byte-swap */
+ tmp = data[0];
+ data[0] = data[1];
+ data[1] = tmp;
+ data += sizeof (guint16);
+ }
+ gst_buffer_unmap (buf, &map);
+ return buf;
+}
+
+static void
+gst_rm_utils_swap_nibbles (guint8 * data, gint idx1, gint idx2, gint len)
+{
+ guint8 *d1, *d2, tmp1 = 0, tmp2, tmp1n, tmp2n;
+
+ if ((idx2 & 1) && !(idx1 & 1)) {
+ /* align destination to a byte by swapping the indexes */
+ tmp1 = idx1;
+ idx1 = idx2;
+ idx2 = tmp1;
+ }
+ d1 = data + (idx1 >> 1);
+ d2 = data + (idx2 >> 1);
+
+ /* check if we have aligned offsets and we can copy bytes */
+ if ((idx1 & 1) == (idx2 & 1)) {
+ if (idx1 & 1) {
+ /* swap first nibble */
+ tmp1 = *d1;
+ tmp2 = *d2;
+ *d1++ = (tmp2 & 0xf0) | (tmp1 & 0x0f);
+ *d2++ = (tmp1 & 0xf0) | (tmp2 & 0x0f);
+ len--;
+ }
+ for (; len > 1; len -= 2) {
+ /* swap 2 nibbles */
+ tmp1 = *d1;
+ *d1++ = *d2;
+ *d2++ = tmp1;
+ }
+ if (len) {
+ /* swap leftover nibble */
+ tmp1 = *d1;
+ tmp2 = *d2;
+ *d1 = (tmp2 & 0x0f) | (tmp1 & 0xf0);
+ *d2 = (tmp1 & 0x0f) | (tmp2 & 0xf0);
+ }
+ } else {
+ /* preload nibbles from source */
+ tmp2n = *d1;
+ tmp2 = *d2;
+
+ for (; len > 1; len -= 2) {
+ /* assemble nibbles */
+ *d1++ = (tmp2n & 0x0f) | (tmp2 << 4);
+ tmp1n = *d1;
+ *d2++ = (tmp1n << 4) | (tmp1 >> 4);
+
+ tmp1 = tmp1n;
+ tmp2n = (tmp2 >> 4);
+ tmp2 = *d2;
+ }
+ if (len) {
+ /* last leftover */
+ *d1 = (tmp2 << 4) | (tmp2n & 0x0f);
+ *d2 = (tmp1 >> 4) | (tmp2 & 0xf0);
+ } else {
+ *d1 = (tmp1 & 0xf0) | (tmp2n);
+ }
+ }
+}
+
+static const gint sipr_swap_index[38][2] = {
+ {0, 63}, {1, 22}, {2, 44}, {3, 90},
+ {5, 81}, {7, 31}, {8, 86}, {9, 58},
+ {10, 36}, {12, 68}, {13, 39}, {14, 73},
+ {15, 53}, {16, 69}, {17, 57}, {19, 88},
+ {20, 34}, {21, 71}, {24, 46}, {25, 94},
+ {26, 54}, {28, 75}, {29, 50}, {32, 70},
+ {33, 92}, {35, 74}, {38, 85}, {40, 56},
+ {42, 87}, {43, 65}, {45, 59}, {48, 79},
+ {49, 93}, {51, 89}, {55, 95}, {61, 76},
+ {67, 83}, {77, 80}
+};
+
+GstBuffer *
+gst_rm_utils_descramble_sipr_buffer (GstBuffer * buf)
+{
+ GstMapInfo map;
+ gint n, bs;
+ gsize size;
+
+ size = gst_buffer_get_size (buf);
+
+ /* split the packet in 96 blocks of nibbles */
+ bs = size * 2 / 96;
+ if (bs == 0)
+ return buf;
+
+ buf = gst_buffer_make_writable (buf);
+
+ gst_buffer_map (buf, &map, GST_MAP_WRITE);
+
+ /* we need to perform 38 swaps on the blocks */
+ for (n = 0; n < 38; n++) {
+ gint idx1, idx2;
+
+ /* get the indexes of the blocks of nibbles that need swapping */
+ idx1 = bs * sipr_swap_index[n][0];
+ idx2 = bs * sipr_swap_index[n][1];
+
+ /* swap the blocks */
+ gst_rm_utils_swap_nibbles (map.data, idx1, idx2, bs);
+ }
+ gst_buffer_unmap (buf, &map);
+
+ return buf;
+}
+
+void
+gst_rm_utils_run_tests (void)
+{
+#if 0
+ guint8 tab1[] = { 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe };
+ guint8 tab2[8];
+
+ memcpy (tab2, tab1, 8);
+ gst_util_dump_mem (tab2, 8);
+
+ gst_rm_utils_swap_nibbles (tab2, 0, 8, 4);
+ gst_util_dump_mem (tab2, 8);
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 0, 8, 5);
+ gst_util_dump_mem (tab2, 8);
+
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 1, 8, 4);
+ gst_util_dump_mem (tab2, 8);
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 1, 8, 5);
+ gst_util_dump_mem (tab2, 8);
+
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 0, 9, 4);
+ gst_util_dump_mem (tab2, 8);
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 0, 9, 5);
+ gst_util_dump_mem (tab2, 8);
+
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 1, 9, 4);
+ gst_util_dump_mem (tab2, 8);
+ memcpy (tab2, tab1, 8);
+ gst_rm_utils_swap_nibbles (tab2, 1, 9, 5);
+ gst_util_dump_mem (tab2, 8);
+#endif
+}
diff --git a/gst/realmedia/rmutils.h b/gst/realmedia/rmutils.h
new file mode 100644
index 0000000..cf8bbb5
--- /dev/null
+++ b/gst/realmedia/rmutils.h
@@ -0,0 +1,50 @@
+/* GStreamer RealMedia utility functions
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RM_UTILS_H__
+#define __GST_RM_UTILS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef gchar * (*GstRmUtilsStringReadFunc) (const guint8 * data, guint datalen, guint * p_strlen);
+
+gchar *gst_rm_utils_read_string8 (const guint8 * data,
+ guint datalen,
+ guint * p_totallen);
+
+gchar *gst_rm_utils_read_string16 (const guint8 * data,
+ guint datalen,
+ guint * p_totallen);
+
+GstTagList *gst_rm_utils_read_tags (const guint8 * data,
+ guint datalen,
+ GstRmUtilsStringReadFunc func);
+
+GstBuffer *gst_rm_utils_descramble_dnet_buffer (GstBuffer * buf);
+GstBuffer *gst_rm_utils_descramble_sipr_buffer (GstBuffer * buf);
+
+void gst_rm_utils_run_tests (void);
+
+
+G_END_DECLS
+
+#endif /* __GST_RM_UTILS_H__ */
+
diff --git a/gst/realmedia/rtspreal.c b/gst/realmedia/rtspreal.c
new file mode 100644
index 0000000..b7b3383
--- /dev/null
+++ b/gst/realmedia/rtspreal.c
@@ -0,0 +1,735 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/* Element-Checklist-Version: 5 */
+
+/**
+ * SECTION:element-rtspreal
+ *
+ * A RealMedia RTSP extension
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "_stdint.h"
+#include <string.h>
+
+#include <gst/rtsp/gstrtspextension.h>
+
+#include "realhash.h"
+#include "rtspreal.h"
+#include "asmrules.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtspreal_debug);
+#define GST_CAT_DEFAULT (rtspreal_debug)
+
+#define SERVER_PREFIX "RealServer"
+#define DEFAULT_BANDWIDTH "10485800"
+
+static GstRTSPResult
+rtsp_ext_real_get_transports (GstRTSPExtension * ext,
+ GstRTSPLowerTrans protocols, gchar ** transport)
+{
+ GstRTSPReal *ctx = (GstRTSPReal *) ext;
+ GString *str;
+
+ if (!ctx->isreal)
+ return GST_RTSP_OK;
+
+ GST_DEBUG_OBJECT (ext, "generating transports for %d", protocols);
+
+ str = g_string_new ("");
+
+ /*
+ if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) {
+ g_string_append (str, "x-real-rdt/mcast;client_port=%%u1;mode=play,");
+ }
+ if (protocols & GST_RTSP_LOWER_TRANS_UDP) {
+ g_string_append (str, "x-real-rdt/udp;client_port=%%u1;mode=play,");
+ g_string_append (str, "x-pn-tng/udp;client_port=%%u1;mode=play,");
+ }
+ */
+ if (protocols & GST_RTSP_LOWER_TRANS_TCP) {
+ g_string_append (str, "x-real-rdt/tcp;mode=play,");
+ g_string_append (str, "x-pn-tng/tcp;mode=play,");
+ }
+
+ /* if we added something, remove trailing ',' */
+ if (str->len > 0)
+ g_string_truncate (str, str->len - 1);
+
+ *transport = g_string_free (str, FALSE);
+
+ return GST_RTSP_OK;
+}
+
+static GstRTSPResult
+rtsp_ext_real_before_send (GstRTSPExtension * ext, GstRTSPMessage * request)
+{
+ GstRTSPReal *ctx = (GstRTSPReal *) ext;
+
+ switch (request->type_data.request.method) {
+ case GST_RTSP_OPTIONS:
+ {
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_USER_AGENT,
+ //"RealMedia Player (" GST_PACKAGE_NAME ")");
+ "RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_CLIENT_CHALLENGE,
+ "9e26d33f2984236010ef6253fb1887f7");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_COMPANY_ID,
+ "KnKV4M4I/B2FjJ1TToLycw==");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_GUID,
+ "00000000-0000-0000-0000-000000000000");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_REGION_DATA, "0");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_PLAYER_START_TIME,
+ "[28/03/2003:22:50:23 00:00]");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_CLIENT_ID,
+ "Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
+ ctx->isreal = FALSE;
+ break;
+ }
+ case GST_RTSP_DESCRIBE:
+ {
+ if (ctx->isreal) {
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_BANDWIDTH,
+ DEFAULT_BANDWIDTH);
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_GUID,
+ "00000000-0000-0000-0000-000000000000");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_REGION_DATA, "0");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_CLIENT_ID,
+ "Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_MAX_ASM_WIDTH, "1");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_LANGUAGE, "en-US");
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE,
+ "com.real.retain-entity-for-setup");
+ }
+ break;
+ }
+ case GST_RTSP_SETUP:
+ {
+ if (ctx->isreal) {
+ gchar *value =
+ g_strdup_printf ("%s, sd=%s", ctx->challenge2, ctx->checksum);
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_REAL_CHALLENGE2,
+ value);
+ gst_rtsp_message_add_header (request, GST_RTSP_HDR_IF_MATCH, ctx->etag);
+ g_free (value);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return GST_RTSP_OK;
+}
+
+static GstRTSPResult
+rtsp_ext_real_after_send (GstRTSPExtension * ext, GstRTSPMessage * req,
+ GstRTSPMessage * resp)
+{
+ GstRTSPReal *ctx = (GstRTSPReal *) ext;
+
+ switch (req->type_data.request.method) {
+ case GST_RTSP_OPTIONS:
+ {
+ gchar *challenge1 = NULL;
+ gchar *server = NULL;
+
+ gst_rtsp_message_get_header (resp, GST_RTSP_HDR_SERVER, &server, 0);
+
+ gst_rtsp_message_get_header (resp, GST_RTSP_HDR_REAL_CHALLENGE1,
+ &challenge1, 0);
+ if (!challenge1)
+ goto no_challenge1;
+
+ gst_rtsp_ext_real_calc_response_and_checksum (ctx->challenge2,
+ ctx->checksum, challenge1);
+
+ GST_DEBUG_OBJECT (ctx, "Found Real challenge tag");
+ ctx->isreal = TRUE;
+ break;
+ }
+ case GST_RTSP_DESCRIBE:
+ {
+ gchar *etag = NULL;
+ guint len;
+
+ gst_rtsp_message_get_header (resp, GST_RTSP_HDR_ETAG, &etag, 0);
+ if (etag) {
+ len = sizeof (ctx->etag);
+ strncpy (ctx->etag, etag, len);
+ ctx->etag[len - 1] = '\0';
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+no_challenge1:
+ {
+ GST_DEBUG_OBJECT (ctx, "Could not find challenge tag.");
+ ctx->isreal = FALSE;
+ return GST_RTSP_OK;
+ }
+}
+
+#define ENSURE_SIZE(size) \
+G_STMT_START { \
+ while (data_len < size) { \
+ data_len += 1024; \
+ data = g_realloc (data, data_len); \
+ } \
+} G_STMT_END
+
+#define READ_BUFFER_GEN(src, func, name, dest, dest_len) \
+G_STMT_START { \
+ dest = (gchar *)func (src, name); \
+ dest_len = 0; \
+ if (!dest) { \
+ dest = (char *) ""; \
+ } \
+ else if (!strncmp (dest, "buffer;\"", 8)) { \
+ dest += 8; \
+ dest_len = strlen (dest) - 1; \
+ dest[dest_len] = '\0'; \
+ g_base64_decode_inplace (dest, &dest_len); \
+ } \
+} G_STMT_END
+
+#define READ_BUFFER(sdp, name, dest, dest_len) \
+ READ_BUFFER_GEN(sdp, gst_sdp_message_get_attribute_val, name, dest, dest_len)
+#define READ_BUFFER_M(media, name, dest, dest_len) \
+ READ_BUFFER_GEN(media, gst_sdp_media_get_attribute_val, name, dest, dest_len)
+
+#define READ_INT_GEN(src, func, name, dest) \
+G_STMT_START { \
+ const gchar *val = func (src, name); \
+ if (val && !strncmp (val, "integer;", 8)) \
+ dest = atoi (val + 8); \
+ else \
+ dest = 0; \
+} G_STMT_END
+
+#define READ_INT(sdp, name, dest) \
+ READ_INT_GEN(sdp, gst_sdp_message_get_attribute_val, name, dest)
+#define READ_INT_M(media, name, dest) \
+ READ_INT_GEN(media, gst_sdp_media_get_attribute_val, name, dest)
+
+#define READ_STRING(media, name, dest, dest_len) \
+G_STMT_START { \
+ const gchar *val = gst_sdp_media_get_attribute_val (media, name); \
+ if (val && !strncmp (val, "string;\"", 8)) { \
+ dest = (gchar *) val + 8; \
+ dest_len = strlen (dest) - 1; \
+ dest[dest_len] = '\0'; \
+ } else { \
+ dest = (char *) ""; \
+ dest_len = 0; \
+ } \
+} G_STMT_END
+
+#define WRITE_STRING1(datap, str, str_len) \
+G_STMT_START { \
+ *datap = str_len; \
+ memcpy ((datap) + 1, str, str_len); \
+ datap += str_len + 1; \
+} G_STMT_END
+
+#define WRITE_STRING2(datap, str, str_len) \
+G_STMT_START { \
+ GST_WRITE_UINT16_BE (datap, str_len); \
+ memcpy (datap + 2, str, str_len); \
+ datap += str_len + 2; \
+} G_STMT_END
+
+static GstRTSPResult
+rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
+ GstStructure * props)
+{
+ GstRTSPReal *ctx = (GstRTSPReal *) ext;
+ guint size;
+ gint i;
+ gchar *title, *author, *copyright, *comment;
+ gsize title_len, author_len, copyright_len, comment_len;
+ guint8 *data = NULL, *datap;
+ guint data_len = 0, offset;
+ GstBuffer *buf;
+ gchar *opaque_data;
+ gsize opaque_data_len, asm_rule_book_len;
+ GHashTable *vars;
+ GString *rules;
+
+ /* don't bother for non-real formats */
+ READ_INT (sdp, "IsRealDataType", ctx->isreal);
+ if (!ctx->isreal)
+ return TRUE;
+
+ /* Force PAUSE | PLAY */
+ //src->methods |= GST_RTSP_PLAY | GST_RTSP_PAUSE;
+
+ ctx->n_streams = gst_sdp_message_medias_len (sdp);
+
+ ctx->max_bit_rate = 0;
+ ctx->avg_bit_rate = 0;
+ ctx->max_packet_size = 0;
+ ctx->avg_packet_size = 0;
+ ctx->duration = 0;
+
+ for (i = 0; i < ctx->n_streams; i++) {
+ const GstSDPMedia *media;
+ gint intval;
+
+ media = gst_sdp_message_get_media (sdp, i);
+
+ READ_INT_M (media, "MaxBitRate", intval);
+ ctx->max_bit_rate += intval;
+ READ_INT_M (media, "AvgBitRate", intval);
+ ctx->avg_bit_rate += intval;
+ READ_INT_M (media, "MaxPacketSize", intval);
+ ctx->max_packet_size = MAX (ctx->max_packet_size, intval);
+ READ_INT_M (media, "AvgPacketSize", intval);
+ ctx->avg_packet_size = (ctx->avg_packet_size * i + intval) / (i + 1);
+ READ_INT_M (media, "Duration", intval);
+ ctx->duration = MAX (ctx->duration, intval);
+ }
+
+ /* FIXME: use GstByteWriter to write the header */
+ /* PROP */
+ offset = 0;
+ size = 50;
+ ENSURE_SIZE (size);
+ datap = data + offset;
+
+ memcpy (datap + 0, "PROP", 4);
+ GST_WRITE_UINT32_BE (datap + 4, size);
+ GST_WRITE_UINT16_BE (datap + 8, 0);
+ GST_WRITE_UINT32_BE (datap + 10, ctx->max_bit_rate);
+ GST_WRITE_UINT32_BE (datap + 14, ctx->avg_bit_rate);
+ GST_WRITE_UINT32_BE (datap + 18, ctx->max_packet_size);
+ GST_WRITE_UINT32_BE (datap + 22, ctx->avg_packet_size);
+ GST_WRITE_UINT32_BE (datap + 26, 0);
+ GST_WRITE_UINT32_BE (datap + 30, ctx->duration);
+ GST_WRITE_UINT32_BE (datap + 34, 0);
+ GST_WRITE_UINT32_BE (datap + 38, 0);
+ GST_WRITE_UINT32_BE (datap + 42, 0);
+ GST_WRITE_UINT16_BE (datap + 46, ctx->n_streams);
+ GST_WRITE_UINT16_BE (datap + 48, 0);
+ offset += size;
+
+ /* CONT */
+ READ_BUFFER (sdp, "Title", title, title_len);
+ READ_BUFFER (sdp, "Author", author, author_len);
+ READ_BUFFER (sdp, "Comment", comment, comment_len);
+ READ_BUFFER (sdp, "Copyright", copyright, copyright_len);
+
+ size = 18 + title_len + author_len + comment_len + copyright_len;
+ ENSURE_SIZE (offset + size);
+ datap = data + offset;
+
+ memcpy (datap, "CONT", 4);
+ GST_WRITE_UINT32_BE (datap + 4, size);
+ GST_WRITE_UINT16_BE (datap + 8, 0); /* Version */
+ datap += 10;
+ WRITE_STRING2 (datap, title, title_len);
+ WRITE_STRING2 (datap, author, author_len);
+ WRITE_STRING2 (datap, copyright, copyright_len);
+ WRITE_STRING2 (datap, comment, comment_len);
+ offset += size;
+
+ /* fix the hashtale for the rule parser */
+ rules = g_string_new ("");
+ vars = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (vars, (gchar *) "Bandwidth",
+ (gchar *) DEFAULT_BANDWIDTH);
+
+ /* MDPR */
+ for (i = 0; i < ctx->n_streams; i++) {
+ const GstSDPMedia *media;
+ guint32 len;
+ GstRTSPRealStream *stream;
+ gchar *str;
+ gint rulematches[MAX_RULEMATCHES];
+ gint sel, j, n;
+
+ media = gst_sdp_message_get_media (sdp, i);
+
+ if (media->media && !strcmp (media->media, "data"))
+ continue;
+
+ stream = g_new0 (GstRTSPRealStream, 1);
+ ctx->streams = g_list_append (ctx->streams, stream);
+
+ READ_INT_M (media, "MaxBitRate", stream->max_bit_rate);
+ READ_INT_M (media, "AvgBitRate", stream->avg_bit_rate);
+ READ_INT_M (media, "MaxPacketSize", stream->max_packet_size);
+ READ_INT_M (media, "AvgPacketSize", stream->avg_packet_size);
+ READ_INT_M (media, "StartTime", stream->start_time);
+ READ_INT_M (media, "Preroll", stream->preroll);
+ READ_INT_M (media, "Duration", stream->duration);
+ READ_STRING (media, "StreamName", str, stream->stream_name_len);
+ stream->stream_name = g_strndup (str, stream->stream_name_len);
+ READ_STRING (media, "mimetype", str, stream->mime_type_len);
+ stream->mime_type = g_strndup (str, stream->mime_type_len);
+
+ /* FIXME: Depending on the current bandwidth, we need to select one
+ * bandwith out of a list offered by the server. Someone needs to write
+ * a parser for strings like
+ *
+ * #($Bandwidth < 67959),TimestampDelivery=T,DropByN=T,priority=9;
+ * #($Bandwidth >= 67959) && ($Bandwidth < 167959),AverageBandwidth=67959,
+ * Priority=9;#($Bandwidth >= 67959) && ($Bandwidth < 167959),
+ * AverageBandwidth=0,Priority=5,OnDepend=\"1\";
+ * #($Bandwidth >= 167959) && ($Bandwidth < 267959),
+ * AverageBandwidth=167959,Priority=9;
+ * #($Bandwidth >= 167959) && ($Bandwidth < 267959),AverageBandwidth=0,
+ * Priority=5,OnDepend=\"3\";#($Bandwidth >= 267959),
+ * AverageBandwidth=267959,Priority=9;#($Bandwidth >= 267959),
+ * AverageBandwidth=0,Priority=5,OnDepend=\"5\";
+ *
+ * As I don't know how to do that, I just use the first entry (sel = 0).
+ * But to give you a starting point, I offer you above string
+ * in the variable 'asm_rule_book'.
+ */
+ READ_STRING (media, "ASMRuleBook", str, asm_rule_book_len);
+ stream->rulebook = gst_asm_rule_book_new (str);
+
+ n = gst_asm_rule_book_match (stream->rulebook, vars, rulematches);
+ for (j = 0; j < n; j++) {
+ g_string_append_printf (rules, "stream=%u;rule=%u,", i, rulematches[j]);
+ }
+
+ /* get the MLTI for the first matched rules */
+ sel = rulematches[0];
+
+ READ_BUFFER_M (media, "OpaqueData", opaque_data, opaque_data_len);
+
+ if (opaque_data_len < 4) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 4",
+ opaque_data_len);
+ goto strange_opaque_data;
+ }
+ if (strncmp (opaque_data, "MLTI", 4)) {
+ GST_DEBUG_OBJECT (ctx, "no MLTI found, appending all");
+ stream->type_specific_data_len = opaque_data_len;
+ stream->type_specific_data = g_memdup (opaque_data, opaque_data_len);
+ goto no_type_specific;
+ }
+ opaque_data += 4;
+ opaque_data_len -= 4;
+
+ if (opaque_data_len < 2) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 2",
+ opaque_data_len);
+ goto strange_opaque_data;
+ }
+ stream->num_rules = GST_READ_UINT16_BE (opaque_data);
+ opaque_data += 2;
+ opaque_data_len -= 2;
+
+ if (sel >= stream->num_rules) {
+ GST_DEBUG_OBJECT (ctx, "sel %d >= num_rules %d", sel, stream->num_rules);
+ goto strange_opaque_data;
+ }
+
+ if (opaque_data_len < 2 * sel) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT
+ " < 2 * sel (%d)", opaque_data_len, 2 * sel);
+ goto strange_opaque_data;
+ }
+ opaque_data += 2 * sel;
+ opaque_data_len -= 2 * sel;
+
+ if (opaque_data_len < 2) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 2",
+ opaque_data_len);
+ goto strange_opaque_data;
+ }
+ stream->codec = GST_READ_UINT16_BE (opaque_data);
+ opaque_data += 2;
+ opaque_data_len -= 2;
+
+ if (opaque_data_len < 2 * (stream->num_rules - sel - 1)) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT
+ " < %d", opaque_data_len, 2 * (stream->num_rules - sel - 1));
+ goto strange_opaque_data;
+ }
+ opaque_data += 2 * (stream->num_rules - sel - 1);
+ opaque_data_len -= 2 * (stream->num_rules - sel - 1);
+
+ if (opaque_data_len < 2) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 2",
+ opaque_data_len);
+ goto strange_opaque_data;
+ }
+ stream->num_rules = GST_READ_UINT16_BE (opaque_data);
+ opaque_data += 2;
+ opaque_data_len -= 2;
+
+ if (stream->codec > stream->num_rules) {
+ GST_DEBUG_OBJECT (ctx, "codec %d > num_rules %d", stream->codec,
+ stream->num_rules);
+ goto strange_opaque_data;
+ }
+
+ for (j = 0; j < stream->codec; j++) {
+ if (opaque_data_len < 4) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 4",
+ opaque_data_len);
+ goto strange_opaque_data;
+ }
+ len = GST_READ_UINT32_BE (opaque_data);
+ opaque_data += 4;
+ opaque_data_len -= 4;
+
+ if (opaque_data_len < len) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < len %d",
+ opaque_data_len, len);
+ goto strange_opaque_data;
+ }
+ opaque_data += len;
+ opaque_data_len -= len;
+ }
+
+ if (opaque_data_len < 4) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 4",
+ opaque_data_len);
+ goto strange_opaque_data;
+ }
+ stream->type_specific_data_len = GST_READ_UINT32_BE (opaque_data);
+ opaque_data += 4;
+ opaque_data_len -= 4;
+
+ if (opaque_data_len < stream->type_specific_data_len) {
+ GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < %d",
+ opaque_data_len, stream->type_specific_data_len);
+ goto strange_opaque_data;
+ }
+ stream->type_specific_data =
+ g_memdup (opaque_data, stream->type_specific_data_len);
+
+ no_type_specific:
+ size =
+ 46 + stream->stream_name_len + stream->mime_type_len +
+ stream->type_specific_data_len;
+ ENSURE_SIZE (offset + size);
+ datap = data + offset;
+
+ memcpy (datap, "MDPR", 4);
+ GST_WRITE_UINT32_BE (datap + 4, size);
+ GST_WRITE_UINT16_BE (datap + 8, 0);
+ GST_WRITE_UINT16_BE (datap + 10, i);
+ GST_WRITE_UINT32_BE (datap + 12, stream->max_bit_rate);
+ GST_WRITE_UINT32_BE (datap + 16, stream->avg_bit_rate);
+ GST_WRITE_UINT32_BE (datap + 20, stream->max_packet_size);
+ GST_WRITE_UINT32_BE (datap + 24, stream->avg_packet_size);
+ GST_WRITE_UINT32_BE (datap + 28, stream->start_time);
+ GST_WRITE_UINT32_BE (datap + 32, stream->preroll);
+ GST_WRITE_UINT32_BE (datap + 36, stream->duration);
+ datap += 40;
+ WRITE_STRING1 (datap, stream->stream_name, stream->stream_name_len);
+ WRITE_STRING1 (datap, stream->mime_type, stream->mime_type_len);
+ GST_WRITE_UINT32_BE (datap, stream->type_specific_data_len);
+ if (stream->type_specific_data_len)
+ memcpy (datap + 4, stream->type_specific_data,
+ stream->type_specific_data_len);
+ offset += size;
+ }
+
+ /* destroy the rulebook hashtable now */
+ g_hash_table_destroy (vars);
+
+ /* strip final , if we added some stream rules */
+ if (rules->len > 0) {
+ rules = g_string_truncate (rules, rules->len - 1);
+ }
+
+ /* and store rules in the context */
+ ctx->rules = g_string_free (rules, FALSE);
+
+ /* DATA */
+ size = 18;
+ ENSURE_SIZE (offset + size);
+ datap = data + offset;
+
+ memcpy (datap, "DATA", 4);
+ GST_WRITE_UINT32_BE (datap + 4, size);
+ GST_WRITE_UINT16_BE (datap + 8, 0);
+ GST_WRITE_UINT32_BE (datap + 10, 0); /* number of packets */
+ GST_WRITE_UINT32_BE (datap + 14, 0); /* next data header */
+ offset += size;
+
+ buf = gst_buffer_new_wrapped (data, offset);
+
+ /* Set on caps */
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+ gst_structure_set (props, "config", GST_TYPE_BUFFER, buf, NULL);
+ gst_buffer_unref (buf);
+
+ /* Overwrite encoding and media fields */
+ gst_structure_set (props, "encoding-name", G_TYPE_STRING, "X-REAL-RDT", NULL);
+ gst_structure_set (props, "media", G_TYPE_STRING, "application", NULL);
+
+ return TRUE;
+
+ /* ERRORS */
+strange_opaque_data:
+ {
+ g_string_free (rules, TRUE);
+ g_hash_table_destroy (vars);
+ g_free (data);
+
+ GST_ELEMENT_ERROR (ctx, RESOURCE, WRITE, ("Strange opaque data."), (NULL));
+ return FALSE;
+ }
+}
+
+static GstRTSPResult
+rtsp_ext_real_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url)
+{
+ GstRTSPReal *ctx = (GstRTSPReal *) ext;
+ GstRTSPResult res;
+ GstRTSPMessage request = { 0 };
+ GstRTSPMessage response = { 0 };
+ gchar *req_url;
+
+ if (!ctx->isreal)
+ return GST_RTSP_OK;
+
+ if (!ctx->rules)
+ return GST_RTSP_OK;
+
+ req_url = gst_rtsp_url_get_request_uri (url);
+
+ /* create SET_PARAMETER */
+ if ((res = gst_rtsp_message_init_request (&request, GST_RTSP_SET_PARAMETER,
+ req_url)) < 0)
+ goto create_request_failed;
+
+ g_free (req_url);
+
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SUBSCRIBE, ctx->rules);
+
+ /* send SET_PARAMETER */
+ if ((res = gst_rtsp_extension_send (ext, &request, &response)) < 0)
+ goto send_error;
+
+ gst_rtsp_message_unset (&request);
+ gst_rtsp_message_unset (&response);
+
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+create_request_failed:
+ {
+ GST_ELEMENT_ERROR (ctx, LIBRARY, INIT,
+ ("Could not create request."), (NULL));
+ goto reset;
+ }
+send_error:
+ {
+ GST_ELEMENT_ERROR (ctx, RESOURCE, WRITE,
+ ("Could not send message."), (NULL));
+ goto reset;
+ }
+reset:
+ {
+ gst_rtsp_message_unset (&request);
+ gst_rtsp_message_unset (&response);
+ return res;
+ }
+}
+
+static void gst_rtsp_real_extension_init (gpointer g_iface,
+ gpointer iface_data);
+static void gst_rtsp_real_finalize (GObject * obj);
+
+#define gst_rtsp_real_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstRTSPReal, gst_rtsp_real, GST_TYPE_ELEMENT,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_RTSP_EXTENSION,
+ gst_rtsp_real_extension_init));
+
+static void
+gst_rtsp_real_class_init (GstRTSPRealClass * g_class)
+{
+ GObjectClass *gobject_class = (GObjectClass *) g_class;
+ GstElementClass *gstelement_class = (GstElementClass *) g_class;
+
+ gobject_class->finalize = gst_rtsp_real_finalize;
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RealMedia RTSP Extension", "Network/Extension/Protocol",
+ "Extends RTSP so that it can handle RealMedia setup",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtspreal_debug, "rtspreal", 0,
+ "RealMedia RTSP extension");
+}
+
+static void
+gst_rtsp_real_init (GstRTSPReal * rtspreal)
+{
+ rtspreal->isreal = FALSE;
+}
+
+static void
+gst_rtsp_stream_free (GstRTSPRealStream * stream)
+{
+ g_free (stream->stream_name);
+ g_free (stream->mime_type);
+ gst_asm_rule_book_free (stream->rulebook);
+ g_free (stream->type_specific_data);
+
+ g_free (stream);
+}
+
+static void
+gst_rtsp_real_finalize (GObject * obj)
+{
+ GstRTSPReal *r = (GstRTSPReal *) obj;
+
+ g_list_foreach (r->streams, (GFunc) gst_rtsp_stream_free, NULL);
+ g_list_free (r->streams);
+ g_free (r->rules);
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_rtsp_real_extension_init (gpointer g_iface, gpointer iface_data)
+{
+ GstRTSPExtensionInterface *iface = (GstRTSPExtensionInterface *) g_iface;
+
+ iface->before_send = rtsp_ext_real_before_send;
+ iface->after_send = rtsp_ext_real_after_send;
+ iface->parse_sdp = rtsp_ext_real_parse_sdp;
+ iface->stream_select = rtsp_ext_real_stream_select;
+ iface->get_transports = rtsp_ext_real_get_transports;
+}
+
+gboolean
+gst_rtsp_real_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtspreal",
+ GST_RANK_MARGINAL, GST_TYPE_RTSP_REAL);
+}
diff --git a/gst/realmedia/rtspreal.h b/gst/realmedia/rtspreal.h
new file mode 100644
index 0000000..fad1427
--- /dev/null
+++ b/gst/realmedia/rtspreal.h
@@ -0,0 +1,92 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_REAL_H__
+#define __GST_RTSP_REAL_H__
+
+#include <gst/gst.h>
+
+#include "asmrules.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTSP_REAL (gst_rtsp_real_get_type())
+#define GST_IS_RTSP_REAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSP_REAL))
+#define GST_IS_RTSP_REAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSP_REAL))
+#define GST_RTSP_REAL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSP_REAL, GstRTSPReal))
+#define GST_RTSP_REAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTSP_REAL, GstRTSPRealClass))
+
+typedef struct _GstRTSPReal GstRTSPReal;
+typedef struct _GstRTSPRealClass GstRTSPRealClass;
+
+typedef struct _GstRTSPRealStream GstRTSPRealStream;
+
+struct _GstRTSPRealStream {
+ guint id;
+ guint max_bit_rate;
+ guint avg_bit_rate;
+ guint max_packet_size;
+ guint avg_packet_size;
+ guint start_time;
+ guint preroll;
+ guint duration;
+ gchar *stream_name;
+ guint stream_name_len;
+ gchar *mime_type;
+ guint mime_type_len;
+
+ GstASMRuleBook *rulebook;
+
+ gchar *type_specific_data;
+ guint type_specific_data_len;
+
+ guint16 num_rules, j, sel, codec;
+};
+
+struct _GstRTSPReal {
+ GstElement element;
+
+ gchar checksum[34];
+ gchar challenge2[64];
+ gchar etag[64];
+ gboolean isreal;
+
+ guint n_streams;
+ GList *streams;
+
+ guint max_bit_rate;
+ guint avg_bit_rate;
+ guint max_packet_size;
+ guint avg_packet_size;
+ guint duration;
+
+ gchar *rules;
+};
+
+struct _GstRTSPRealClass {
+ GstElementClass parent_class;
+};
+
+GType gst_rtsp_real_get_type(void);
+
+gboolean gst_rtsp_real_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_REAL_H__ */
diff --git a/gst/xingmux/Makefile.am b/gst/xingmux/Makefile.am
new file mode 100644
index 0000000..c5d7692
--- /dev/null
+++ b/gst/xingmux/Makefile.am
@@ -0,0 +1,25 @@
+# FIXME 0.11: element should move somewhere else really, such as
+# gst-plugins-good/gst/tags/ or so
+plugin_LTLIBRARIES = libgstxingmux.la
+
+libgstxingmux_la_SOURCES = plugin.c gstxingmux.c
+libgstxingmux_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstxingmux_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
+libgstxingmux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstxingmux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = gstxingmux.h
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstxingmux -:SHARED libgstxingmux \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstxingmux_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstxingmux_la_CFLAGS) \
+ -:LDFLAGS $(libgstxingmux_la_LDFLAGS) \
+ $(libgstxingmux_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
diff --git a/gst/xingmux/Makefile.in b/gst/xingmux/Makefile.in
new file mode 100644
index 0000000..52d03f6
--- /dev/null
+++ b/gst/xingmux/Makefile.in
@@ -0,0 +1,851 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = gst/xingmux
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-function.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/a52.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-sid.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstxingmux_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstxingmux_la_OBJECTS = libgstxingmux_la-plugin.lo \
+ libgstxingmux_la-gstxingmux.lo
+libgstxingmux_la_OBJECTS = $(am_libgstxingmux_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgstxingmux_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstxingmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstxingmux_la_CFLAGS) $(CFLAGS) \
+ $(libgstxingmux_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgstxingmux_la_SOURCES)
+DIST_SOURCES = $(libgstxingmux_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A52DEC_CFLAGS = @A52DEC_CFLAGS@
+A52DEC_LIBS = @A52DEC_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMRNB_CFLAGS = @AMRNB_CFLAGS@
+AMRNB_LIBS = @AMRNB_LIBS@
+AMRWB_CFLAGS = @AMRWB_CFLAGS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDIO_CFLAGS = @CDIO_CFLAGS@
+CDIO_LIBS = @CDIO_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVDREAD_LIBS = @DVDREAD_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DVDREAD = @HAVE_DVDREAD@
+HAVE_LAME = @HAVE_LAME@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LAME_CFLAGS = @LAME_CFLAGS@
+LAME_LIBS = @LAME_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAD_CFLAGS = @MAD_CFLAGS@
+MAD_LIBS = @MAD_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPEG2DEC_CFLAGS = @MPEG2DEC_CFLAGS@
+MPEG2DEC_LIBS = @MPEG2DEC_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIDPLAY_CFLAGS = @SIDPLAY_CFLAGS@
+SIDPLAY_LIBS = @SIDPLAY_LIBS@
+STRIP = @STRIP@
+TWOLAME_CFLAGS = @TWOLAME_CFLAGS@
+TWOLAME_LIBS = @TWOLAME_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WIN32_LIBS = @WIN32_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# FIXME 0.11: element should move somewhere else really, such as
+# gst-plugins-good/gst/tags/ or so
+plugin_LTLIBRARIES = libgstxingmux.la
+libgstxingmux_la_SOURCES = plugin.c gstxingmux.c
+libgstxingmux_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstxingmux_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
+libgstxingmux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstxingmux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+noinst_HEADERS = gstxingmux.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/xingmux/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/xingmux/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgstxingmux.la: $(libgstxingmux_la_OBJECTS) $(libgstxingmux_la_DEPENDENCIES) $(EXTRA_libgstxingmux_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstxingmux_la_LINK) -rpath $(plugindir) $(libgstxingmux_la_OBJECTS) $(libgstxingmux_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstxingmux_la-gstxingmux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstxingmux_la-plugin.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstxingmux_la-plugin.lo: plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstxingmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstxingmux_la_CFLAGS) $(CFLAGS) -MT libgstxingmux_la-plugin.lo -MD -MP -MF $(DEPDIR)/libgstxingmux_la-plugin.Tpo -c -o libgstxingmux_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstxingmux_la-plugin.Tpo $(DEPDIR)/libgstxingmux_la-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugin.c' object='libgstxingmux_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstxingmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstxingmux_la_CFLAGS) $(CFLAGS) -c -o libgstxingmux_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+
+libgstxingmux_la-gstxingmux.lo: gstxingmux.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstxingmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstxingmux_la_CFLAGS) $(CFLAGS) -MT libgstxingmux_la-gstxingmux.lo -MD -MP -MF $(DEPDIR)/libgstxingmux_la-gstxingmux.Tpo -c -o libgstxingmux_la-gstxingmux.lo `test -f 'gstxingmux.c' || echo '$(srcdir)/'`gstxingmux.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstxingmux_la-gstxingmux.Tpo $(DEPDIR)/libgstxingmux_la-gstxingmux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstxingmux.c' object='libgstxingmux_la-gstxingmux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstxingmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstxingmux_la_CFLAGS) $(CFLAGS) -c -o libgstxingmux_la-gstxingmux.lo `test -f 'gstxingmux.c' || echo '$(srcdir)/'`gstxingmux.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+Android.mk: Makefile.am $(BUILT_SOURCES)
+ androgenizer \
+ -:PROJECT libgstxingmux -:SHARED libgstxingmux \
+ -:TAGS eng debug \
+ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+ -:SOURCES $(libgstxingmux_la_SOURCES) \
+ -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstxingmux_la_CFLAGS) \
+ -:LDFLAGS $(libgstxingmux_la_LDFLAGS) \
+ $(libgstxingmux_la_LIBADD) \
+ -ldl \
+ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+ LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
+ > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/xingmux/gstxingmux.c b/gst/xingmux/gstxingmux.c
new file mode 100644
index 0000000..fd09ac0
--- /dev/null
+++ b/gst/xingmux/gstxingmux.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (c) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* Xing SDK: http://www.mp3-tech.org/programmer/sources/vbrheadersdk.zip */
+
+
+/**
+ * SECTION:element-xingmux
+ *
+ * xingmux adds a Xing header to MP3 files. This contains information about the duration and size
+ * of the file and a seek table and is very useful for getting an almost correct duration and better
+ * seeking on VBR MP3 files.
+ *
+ * This element will remove any existing Xing, LAME or VBRI headers from the beginning of the file.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch audiotestsrc num-buffers=1000 ! audioconvert ! lamemp3enc ! xingmux ! filesink location=test.mp3
+ * gst-launch filesrc location=test.mp3 ! xingmux ! filesink location=test2.mp3
+ * gst-launch filesrc location=test.mp3 ! mp3parse ! xingmux ! filesink location=test2.mp3
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include "gstxingmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (xing_mux_debug);
+#define GST_CAT_DEFAULT xing_mux_debug
+
+#define gst_xing_mux_parent_class parent_class
+G_DEFINE_TYPE (GstXingMux, gst_xing_mux, GST_TYPE_ELEMENT);
+
+/* Xing Header stuff */
+#define GST_XING_FRAME_FIELD (1 << 0)
+#define GST_XING_BYTES_FIELD (1 << 1)
+#define GST_XING_TOC_FIELD (1 << 2)
+#define GST_XING_QUALITY_FIELD (1 << 3)
+
+typedef struct _GstXingSeekEntry
+{
+ gint64 timestamp;
+ gint byte;
+} GstXingSeekEntry;
+
+static inline GstXingSeekEntry *
+gst_xing_seek_entry_new (void)
+{
+ return g_slice_new (GstXingSeekEntry);
+}
+
+static inline void
+gst_xing_seek_entry_free (GstXingSeekEntry * entry)
+{
+ g_slice_free (GstXingSeekEntry, entry);
+}
+
+static void gst_xing_mux_finalize (GObject * obj);
+static GstStateChangeReturn
+gst_xing_mux_change_state (GstElement * element, GstStateChange transition);
+static GstFlowReturn gst_xing_mux_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+static gboolean gst_xing_mux_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+
+static GstStaticPadTemplate gst_xing_mux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg, "
+ "mpegversion = (int) 1, " "layer = (int) [ 1, 3 ]"));
+
+
+static GstStaticPadTemplate gst_xing_mux_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg, "
+ "mpegversion = (int) 1, " "layer = (int) [ 1, 3 ]"));
+static const guint mp3types_bitrates[2][3][16] = {
+ {
+ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
+ },
+ {
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
+ },
+};
+
+static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
+{22050, 24000, 16000},
+{11025, 12000, 8000}
+};
+
+static gboolean
+parse_header (guint32 header, guint * ret_size, guint * ret_spf,
+ gulong * ret_rate)
+{
+ guint length, spf;
+ gulong samplerate, bitrate, layer, padding;
+ gint lsf, mpg25;
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ g_warning ("invalid sync");
+ return FALSE;
+ }
+
+ if (((header >> 19) & 3) == 0x01) {
+ g_warning ("invalid MPEG version");
+ return FALSE;
+ }
+
+ if (((header >> 17) & 3) == 0x00) {
+ g_warning ("invalid MPEG layer");
+ return FALSE;
+ }
+
+ if (((header >> 12) & 0xf) == 0xf || ((header >> 12) & 0xf) == 0x0) {
+ g_warning ("invalid bitrate");
+ return FALSE;
+ }
+
+ if (((header >> 10) & 0x3) == 0x3) {
+ g_warning ("invalid sampling rate");
+ return FALSE;
+ }
+
+ if (header & 0x00000002) {
+ g_warning ("invalid emphasis");
+ return FALSE;
+ }
+
+ if (header & (1 << 20)) {
+ lsf = (header & (1 << 19)) ? 0 : 1;
+ mpg25 = 0;
+ } else {
+ lsf = 1;
+ mpg25 = 1;
+ }
+
+ layer = 4 - ((header >> 17) & 0x3);
+
+ bitrate = (header >> 12) & 0xF;
+ bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
+ if (bitrate == 0)
+ return FALSE;
+
+ samplerate = (header >> 10) & 0x3;
+ samplerate = mp3types_freqs[lsf + mpg25][samplerate];
+
+ padding = (header >> 9) & 0x1;
+
+ switch (layer) {
+ case 1:
+ length = 4 * ((bitrate * 12) / samplerate + padding);
+ break;
+ case 2:
+ length = (bitrate * 144) / samplerate + padding;
+ break;
+ default:
+ case 3:
+ length = (bitrate * 144) / (samplerate << lsf) + padding;
+ break;
+ }
+
+ if (layer == 1)
+ spf = 384;
+ else if (layer == 2 || lsf == 0)
+ spf = 1152;
+ else
+ spf = 576;
+
+ if (ret_size)
+ *ret_size = length;
+ if (ret_spf)
+ *ret_spf = spf;
+ if (ret_rate)
+ *ret_rate = samplerate;
+
+ return TRUE;
+}
+
+static guint
+get_xing_offset (guint32 header)
+{
+ guint mpeg_version = (header >> 19) & 0x3;
+ guint channel_mode = (header >> 6) & 0x3;
+
+ if (mpeg_version == 0x3) {
+ if (channel_mode == 0x3) {
+ return 0x11;
+ } else {
+ return 0x20;
+ }
+ } else {
+ if (channel_mode == 0x3) {
+ return 0x09;
+ } else {
+ return 0x11;
+ }
+ }
+}
+
+static gboolean
+has_xing_header (guint32 header, GstBuffer * buffer, gsize size)
+{
+ gboolean ret;
+ GstMapInfo map;
+ guint8 *data;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ data += 4;
+ data += get_xing_offset (header);
+
+ if (memcmp (data, "Xing", 4) == 0 ||
+ memcmp (data, "Info", 4) == 0 || memcmp (data, "VBRI", 4) == 0)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ gst_buffer_unmap (buffer, &map);
+ return ret;
+}
+
+static GstBuffer *
+generate_xing_header (GstXingMux * xing)
+{
+ guint8 *xing_flags;
+ guint32 xing_flags_tmp = 0;
+ GstBuffer *xing_header;
+ GstMapInfo map;
+ guchar *data;
+
+ guint32 header;
+ guint32 header_be;
+ guint size, spf, xing_offset;
+ gulong rate;
+ guint bitrate = 0x00;
+
+ gint64 duration;
+ gint64 byte_count;
+
+ header = xing->first_header;
+
+ /* Set bitrate and choose lowest possible size */
+ do {
+ bitrate++;
+
+ header &= 0xffff0fff;
+ header |= bitrate << 12;
+
+ parse_header (header, &size, &spf, &rate);
+ xing_offset = get_xing_offset (header);
+ } while (size < (4 + xing_offset + 4 + 4 + 4 + 4 + 100) && bitrate < 0xe);
+
+ if (bitrate == 0xe) {
+ GST_ERROR ("No usable bitrate found!");
+ return NULL;
+ }
+
+ xing_header = gst_buffer_new_and_alloc (size);
+
+ gst_buffer_map (xing_header, &map, GST_MAP_WRITE);
+ data = map.data;
+ memset (data, 0, size);
+ header_be = GUINT32_TO_BE (header);
+ memcpy (data, &header_be, 4);
+
+ data += 4;
+ data += xing_offset;
+
+ memcpy (data, "Xing", 4);
+ data += 4;
+
+ xing_flags = data;
+ data += 4;
+
+ if (xing->duration != GST_CLOCK_TIME_NONE) {
+ duration = xing->duration;
+ } else {
+ GstFormat fmt = GST_FORMAT_TIME;
+
+ if (!gst_pad_peer_query_duration (xing->sinkpad, fmt, &duration))
+ duration = GST_CLOCK_TIME_NONE;
+ }
+
+ if (duration != GST_CLOCK_TIME_NONE) {
+ guint32 number_of_frames;
+
+ /* The Xing Header contains a NumberOfFrames field, which verifies to:
+ * Duration = NumberOfFrames *SamplesPerFrame/SamplingRate
+ * SamplesPerFrame and SamplingRate are values for the current frame.
+ */
+ number_of_frames = gst_util_uint64_scale (duration, rate, GST_SECOND) / spf;
+ number_of_frames += 1; /* Xing Header Frame */
+ GST_DEBUG ("Setting number of frames to %u", number_of_frames);
+ number_of_frames = GUINT32_TO_BE (number_of_frames);
+ memcpy (data, &number_of_frames, 4);
+ xing_flags_tmp |= GST_XING_FRAME_FIELD;
+ data += 4;
+ }
+
+ if (xing->byte_count != 0) {
+ byte_count = xing->byte_count;
+ } else {
+ GstFormat fmt = GST_FORMAT_BYTES;
+
+ if (!gst_pad_peer_query_duration (xing->sinkpad, fmt, &byte_count))
+ byte_count = 0;
+ if (byte_count == -1)
+ byte_count = 0;
+ }
+
+ if (byte_count != 0) {
+ guint32 nbytes;
+
+ if (byte_count > G_MAXUINT32) {
+ GST_DEBUG ("Too large stream: %" G_GINT64_FORMAT " > %u bytes",
+ byte_count, G_MAXUINT32);
+ } else {
+ nbytes = byte_count;
+ GST_DEBUG ("Setting number of bytes to %u", nbytes);
+ nbytes = GUINT32_TO_BE (nbytes);
+ memcpy (data, &nbytes, 4);
+ xing_flags_tmp |= GST_XING_BYTES_FIELD;
+ data += 4;
+ }
+ }
+
+ if (xing->seek_table != NULL && byte_count != 0
+ && duration != GST_CLOCK_TIME_NONE) {
+ GList *it;
+ gint percent = 0;
+
+ xing_flags_tmp |= GST_XING_TOC_FIELD;
+
+ GST_DEBUG ("Writing seek table");
+ for (it = xing->seek_table; it != NULL && percent < 100; it = it->next) {
+ GstXingSeekEntry *entry = (GstXingSeekEntry *) it->data;
+ gint64 pos;
+ guchar byte;
+
+ while ((entry->timestamp * 100) / duration >= percent) {
+ pos = (entry->byte * 256) / byte_count;
+ GST_DEBUG (" %d %% -- %" G_GINT64_FORMAT " 1/256", percent, pos);
+ byte = (guchar) pos;
+ memcpy (data, &byte, 1);
+ data++;
+ percent++;
+ }
+ }
+
+ if (percent < 100) {
+ guchar b;
+ gint i;
+
+ memcpy (&b, data - 1, 1);
+
+ for (i = percent; i < 100; i++) {
+ GST_DEBUG (" %d %% -- %d 1/256", i, b);
+ memcpy (data, &b, 1);
+ data++;
+ }
+ }
+ }
+
+ GST_DEBUG ("Setting Xing flags to 0x%x\n", xing_flags_tmp);
+ xing_flags_tmp = GUINT32_TO_BE (xing_flags_tmp);
+ memcpy (xing_flags, &xing_flags_tmp, 4);
+ gst_buffer_unmap (xing_header, &map);
+ return xing_header;
+}
+
+static void
+gst_xing_mux_class_init (GstXingMuxClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_xing_mux_finalize);
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_xing_mux_change_state);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_xing_mux_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_xing_mux_sink_template));
+
+ GST_DEBUG_CATEGORY_INIT (xing_mux_debug, "xingmux", 0, "Xing Header Muxer");
+
+ gst_element_class_set_static_metadata (gstelement_class, "MP3 Xing muxer",
+ "Formatter/Muxer/Metadata",
+ "Adds a Xing header to the beginning of a VBR MP3 file",
+ "Christophe Fergeau <teuf@gnome.org>");
+}
+
+static void
+gst_xing_mux_finalize (GObject * obj)
+{
+ GstXingMux *xing = GST_XING_MUX (obj);
+
+ if (xing->adapter) {
+ g_object_unref (xing->adapter);
+ xing->adapter = NULL;
+ }
+
+ if (xing->seek_table) {
+ g_list_foreach (xing->seek_table, (GFunc) gst_xing_seek_entry_free, NULL);
+ g_list_free (xing->seek_table);
+ xing->seek_table = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+xing_reset (GstXingMux * xing)
+{
+ xing->duration = GST_CLOCK_TIME_NONE;
+ xing->byte_count = 0;
+
+ gst_adapter_clear (xing->adapter);
+
+ if (xing->seek_table) {
+ g_list_foreach (xing->seek_table, (GFunc) gst_xing_seek_entry_free, NULL);
+ g_list_free (xing->seek_table);
+ xing->seek_table = NULL;
+ }
+
+ xing->sent_xing = FALSE;
+}
+
+
+static void
+gst_xing_mux_init (GstXingMux * xing)
+{
+ /* pad through which data comes in to the element */
+ xing->sinkpad =
+ gst_pad_new_from_static_template (&gst_xing_mux_sink_template, "sink");
+ gst_pad_set_chain_function (xing->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_xing_mux_chain));
+ gst_pad_set_event_function (xing->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_xing_mux_sink_event));
+ GST_PAD_SET_PROXY_CAPS (xing->sinkpad);
+ gst_element_add_pad (GST_ELEMENT (xing), xing->sinkpad);
+
+ /* pad through which data goes out of the element */
+ xing->srcpad =
+ gst_pad_new_from_static_template (&gst_xing_mux_src_template, "src");
+ gst_element_add_pad (GST_ELEMENT (xing), xing->srcpad);
+
+ xing->adapter = gst_adapter_new ();
+
+ xing_reset (xing);
+}
+
+static GstFlowReturn
+gst_xing_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+ GstXingMux *xing = GST_XING_MUX (parent);
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ gst_adapter_push (xing->adapter, buffer);
+
+ while (gst_adapter_available (xing->adapter) >= 4) {
+ const guchar *data;
+ guint32 header;
+ GstBuffer *outbuf;
+ GstClockTime duration;
+ guint size, spf;
+ gulong rate;
+ GstXingSeekEntry *seek_entry;
+
+ data = gst_adapter_map (xing->adapter, 4);
+ header = GST_READ_UINT32_BE (data);
+ gst_adapter_unmap (xing->adapter);
+
+ if (!parse_header (header, &size, &spf, &rate)) {
+ GST_DEBUG ("Lost sync, resyncing");
+ gst_adapter_flush (xing->adapter, 1);
+ continue;
+ }
+
+ if (gst_adapter_available (xing->adapter) < size)
+ break;
+
+ outbuf = gst_adapter_take_buffer (xing->adapter, size);
+
+ if (!xing->sent_xing) {
+ if (has_xing_header (header, outbuf, size)) {
+ GST_LOG_OBJECT (xing, "Dropping old Xing header");
+ gst_buffer_unref (outbuf);
+ continue;
+ } else {
+ GstBuffer *xing_header;
+ guint64 xing_header_size;
+
+ xing->first_header = header;
+
+ xing_header = generate_xing_header (xing);
+
+ if (xing_header == NULL) {
+ GST_ERROR ("Can't generate Xing header");
+ gst_buffer_unref (outbuf);
+ return GST_FLOW_ERROR;
+ }
+
+ xing_header_size = gst_buffer_get_size (xing_header);
+
+ if ((ret = gst_pad_push (xing->srcpad, xing_header)) != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (xing, "Failed to push Xing header: %s",
+ gst_flow_get_name (ret));
+ gst_buffer_unref (xing_header);
+ gst_buffer_unref (outbuf);
+ return ret;
+ }
+
+ xing->byte_count += xing_header_size;
+ xing->sent_xing = TRUE;
+ }
+ }
+
+ seek_entry = gst_xing_seek_entry_new ();
+ seek_entry->timestamp =
+ (xing->duration == GST_CLOCK_TIME_NONE) ? 0 : xing->duration;
+ /* Workaround for parsers checking that the first seek table entry is 0 */
+ seek_entry->byte = (seek_entry->timestamp == 0) ? 0 : xing->byte_count;
+ xing->seek_table = g_list_append (xing->seek_table, seek_entry);
+
+ duration = gst_util_uint64_scale_ceil (spf, GST_SECOND, rate);
+
+ GST_BUFFER_TIMESTAMP (outbuf) =
+ (xing->duration == GST_CLOCK_TIME_NONE) ? 0 : xing->duration;
+ GST_BUFFER_DURATION (outbuf) = duration;
+ GST_BUFFER_OFFSET (outbuf) = xing->byte_count;
+ xing->byte_count += gst_buffer_get_size (outbuf);
+ GST_BUFFER_OFFSET_END (outbuf) = xing->byte_count;
+
+ if (xing->duration == GST_CLOCK_TIME_NONE)
+ xing->duration = duration;
+ else
+ xing->duration += duration;
+
+ if ((ret = gst_pad_push (xing->srcpad, outbuf)) != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (xing, "Failed to push MP3 frame: %s",
+ gst_flow_get_name (ret));
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_xing_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstXingMux *xing;
+ gboolean result;
+
+ xing = GST_XING_MUX (parent);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ if (xing->sent_xing) {
+ GST_ERROR ("Already sent Xing header, dropping NEWSEGMENT event!");
+ gst_event_unref (event);
+ result = FALSE;
+ } else {
+ GstSegment segment;
+
+ gst_event_copy_segment (event, &segment);
+
+ if (segment.format == GST_FORMAT_BYTES) {
+ result = gst_pad_push_event (xing->srcpad, event);
+ } else {
+
+ gst_event_unref (event);
+ gst_segment_init (&segment, GST_FORMAT_BYTES);
+ event = gst_event_new_segment (&segment);
+
+ result = gst_pad_push_event (xing->srcpad, event);
+ }
+ }
+ break;
+
+ case GST_EVENT_EOS:{
+ GstEvent *n_event;
+
+ GST_DEBUG_OBJECT (xing, "handling EOS event");
+
+ if (xing->sent_xing) {
+ GstSegment segment;
+
+ gst_segment_init (&segment, GST_FORMAT_BYTES);
+ n_event = gst_event_new_segment (&segment);
+
+ if (G_UNLIKELY (!gst_pad_push_event (xing->srcpad, n_event))) {
+ GST_WARNING
+ ("Failed to seek to position 0 for pushing the Xing header");
+ } else {
+ GstBuffer *header;
+ GstFlowReturn ret;
+
+ header = generate_xing_header (xing);
+
+ if (header == NULL) {
+ GST_ERROR ("Can't generate Xing header");
+ } else {
+
+ GST_INFO ("Writing real Xing header to beginning of stream");
+
+ if ((ret = gst_pad_push (xing->srcpad, header)) != GST_FLOW_OK)
+ GST_WARNING ("Failed to push updated Xing header: %s\n",
+ gst_flow_get_name (ret));
+ }
+ }
+ }
+ result = gst_pad_push_event (xing->srcpad, event);
+ break;
+ }
+ default:
+ result = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return result;
+}
+
+
+static GstStateChangeReturn
+gst_xing_mux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstXingMux *xing;
+ GstStateChangeReturn result;
+
+ xing = GST_XING_MUX (element);
+
+ result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ xing_reset (xing);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
diff --git a/gst/xingmux/gstxingmux.h b/gst/xingmux/gstxingmux.h
new file mode 100644
index 0000000..9f0c47a
--- /dev/null
+++ b/gst/xingmux/gstxingmux.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (c) 2008 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#ifndef __GST_XINGMUX_H__
+#define __GST_XINGMUX_H__
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_XING_MUX \
+ (gst_xing_mux_get_type())
+#define GST_XING_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XING_MUX,GstXingMux))
+#define GST_XING_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XING_MUX,GstXingMuxClass))
+#define GST_IS_XING_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XING_MUX))
+#define GST_IS_XING_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XING_MUX))
+
+typedef struct _GstXingMux GstXingMux;
+typedef struct _GstXingMuxClass GstXingMuxClass;
+
+/* Definition of structure storing data for this element. */
+
+/**
+ * GstXingMux:
+ *
+ * Opaque data structure.
+ */
+struct _GstXingMux {
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ /* < private > */
+
+ GstAdapter *adapter;
+ GstClockTime duration;
+ guint64 byte_count;
+ guint64 frame_count;
+ GList *seek_table;
+ gboolean sent_xing;
+
+ /* Copy of the first frame header */
+ guint32 first_header;
+};
+
+/* Standard definition defining a class for this element. */
+
+/**
+ * GstXingMuxClass:
+ *
+ * Opaque data structure.
+ */
+struct _GstXingMuxClass {
+ GstElementClass parent_class;
+};
+
+/* Standard function returning type information. */
+GType gst_xing_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_XINGMUX_H__ */
diff --git a/gst/xingmux/plugin.c b/gst/xingmux/plugin.c
new file mode 100644
index 0000000..470a24e
--- /dev/null
+++ b/gst/xingmux/plugin.c
@@ -0,0 +1,41 @@
+/* GStreamer
+ * Copyright (C) <2008> Jan Schmidt <jan.schmidt@sun.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstxingmux.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "xingmux", GST_RANK_MARGINAL,
+ GST_TYPE_XING_MUX))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ xingmux,
+ "Add XING tags to mpeg audio files",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);