Index: tests/examples/qtmux/Makefile.in
===================================================================
--- tests/examples/qtmux/Makefile.in	(revision 0)
+++ tests/examples/qtmux/Makefile.in	(revision 473)
@@ -0,0 +1,742 @@
+# Makefile.in generated by automake 1.10.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008  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@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@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@
+noinst_PROGRAMS = qtmuxrecover$(EXEEXT) qtmuxedits$(EXEEXT)
+subdir = tests/examples/qtmux
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+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-objc.m4 \
+	$(top_srcdir)/common/m4/as-python.m4 \
+	$(top_srcdir)/common/m4/as-scrub-include.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-dowhile.m4 \
+	$(top_srcdir)/common/m4/gst-error.m4 \
+	$(top_srcdir)/common/m4/gst-feature.m4 \
+	$(top_srcdir)/common/m4/gst-gettext.m4 \
+	$(top_srcdir)/common/m4/gst-glib2.m4 \
+	$(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+	$(top_srcdir)/common/m4/gst-plugindir.m4 \
+	$(top_srcdir)/common/m4/gst-x11.m4 \
+	$(top_srcdir)/common/m4/gst.m4 \
+	$(top_srcdir)/common/m4/gtk-doc.m4 \
+	$(top_srcdir)/common/m4/pkg.m4 \
+	$(top_srcdir)/common/m4/shave.m4 $(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gst-alsa.m4 $(top_srcdir)/m4/gst-fionread.m4 \
+	$(top_srcdir)/m4/gst-sdl.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 =
+PROGRAMS = $(noinst_PROGRAMS)
+am_qtmuxedits_OBJECTS = qtmuxedits-qtmuxedits-test.$(OBJEXT)
+qtmuxedits_OBJECTS = $(am_qtmuxedits_OBJECTS)
+qtmuxedits_LDADD = $(LDADD)
+qtmuxedits_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(qtmuxedits_CFLAGS) \
+	$(CFLAGS) $(qtmuxedits_LDFLAGS) $(LDFLAGS) -o $@
+am_qtmuxrecover_OBJECTS = qtmuxrecover-qtmuxrecover-test.$(OBJEXT)
+qtmuxrecover_OBJECTS = $(am_qtmuxrecover_OBJECTS)
+qtmuxrecover_LDADD = $(LDADD)
+qtmuxrecover_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(qtmuxrecover_CFLAGS) \
+	$(CFLAGS) $(qtmuxrecover_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(qtmuxedits_SOURCES) $(qtmuxrecover_SOURCES)
+DIST_SOURCES = $(qtmuxedits_SOURCES) $(qtmuxrecover_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ACMENC_CFLAGS = @ACMENC_CFLAGS@
+ACMMP3DEC_CFLAGS = @ACMMP3DEC_CFLAGS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMRWB_LIBS = @AMRWB_LIBS@
+AMTAR = @AMTAR@
+AM_MAKEFLAGS = @AM_MAKEFLAGS@
+APEXSINK_CFLAGS = @APEXSINK_CFLAGS@
+APEXSINK_LIBS = @APEXSINK_LIBS@
+AR = @AR@
+AS = @AS@
+ASSRENDER_CFLAGS = @ASSRENDER_CFLAGS@
+ASSRENDER_LIBS = @ASSRENDER_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CC = @CC@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDAUDIO_CFLAGS = @CDAUDIO_CFLAGS@
+CDAUDIO_CONFIG = @CDAUDIO_CONFIG@
+CDAUDIO_LIBS = @CDAUDIO_LIBS@
+CELT_CFLAGS = @CELT_CFLAGS@
+CELT_LIBS = @CELT_LIBS@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DCCP_LIBS = @DCCP_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRAC_CFLAGS = @DIRAC_CFLAGS@
+DIRAC_LIBS = @DIRAC_LIBS@
+DIRECTDRAW_CFLAGS = @DIRECTDRAW_CFLAGS@
+DIRECTDRAW_LDFLAGS = @DIRECTDRAW_LDFLAGS@
+DIRECTDRAW_LIBS = @DIRECTDRAW_LIBS@
+DIRECTFB_CFLAGS = @DIRECTFB_CFLAGS@
+DIRECTFB_LIBS = @DIRECTFB_LIBS@
+DIVXDEC_LIBS = @DIVXDEC_LIBS@
+DIVXENC_LIBS = @DIVXENC_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DTS_LIBS = @DTS_LIBS@
+DUMPBIN = @DUMPBIN@
+DVDNAV_CFLAGS = @DVDNAV_CFLAGS@
+DVDNAV_CONFIG = @DVDNAV_CONFIG@
+DVDNAV_LIBS = @DVDNAV_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@
+EXIF_CFLAGS = @EXIF_CFLAGS@
+EXIF_LIBS = @EXIF_LIBS@
+EXPAT_LIBS = @EXPAT_LIBS@
+F77 = @F77@
+FAAC_LIBS = @FAAC_LIBS@
+FAAD_IS_NEAAC = @FAAD_IS_NEAAC@
+FAAD_LIBS = @FAAD_LIBS@
+FC = @FC@
+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_LIBS = @GIO_LIBS@
+GLADE_CFLAGS = @GLADE_CFLAGS@
+GLADE_LIBS = @GLADE_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GMYTH_CFLAGS = @GMYTH_CFLAGS@
+GMYTH_LIBS = @GMYTH_LIBS@
+GREP = @GREP@
+GSM_LIBS = @GSM_LIBS@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+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_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+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_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+HAVE_AMRWB = @HAVE_AMRWB@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTDRAW = @HAVE_DIRECTDRAW@
+HAVE_DTS = @HAVE_DTS@
+HAVE_FAAC = @HAVE_FAAC@
+HAVE_FAAD = @HAVE_FAAD@
+HAVE_GLADE = @HAVE_GLADE@
+HAVE_GSM = @HAVE_GSM@
+HAVE_JP2K = @HAVE_JP2K@
+HAVE_NAS = @HAVE_NAS@
+HAVE_QTMUX = @HAVE_QTMUX@
+HAVE_X = @HAVE_X@
+HAVE_X11 = @HAVE_X11@
+HAVE_X264 = @HAVE_X264@
+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@
+IPTC_CFLAGS = @IPTC_CFLAGS@
+IPTC_LIBS = @IPTC_LIBS@
+IVORBIS_CFLAGS = @IVORBIS_CFLAGS@
+IVORBIS_LIBS = @IVORBIS_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JP2K_LIBS = @JP2K_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDC1394_CFLAGS = @LIBDC1394_CFLAGS@
+LIBDC1394_LIBS = @LIBDC1394_LIBS@
+LIBDIR = @LIBDIR@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBMMS_CFLAGS = @LIBMMS_CFLAGS@
+LIBMMS_LIBS = @LIBMMS_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOIL_CFLAGS = @LIBOIL_CFLAGS@
+LIBOIL_LIBS = @LIBOIL_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LRDF_CFLAGS = @LRDF_CFLAGS@
+LRDF_LIBS = @LRDF_LIBS@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEFLAGS = @MAKEFLAGS@
+MAKEINFO = @MAKEINFO@
+METADATA_CFLAGS = @METADATA_CFLAGS@
+METADATA_LIBS = @METADATA_LIBS@
+MIMIC_CFLAGS = @MIMIC_CFLAGS@
+MIMIC_LIBS = @MIMIC_LIBS@
+MJPEG_CFLAGS = @MJPEG_CFLAGS@
+MJPEG_LIBS = @MJPEG_LIBS@
+MKDIR_P = @MKDIR_P@
+MODPLUG_CFLAGS = @MODPLUG_CFLAGS@
+MODPLUG_LIBS = @MODPLUG_LIBS@
+MPEG2ENC_CFLAGS = @MPEG2ENC_CFLAGS@
+MPEG2ENC_LIBS = @MPEG2ENC_LIBS@
+MPLEX_CFLAGS = @MPLEX_CFLAGS@
+MPLEX_LIBS = @MPLEX_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MUSEPACK_LIBS = @MUSEPACK_LIBS@
+MUSICBRAINZ_CFLAGS = @MUSICBRAINZ_CFLAGS@
+MUSICBRAINZ_LIBS = @MUSICBRAINZ_LIBS@
+NAS_CFLAGS = @NAS_CFLAGS@
+NAS_LIBS = @NAS_LIBS@
+NEON_CFLAGS = @NEON_CFLAGS@
+NEON_LIBS = @NEON_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OFA_CFLAGS = @OFA_CFLAGS@
+OFA_LIBS = @OFA_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+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@
+Q = @Q@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+SOUNDTOUCH_CFLAGS = @SOUNDTOUCH_CFLAGS@
+SOUNDTOUCH_LIBS = @SOUNDTOUCH_LIBS@
+SPC_LIBS = @SPC_LIBS@
+STRIP = @STRIP@
+SWFDEC_CFLAGS = @SWFDEC_CFLAGS@
+SWFDEC_LIBS = @SWFDEC_LIBS@
+THEORADEC_CFLAGS = @THEORADEC_CFLAGS@
+THEORADEC_LIBS = @THEORADEC_LIBS@
+TIMIDITY_CFLAGS = @TIMIDITY_CFLAGS@
+TIMIDITY_LIBS = @TIMIDITY_LIBS@
+USE_NLS = @USE_NLS@
+V = @V@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WILDMIDI_CFLAGS = @WILDMIDI_CFLAGS@
+WILDMIDI_LIBS = @WILDMIDI_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+X11_CFLAGS = @X11_CFLAGS@
+X11_LIBS = @X11_LIBS@
+X264_CFLAGS = @X264_CFLAGS@
+X264_LIBS = @X264_LIBS@
+XDG_LIBS = @XDG_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XMP_1_99_5_CFLAGS = @XMP_1_99_5_CFLAGS@
+XMP_1_99_5_LIBS = @XMP_1_99_5_LIBS@
+XMP_CFLAGS = @XMP_CFLAGS@
+XMP_LIBS = @XMP_LIBS@
+XVID_LIBS = @XVID_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+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@
+lt_ECHO = @lt_ECHO@
+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@
+shavedir = @shavedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+qtmuxrecover_SOURCES = qtmuxrecover-test.c
+qtmuxrecover_CFLAGS = $(GST_CFLAGS)
+qtmuxrecover_LDFLAGS = $(GST_LIBS)
+qtmuxedits_SOURCES = qtmuxedits-test.c
+qtmuxedits_CFLAGS = $(GST_CFLAGS)
+qtmuxedits_LDFLAGS = $(GST_LIBS)
+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  tests/examples/qtmux/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  tests/examples/qtmux/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
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+qtmuxedits$(EXEEXT): $(qtmuxedits_OBJECTS) $(qtmuxedits_DEPENDENCIES) 
+	@rm -f qtmuxedits$(EXEEXT)
+	$(qtmuxedits_LINK) $(qtmuxedits_OBJECTS) $(qtmuxedits_LDADD) $(LIBS)
+qtmuxrecover$(EXEEXT): $(qtmuxrecover_OBJECTS) $(qtmuxrecover_DEPENDENCIES) 
+	@rm -f qtmuxrecover$(EXEEXT)
+	$(qtmuxrecover_LINK) $(qtmuxrecover_OBJECTS) $(qtmuxrecover_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtmuxedits-qtmuxedits-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+qtmuxedits-qtmuxedits-test.o: qtmuxedits-test.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxedits_CFLAGS) $(CFLAGS) -MT qtmuxedits-qtmuxedits-test.o -MD -MP -MF $(DEPDIR)/qtmuxedits-qtmuxedits-test.Tpo -c -o qtmuxedits-qtmuxedits-test.o `test -f 'qtmuxedits-test.c' || echo '$(srcdir)/'`qtmuxedits-test.c
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/qtmuxedits-qtmuxedits-test.Tpo $(DEPDIR)/qtmuxedits-qtmuxedits-test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='qtmuxedits-test.c' object='qtmuxedits-qtmuxedits-test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxedits_CFLAGS) $(CFLAGS) -c -o qtmuxedits-qtmuxedits-test.o `test -f 'qtmuxedits-test.c' || echo '$(srcdir)/'`qtmuxedits-test.c
+
+qtmuxedits-qtmuxedits-test.obj: qtmuxedits-test.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxedits_CFLAGS) $(CFLAGS) -MT qtmuxedits-qtmuxedits-test.obj -MD -MP -MF $(DEPDIR)/qtmuxedits-qtmuxedits-test.Tpo -c -o qtmuxedits-qtmuxedits-test.obj `if test -f 'qtmuxedits-test.c'; then $(CYGPATH_W) 'qtmuxedits-test.c'; else $(CYGPATH_W) '$(srcdir)/qtmuxedits-test.c'; fi`
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/qtmuxedits-qtmuxedits-test.Tpo $(DEPDIR)/qtmuxedits-qtmuxedits-test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='qtmuxedits-test.c' object='qtmuxedits-qtmuxedits-test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxedits_CFLAGS) $(CFLAGS) -c -o qtmuxedits-qtmuxedits-test.obj `if test -f 'qtmuxedits-test.c'; then $(CYGPATH_W) 'qtmuxedits-test.c'; else $(CYGPATH_W) '$(srcdir)/qtmuxedits-test.c'; fi`
+
+qtmuxrecover-qtmuxrecover-test.o: qtmuxrecover-test.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxrecover_CFLAGS) $(CFLAGS) -MT qtmuxrecover-qtmuxrecover-test.o -MD -MP -MF $(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Tpo -c -o qtmuxrecover-qtmuxrecover-test.o `test -f 'qtmuxrecover-test.c' || echo '$(srcdir)/'`qtmuxrecover-test.c
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Tpo $(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='qtmuxrecover-test.c' object='qtmuxrecover-qtmuxrecover-test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxrecover_CFLAGS) $(CFLAGS) -c -o qtmuxrecover-qtmuxrecover-test.o `test -f 'qtmuxrecover-test.c' || echo '$(srcdir)/'`qtmuxrecover-test.c
+
+qtmuxrecover-qtmuxrecover-test.obj: qtmuxrecover-test.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxrecover_CFLAGS) $(CFLAGS) -MT qtmuxrecover-qtmuxrecover-test.obj -MD -MP -MF $(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Tpo -c -o qtmuxrecover-qtmuxrecover-test.obj `if test -f 'qtmuxrecover-test.c'; then $(CYGPATH_W) 'qtmuxrecover-test.c'; else $(CYGPATH_W) '$(srcdir)/qtmuxrecover-test.c'; fi`
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Tpo $(DEPDIR)/qtmuxrecover-qtmuxrecover-test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='qtmuxrecover-test.c' object='qtmuxrecover-qtmuxrecover-test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(qtmuxrecover_CFLAGS) $(CFLAGS) -c -o qtmuxrecover-qtmuxrecover-test.obj `if test -f 'qtmuxrecover-test.c'; then $(CYGPATH_W) 'qtmuxrecover-test.c'; else $(CYGPATH_W) '$(srcdir)/qtmuxrecover-test.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+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 $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$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 $(PROGRAMS)
+installdirs:
+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:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_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 \
+	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
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+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
+
+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:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstPROGRAMS ctags 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-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 uninstall uninstall-am
+
+# 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:
Index: tests/examples/qtmux/qtmuxrecover-test.c
===================================================================
--- tests/examples/qtmux/qtmuxrecover-test.c	(revision 0)
+++ tests/examples/qtmux/qtmuxrecover-test.c	(revision 477)
@@ -0,0 +1,94 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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.
+ */
+#include <stdio.h>
+#include <gmodule.h>
+#include <gst/gst.h>
+#include <gst/qtmux/gstqtmuxrecover.h>
+
+
+static gst_qt_mux_recover_ptr gst_qt_mux_recover_cb = NULL;
+
+int main(int argc, char ** argv)
+{
+	GModule * qtmux_module;
+	GstPlugin * plugin;
+	gpointer ptr=NULL;
+	gint ret = 1;
+	guint64 duration = 0;
+
+	if(argc != 3) {
+		printf("Expected:\n\n");
+		printf("%s [MP4-IN-FILE] [MOOV-XML-BACKUP-FILE]\n\n", argv[0]);
+		goto end;
+	}
+
+	gst_init(&argc, &argv);
+
+	if(!(plugin = gst_plugin_load_by_name("qtmux"))) {
+		g_warning("Failed to load gstreamer plugin 'qtmux'");
+		goto end;
+	}
+
+	if(!(qtmux_module = gst_plugin_get_module(plugin))) {
+		g_warning("Failed to get glib module");
+		goto end;
+	}
+
+	if(!g_module_symbol(qtmux_module, "gst_qt_mux_recover", &ptr) || ptr==NULL) {
+		g_warning("Failed to load symbol: 'gst_qt_mux_recover'");
+		goto end;
+	}
+
+	gst_qt_mux_recover_cb = ptr;
+
+	if(!gst_qt_mux_recover_cb(argv[1], argv[2], &duration))
+		goto end;
+
+	printf("Success.. duration: %llu (ns)\n", duration);
+
+	ret = 0;
+
+ end:
+	return ret;
+}
Index: tests/examples/qtmux/qtmuxedits-test.c
===================================================================
--- tests/examples/qtmux/qtmuxedits-test.c	(revision 0)
+++ tests/examples/qtmux/qtmuxedits-test.c	(revision 477)
@@ -0,0 +1,447 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <gst/gst.h>
+#include "qtmuxedits-test.h"
+
+GST_DEBUG_CATEGORY (gst_qtmuxtest_debug);
+#define GST_CAT_DEFAULT gst_qtmuxtest_debug
+
+#define TRANS_TIMEOUT (GST_SECOND * 10)
+
+static GMainLoop * loop = NULL;
+static GstElement * pipeline = NULL;
+static GstElement * vidsrc = NULL;
+static GstElement * videnc = NULL;
+static GstElement * vidque = NULL;
+static GstElement * audsrc = NULL;
+static GstElement * audenc = NULL;
+static GstElement * audque = NULL;
+static GstElement * muxer = NULL;
+static GstElement * filesink = NULL;
+
+#define TEST_EDITS
+//# define AUDIO_SEG_START
+#define AUDIO_SEG_LEN   3
+gulong timeout_id = 0;
+
+/* QT or MP4 */
+#define USE_QT_FMT
+
+gboolean qtmux_test_bus_watch_cb(GstBus * bus, GstMessage * message, gpointer userdata)
+{
+	const gchar * msg_name;
+	GError *err=NULL;
+	gchar *debug=NULL;
+	gchar *src_name;
+
+	g_return_val_if_fail(message != NULL, TRUE);
+
+	src_name = gst_object_get_name(message->src);
+
+	msg_name = gst_message_type_get_name(GST_MESSAGE_TYPE(message));
+	if(!msg_name)
+		msg_name = "Unknown";
+
+	switch((gint)GST_MESSAGE_TYPE(message)) {
+
+	case GST_MESSAGE_WARNING:
+	{
+		gst_message_parse_warning(message, &err, &debug);
+		GST_DEBUG("%s - %s - %s",
+			  msg_name,
+			  (err?(err->message?err->message:""):""),
+			  (debug?debug:""));
+		g_error_free(err);
+		g_free(debug);
+		break;
+	}
+
+	case GST_MESSAGE_ERROR: 
+	{
+		gst_message_parse_error(message, &err, &debug);
+		GST_ERROR("%s - %s - %s",
+			  msg_name,
+			  (err?(err->message?err->message:""):""),
+			  (debug?debug:""));
+		g_free(debug);
+		debug = gst_object_get_name(message->src);
+		if(debug) {
+			GST_ERROR("%s - error src object: %s", msg_name, debug);
+		}
+		g_error_free(err);
+		g_free(debug);
+		break;
+	}
+
+    case GST_MESSAGE_STATE_CHANGED:
+	{
+		GstState old_state, new_state, pending;
+
+		gst_message_parse_state_changed(message, &old_state, &new_state, &pending);
+
+		if(old_state == new_state)
+			break;
+
+		/* Seeing state changes of child elements is too verbose..
+		 */
+#if 1
+		GST_DEBUG("%s changed state from %s to %s", src_name,
+				  gst_element_state_get_name(old_state),
+				  gst_element_state_get_name(new_state));
+#endif
+		break;
+	}
+
+	case GST_MESSAGE_EOS:
+	{
+		GST_DEBUG("[%s] EOS", src_name);
+		g_main_loop_quit(loop);
+		break;
+	}
+
+	}/* end switch */
+
+	g_free(src_name);
+
+	return TRUE;
+}
+
+GstStateChangeReturn qtmux_test_set_element_state(GstElement * bin,
+														 GstState state, GstClockTime timeout)
+{
+	GstStateChangeReturn rstate;
+
+	rstate = gst_element_set_state(bin, state);
+	if(rstate == GST_STATE_CHANGE_ASYNC) {
+		if(timeout !=0) {
+			rstate = gst_element_get_state(bin, NULL, NULL, timeout);
+		}
+	}
+
+	return rstate;
+}
+
+gchar * get_request_pad_data_name(gboolean is_src, GstElement * elem)
+{
+	gchar * name, *ret;
+
+	if(!GST_IS_ELEMENT(elem))
+		return NULL;
+	if(!(name = gst_object_get_name(GST_OBJECT(elem))))
+		return NULL;
+	ret = g_strdup_printf("%s-%s-request-pad", name, is_src?"src":"sink");
+	g_free(name);
+	return ret;
+}
+
+gboolean qtmux_test_request_sinkpad_link(GstElement * src, const gchar * src_pad,
+												GstElement * sink, const char * sink_pad)
+{
+	GstPad *srcpad=NULL, *sinkpad=NULL;
+	gchar * datname;
+
+	g_return_val_if_fail(src != NULL, FALSE);
+	g_return_val_if_fail(src_pad != NULL, FALSE);
+	g_return_val_if_fail(sink != NULL, FALSE);
+	g_return_val_if_fail(sink_pad != NULL, FALSE);
+
+	/* Get Pads.. */
+	if(!(sinkpad = gst_element_get_request_pad(sink, sink_pad)))
+		goto err;
+
+	if(!(srcpad = gst_element_get_static_pad(src, src_pad)))
+		goto err;
+
+	/* Link Pads.. */
+	if(gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK)
+		goto err;
+
+	/* Attach pad .. w/ unique name */
+	if(!(datname = get_request_pad_data_name(FALSE, src)))
+		goto err;
+
+	g_object_set_data(G_OBJECT(sink), datname, sinkpad);
+	g_free(datname);
+
+	return TRUE;
+
+ err:
+	if(sinkpad) {
+		gst_element_release_request_pad(sink, sinkpad);
+	}
+
+	return FALSE;
+}
+
+void qtmux_test_request_sinkpad_unlink(GstElement * src, GstElement * sink)
+{
+	GstPad * sinkpad=NULL;
+	gchar * datname;
+
+	gst_element_unlink(src, sink);
+
+	datname = get_request_pad_data_name(FALSE, src);
+	if(datname) {
+		sinkpad = (GstPad*)g_object_get_data(G_OBJECT(sink), datname);
+		if(sinkpad) {
+			gst_element_release_request_pad(sink, sinkpad);
+			g_object_set_data(G_OBJECT(sink), datname, NULL);
+		}
+		g_free(datname);
+	}
+}
+
+gboolean qtmux_test_init(const gchar * filename)
+{
+	g_return_val_if_fail(filename != NULL, FALSE);
+
+	GST_MAKE_OR_BREAK_PIPELINE(pipeline, "qtmux-test-pipeline", err);
+
+	gst_bus_add_watch(gst_pipeline_get_bus((GstPipeline*)pipeline),
+					  (GstBusFunc)qtmux_test_bus_watch_cb, NULL);
+
+	/* Video Leg */
+	GST_MAKE_OR_BREAK_ELEMENT(vidsrc, "videotestsrc", NULL, err);
+	GST_MAKE_OR_BREAK_ELEMENT(videnc,
+#ifdef USE_QT_FMT
+							  "x264enc",
+#else
+							  "ffenc_mpeg4",
+#endif
+							  NULL, err);
+	GST_MAKE_OR_BREAK_ELEMENT(vidque, "queue", "video-queue", err);
+	/* Audio Leg */
+	GST_MAKE_OR_BREAK_ELEMENT(audsrc, "audiotestsrc", NULL, err);
+	GST_MAKE_OR_BREAK_ELEMENT(audenc, "faac", NULL, err);
+	GST_MAKE_OR_BREAK_ELEMENT(audque, "queue", "audio-queue", err);
+	/* Muxer */
+	GST_MAKE_OR_BREAK_ELEMENT(muxer,
+#ifdef USE_QT_FMT
+							  "qtmux",
+#else
+							  "mp4mux",
+#endif
+							  NULL, err);
+	GST_MAKE_OR_BREAK_ELEMENT(filesink, "filesink", NULL, err);
+
+	/* Configure */
+	g_object_set(G_OBJECT(vidsrc), "is-live", TRUE, NULL);
+	g_object_set(G_OBJECT(audsrc), "is-live", TRUE, NULL);
+	g_object_set(G_OBJECT(audenc), "profile", 2, NULL);
+	g_object_set(G_OBJECT(muxer), "mux-by-timestamp",
+#if defined(TEST_EDITS)
+				 TRUE,
+#else
+				 FALSE,
+#endif
+				 NULL);
+	g_object_set(G_OBJECT(filesink), "async", FALSE, NULL);
+	g_object_set(G_OBJECT(filesink), "sync", FALSE, NULL);
+	g_object_set(G_OBJECT(filesink), "location", filename, NULL);
+
+	/* Add */
+	gst_bin_add_many(GST_BIN(pipeline),
+					 muxer, filesink, NULL);
+
+	/* Link */
+	GST_LINK_PADS_OR_BREAK(muxer, "src", filesink, "sink", err);
+
+	return TRUE;
+
+ err:
+	GST_ERROR("Something didn't work");
+	return FALSE;
+}
+
+gboolean qtmux_test_link_video()
+{
+	gboolean is_playing;
+
+	is_playing = (GST_STATE(pipeline) == GST_STATE_PLAYING);
+
+	gst_bin_add_many(GST_BIN(pipeline), vidsrc, videnc, vidque, NULL);
+
+	GST_LINK_PADS_OR_BREAK(vidsrc, "src", videnc, "sink", err);
+	GST_LINK_PADS_OR_BREAK(videnc, "src", vidque, "sink", err);
+	GST_LINK_REQ_SINK_OR_BREAK(vidque, "src", muxer, "video_00", err);
+
+	if(is_playing) {
+		GST_SET_STATE_OR_BREAK_TM(vidque, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+		GST_SET_STATE_OR_BREAK_TM(videnc, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+		GST_SET_STATE_OR_BREAK_TM(vidsrc, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+	}
+
+	return TRUE;
+ err:
+	return FALSE;
+}
+
+gboolean qtmux_test_link_audio()
+{
+	gboolean is_playing;
+
+	is_playing = (GST_STATE(pipeline) == GST_STATE_PLAYING);
+
+	gst_bin_add_many(GST_BIN(pipeline), audsrc, audenc, audque, NULL);
+
+	GST_LINK_PADS_OR_BREAK(audsrc, "src", audenc, "sink", err);
+	GST_LINK_PADS_OR_BREAK(audenc, "src", audque, "sink", err);
+	GST_LINK_REQ_SINK_OR_BREAK(audque, "src", muxer, "audio_00", err);
+
+	if(is_playing) {
+		GST_SET_STATE_OR_BREAK_TM(audque, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+		GST_SET_STATE_OR_BREAK_TM(audenc, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+		GST_SET_STATE_OR_BREAK_TM(audsrc, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+	}
+
+	return TRUE;
+ err:
+	return FALSE;
+}
+
+gboolean qtmux_test_unlink_audio()
+{
+	gboolean is_playing;
+
+	is_playing = (GST_STATE(audsrc) == GST_STATE_PLAYING);
+
+	if(is_playing)
+		qtmux_test_set_element_state(audsrc, GST_STATE_NULL, TRANS_TIMEOUT);
+
+	gst_element_unlink(audsrc, audenc);
+	gst_element_unlink(audenc, audque);
+	qtmux_test_request_sinkpad_unlink(audque, muxer);
+
+	gst_element_set_state(audsrc, GST_STATE_NULL);
+	gst_element_set_state(audenc, GST_STATE_NULL);
+	gst_element_set_state(audque, GST_STATE_NULL);
+
+	gst_object_ref(GST_OBJECT(audsrc));
+	gst_bin_remove(GST_BIN(pipeline), audsrc);
+	gst_object_ref(GST_OBJECT(audenc));
+	gst_bin_remove(GST_BIN(pipeline), audenc);
+	gst_object_ref(GST_OBJECT(audque));
+	gst_bin_remove(GST_BIN(pipeline), audque);
+
+	return TRUE;
+}
+
+void qtmux_test_send_eos()
+{
+	GST_INFO("EOS on shutdown");
+
+	gst_element_send_event (pipeline, gst_event_new_eos());
+
+	GST_INFO("Waiting for EOS...");
+}
+
+void signal_trap(int sig)
+{
+	GST_INFO("Received 'SIGINT' signal. Shutting down..");
+
+	signal(SIGINT, SIG_DFL);
+
+	if(timeout_id > 0) {
+		g_source_remove(timeout_id);
+		timeout_id = 0;
+	}
+	qtmux_test_send_eos();
+}
+
+gboolean qtmux_test_timeout_cb(gpointer userdata)
+{
+	if(gst_element_get_parent(audsrc)) {
+		GST_INFO("Removing audio source..");
+		qtmux_test_unlink_audio();
+	}
+	else {
+		qtmux_test_link_audio();
+		GST_INFO("Adding audio source..");
+	}
+	return TRUE;
+}
+
+int main (int argc, char *argv[])
+{
+	gchar * filename = "test.mp4";
+
+	signal(SIGINT, signal_trap);
+
+	if(argc == 2 && argv[1] != NULL)
+		filename = argv[1];
+
+	if(!g_thread_supported())
+		g_thread_init(NULL);
+
+	gst_init(&argc, &argv);
+
+	GST_DEBUG_CATEGORY_INIT (gst_qtmuxtest_debug, "qtmuxedits", 0, "QT Muxer edit atom testing");
+
+	qtmux_test_init(filename);
+
+	qtmux_test_link_video();
+#if defined(AUDIO_SEG_START)
+	qtmux_test_link_audio();
+#endif
+
+	GST_SET_STATE_OR_BREAK_TM(pipeline, GST_STATE_PLAYING, TRANS_TIMEOUT, err);
+
+	timeout_id = g_timeout_add(AUDIO_SEG_LEN * 1000, (GSourceFunc)qtmux_test_timeout_cb, NULL);
+
+	/** Create glib main loop **/
+	loop = g_main_loop_new(NULL, TRUE);
+
+	GST_INFO("Entering main loop");
+
+	/** Run main loop **/
+	g_main_loop_run(loop);
+
+	GST_INFO("Exiting main loop");
+
+ err:
+	return 0;
+}
Index: tests/examples/qtmux/Makefile.am
===================================================================
--- tests/examples/qtmux/Makefile.am	(revision 0)
+++ tests/examples/qtmux/Makefile.am	(revision 473)
@@ -0,0 +1,9 @@
+noinst_PROGRAMS = qtmuxrecover qtmuxedits
+
+qtmuxrecover_SOURCES = qtmuxrecover-test.c
+qtmuxrecover_CFLAGS = $(GST_CFLAGS)
+qtmuxrecover_LDFLAGS = $(GST_LIBS)
+
+qtmuxedits_SOURCES = qtmuxedits-test.c
+qtmuxedits_CFLAGS = $(GST_CFLAGS)
+qtmuxedits_LDFLAGS = $(GST_LIBS)
Index: tests/examples/qtmux/qtmuxedits-test.h
===================================================================
--- tests/examples/qtmux/qtmuxedits-test.h	(revision 0)
+++ tests/examples/qtmux/qtmuxedits-test.h	(revision 477)
@@ -0,0 +1,134 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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 _QTMUXTEST_H_
+#define _QTMUXTEST_H_
+
+#define GST_MAKE_OR_BREAK_PIPELINE(bin, name, err_label)				\
+	if(!(bin = gst_pipeline_new(name))) {								\
+		GST_ERROR("Pipeline element '%s' could not be created", #bin);	\
+		goto err_label;													\
+	}
+#define GST_MAKE_OR_BREAK_BIN(bin, name, err_label)						\
+	if(!(bin = gst_bin_new(name))) {									\
+		GST_ERROR("Bin element '%s' could not be created", #bin);			\
+		goto err_label;													\
+	}
+#define GST_MAKE_OR_BREAK_ELEMENT(element, type, name, err_label)		\
+	if(!(element = gst_element_factory_make(type, name))) {				\
+		GST_ERROR("'%s' element '%s' could not be created", type, #element); \
+		goto err_label;													\
+	}
+#define GST_LINK_OR_BREAK(elem1, elem2, filter_caps, err_label)			\
+	{																	\
+		gboolean link_resp;												\
+		GstCaps * fcaps = filter_caps;									\
+		if(fcaps) {														\
+			link_resp = gst_element_link_filtered(elem1, elem2, fcaps); \
+			gst_caps_unref(fcaps);										\
+		}																\
+		else															\
+			link_resp = gst_element_link(elem1, elem2); 				\
+		if(!link_resp) {												\
+			GST_ERROR("Linking %s w/ %s", #elem1, #elem2);					\
+			goto err_label;												\
+		}																\
+	}
+#define GST_LINK_REQ_SRC_OR_BREAK(src, srcpad, sink, sinkpad, block_if_playing, err_label) \
+	{																	\
+		if(!advr_gst_request_srcpad_link(src, srcpad, sink, sinkpad, block_if_playing)) { \
+			GST_ERROR("Linking %s w/ %s", #src, #sink);						\
+			goto err_label;												\
+		}																\
+	}
+#define GST_LINK_REQ_SINK_OR_BREAK(src, srcpad, sink, sinkpad, err_label) \
+	{																	\
+		if(!qtmux_test_request_sinkpad_link(src, srcpad, sink, sinkpad)) { \
+			GST_ERROR("Linking %s w/ %s", #src, #sink);						\
+			goto err_label;												\
+		}																\
+	}
+#define GST_LINK_PADS_OR_BREAK(elem1, pad1, elem2, pad2, err_label)		\
+	if(!gst_element_link_pads(elem1, pad1, elem2, pad2)) {				\
+		GST_ERROR("Linking %s w/ %s", #elem1, #elem2);						\
+		goto err_label;													\
+	}
+#define GST_GHOST_BIN_OR_BREAK(bin_elem, target_elem, bin_pad_name, target_pad_name, err_label) \
+	{																	\
+		GstPad * srcpad = gst_ghost_pad_new(bin_pad_name, gst_element_get_pad(target_elem, target_pad_name)); \
+		if(!srcpad) {													\
+			GST_ERROR("Could not create '%s' bin ghost pad: '%s'", #bin_elem, bin_pad_name); \
+			goto err_label;												\
+		}																\
+		gst_element_add_pad(bin_elem, srcpad);							\
+	}
+#define GST_SET_STATE_OR_BREAK(elem, state, err_label)					\
+	{																	\
+		GstStateChangeReturn rstate;									\
+		rstate = gst_element_set_state(elem, state);					\
+		if(rstate == GST_STATE_CHANGE_FAILURE) {						\
+			GST_ERROR("Setting element %s to %s", #elem, gst_element_state_get_name(state)); \
+			goto err_label;												\
+		}																\
+	}
+#define GST_SET_STATE_OR_BREAK_TM(elem, state, timeout, err_label)		\
+	{																	\
+		GstStateChangeReturn rstate;									\
+		rstate = qtmux_test_set_element_state(elem, state, timeout);	\
+		if(rstate == GST_STATE_CHANGE_FAILURE) {						\
+			GST_ERROR("Setting element %s to %s", #elem, gst_element_state_get_name(state)); \
+			goto err_label;												\
+		}																\
+		else if(timeout != 0 && rstate == GST_STATE_CHANGE_ASYNC) {		\
+			GST_ERROR("Timed out setting %s to %s", #elem, gst_element_state_get_name(state)); \
+			goto err_label;												\
+		}																\
+	}
+#define GST_DESTROY_IF_UNPARENTED(element)								\
+	if(element != NULL && gst_element_get_parent(element) == NULL) {	\
+		gst_object_unref(element);										\
+		element = NULL;													\
+	}
+
+
+#endif /* _QTMUXTEST_H_ */
Index: tests/examples/Makefile.in
===================================================================
--- tests/examples/Makefile.in	(revision 90)
+++ tests/examples/Makefile.in	(working copy)
@@ -150,6 +150,7 @@
 EXEEXT = @EXEEXT@
 EXIF_CFLAGS = @EXIF_CFLAGS@
 EXIF_LIBS = @EXIF_LIBS@
+EXPAT_LIBS = @EXPAT_LIBS@
 F77 = @F77@
 FAAC_LIBS = @FAAC_LIBS@
 FAAD_IS_NEAAC = @FAAD_IS_NEAAC@
@@ -219,6 +220,7 @@
 HAVE_GSM = @HAVE_GSM@
 HAVE_JP2K = @HAVE_JP2K@
 HAVE_NAS = @HAVE_NAS@
+HAVE_QTMUX = @HAVE_QTMUX@
 HAVE_X = @HAVE_X@
 HAVE_X11 = @HAVE_X11@
 HAVE_X264 = @HAVE_X264@
@@ -429,8 +431,10 @@
 @HAVE_GTK_TRUE@GTK_EXAMPLES = scaletempo
 @USE_DIRECTFB_FALSE@DIRECTFB_DIR = 
 @USE_DIRECTFB_TRUE@DIRECTFB_DIR = directfb
-SUBDIRS = $(DIRECTFB_DIR) $(GTK_EXAMPLES) switch
-DIST_SUBDIRS = directfb switch scaletempo mxf
+@USE_QTMUX_FALSE@QTMUX_DIR = 
+@USE_QTMUX_TRUE@QTMUX_DIR = qtmux
+SUBDIRS = $(DIRECTFB_DIR) $(GTK_EXAMPLES) switch $(QTMUX_DIR)
+DIST_SUBDIRS = directfb switch scaletempo mxf qtmux
 all: all-recursive
 
 .SUFFIXES:
Index: tests/examples/Makefile.am
===================================================================
--- tests/examples/Makefile.am	(revision 90)
+++ tests/examples/Makefile.am	(working copy)
@@ -10,5 +10,11 @@
 DIRECTFB_DIR=
 endif
 
-SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) switch
-DIST_SUBDIRS= directfb switch scaletempo mxf
+if USE_QTMUX
+QTMUX_DIR=qtmux
+else
+QTMUX_DIR=
+endif
+
+SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) switch $(QTMUX_DIR)
+DIST_SUBDIRS= directfb switch scaletempo mxf qtmux
Index: gst/qtmux/atom-moov-xml.c
===================================================================
--- gst/qtmux/atom-moov-xml.c	(revision 0)
+++ gst/qtmux/atom-moov-xml.c	(revision 476)
@@ -0,0 +1,3459 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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.
+ */
+#include <string.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+/* only needed for gst_util_uint64_scale */
+#include <gst/gst.h>
+
+/* Pulled in by libxml2 - conflicts with expat */
+#undef XMLCALL
+#include <expat.h>
+#include "atom-context.h"
+#include "atom-moov-xml.h"
+#include "fourcc.h"
+#include "descriptors.h"
+#include "atoms.h"
+
+#define MAX_TRACKS 50
+
+GST_DEBUG_CATEGORY_EXTERN (gst_qtmux_atom_ctx_debug);
+#define GST_CAT_DEFAULT gst_qtmux_atom_ctx_debug
+
+//#define KEEP_TMP_FILES 1
+
+typedef struct _MoovTrakOffset
+{
+	guint64 trak_offset;
+	guint64 offset_delta;
+} MoovTrakOffset;
+
+#define METADATA_DATA_FLAG 0x0
+#define METADATA_TEXT_FLAG 0x1
+
+typedef enum {
+	TAG_UNKNOWN = 0,
+	TAG_DATA,
+	TAG_STRING,
+	TAG_UINT32,
+	TAG_3GP_STR,
+	TAG_3GP_STR_INT,
+	TAG_3GP_UINT,
+	TAG_3GP_LOCATION,
+	TAG_3GP_KEYWORD,
+	TAG_BLOB,
+} MoovTagType;
+
+typedef struct _MoovTag
+{
+	MoovTagType type;
+} MoovTag;
+
+typedef struct _MoovTagData
+{
+	MoovTagType type;
+	guint32 fourcc;
+	guint32 flags;
+	guint8 * data;
+	guint size;
+} MoovTagData;
+#define MOOV_TAG_DATA(tag) ((MoovTagData*)tag)
+
+typedef struct _MoovTagString
+{
+	MoovTagType type;
+	guint32 fourcc;
+	gchar * value;
+} MoovTagString;
+#define MOOV_TAG_STRING(tag) ((MoovTagString*)tag)
+
+typedef struct _MoovTagUint32
+{
+	MoovTagType type;
+	guint32 fourcc;
+	guint32 flags;
+	guint32 value;
+} MoovTagUint32;
+#define MOOV_TAG_UINT32(tag) ((MoovTagUint32*)tag)
+
+typedef struct _MoovTag3GPString
+{
+	MoovTagType type;
+	guint32 fourcc;
+	gchar * value;
+} MoovTag3GPString;
+#define MOOV_TAG_3GP_STRING(tag) ((MoovTag3GPString*)tag)
+
+typedef struct _MoovTag3GPStringInt
+{
+	MoovTagType type;
+	guint32 fourcc;
+	gchar * value;
+	gint16 ivalue;
+} MoovTag3GPStringInt;
+#define MOOV_TAG_3GP_STRING_INT(tag) ((MoovTag3GPStringInt*)tag)
+
+typedef struct _MoovTag3GPUint
+{
+	MoovTagType type;
+	guint32 fourcc;
+	guint16 value;
+} MoovTag3GPUint;
+#define MOOV_TAG_3GP_UINT(tag) ((MoovTag3GPUint*)tag)
+
+typedef struct _MoovTag3GPLocation
+{
+	MoovTagType type;
+	guint32 fourcc;
+	gchar * location;
+	gdouble latitude;
+	gdouble longitude;
+	gdouble altitude;
+} MoovTag3GPLocation;
+#define MOOV_TAG_3GP_LOCATION(tag) ((MoovTag3GPLocation*)tag)
+
+typedef struct _MoovTag3GPKeyword
+{
+	MoovTagType type;
+	gchar * language;
+	gchar * keyword;
+	guint32 fourcc;
+} MoovTag3GPKeyword;
+#define MOOV_TAG_3GP_KEYWORD(tag) ((MoovTag3GPKeyword*)tag)
+
+typedef struct _MoovTagBlob
+{
+	MoovTagType type;
+	guint8 * data;
+	guint size;
+} MoovTagBlob;
+#define MOOV_TAG_BLOB(tag) ((MoovTagBlob*)tag)
+
+
+typedef struct _MoovTrak
+{
+	guint trak_id;
+	guint32 fourcc;
+	guint32 sub_fourcc;
+	gboolean is_video;
+
+	FILE * fd_stts;
+	gchar * filename_stts;
+	guint32 stts_entry_count;
+	FILE * fd_stsc;
+	gchar * filename_stsc;
+	guint32 stsc_entry_count;
+	FILE * fd_stsz;
+	gchar * filename_stsz;
+	guint32 stsz_entry_count;
+	FILE * fd_stco;
+	gchar * filename_stco;
+	guint32 stco_entry_count;
+	FILE * fd_stss;
+	gchar * filename_stss;
+	guint32 stss_entry_count;
+	FILE * fd_ctts;
+	gchar * filename_ctts;
+	guint32 ctts_entry_count;
+
+	/** Trak Configuration **/
+	guint32  timescale;
+	guint32  fixed_sample_size;  /* 0 size means variable size */
+	guint16  data_ref_index;
+	gchar *  component_name;     /* HDLR - media handler used to create track */
+	guint8 * codec_data;
+	guint    codec_data_size;
+
+	/** Atom Config **/
+	guint8 tkhd_version;
+	guint8 mdhd_version;
+	guint64 tkhd_duration;
+
+	/** Trak Totals Tracking **/
+	guint32 sample_count;
+	guint32 chunk_count;
+	guint64 total_size;
+	guint64 stts_duration;
+	guint64 edts_duration;
+
+	/** Trak Offsets **/
+	guint64 start_ts;
+	GSList * offsets;
+	guint64 offsets_duration;
+
+	/** STBL Last Entry Tracking **/
+	/* STSC */
+	guint32 last_chunk_samples;
+	/* CTTS */
+	guint32 ctts_last_offset;
+	guint32 ctts_sample_count;
+	/* STTS */
+	guint64 stts_last_duration;
+	guint64 stts_last_duration_nsamples;
+} MoovTrak;
+
+typedef struct _MoovTrakAudio
+{
+	MoovTrak trak;
+	/* AudioSampleEntry Values */
+	guint16 version;
+	guint16 compression_id;
+	guint16 channels;
+	guint16 sample_size;
+	guint32 bytes_per_packet;
+	guint32 samples_per_packet;
+	guint32 bytes_per_sample;
+	guint32 bytes_per_frame;
+	AtomContextAudioExt audio_ext;
+} MoovTrakAudio;
+
+typedef struct _MoovTrakVideo
+{
+	MoovTrak trak;
+	guint par_n;
+	guint par_d;
+	guint width;
+	guint height;
+	guint depth;
+	guint color_table_id;
+	guint frame_count;
+	AtomContextVisualExt visual_ext;
+} MoovTrakVideo;
+
+typedef struct _MoovDat
+{
+	FILE *           fd;
+	gchar *          filename;
+	guint            version;
+	AtomsTreeFlavor  flavor;
+	gboolean         largefile;
+	guint64          chunk_offset;
+	AtomMoovProcPingCB ping_cb;
+	gpointer         ping_userdata;
+	GstClockTime     last_ping;
+	gboolean         elst_64bit;
+
+	/** Atom Config **/
+	guint64          creation_time;
+	guint64          modification_time;
+	guint            timescale;
+	guint64          mvhd_duration;
+	guint8           mvhd_version;
+
+	/* Tags */
+	GSList *         taglist;
+	GSList *         keywords;
+
+	gint             track_count;
+	MoovTrak *       tracks[MAX_TRACKS];
+} MoovDat;
+
+#define MOOV_TRAK(trak)       ((MoovTrak*)trak)
+#define MOOV_TRAK_AUDIO(trak) ((MoovTrakAudio*)trak)
+#define MOOV_TRAK_VIDEO(trak) ((MoovTrakVideo*)trak)
+
+#define NS2MEDIA(time_units, media_rate) \
+	gst_util_uint64_scale(time_units, media_rate, GST_SECOND)
+#define MEDIA2MOVIE(time_units, movie_rate, media_rate) \
+	gst_util_uint64_scale(time_units, movie_rate, media_rate)
+#define NS2MOVIE(time_units, movie_rate) \
+	gst_util_uint64_scale(time_units, movie_rate, GST_SECOND)
+#define MOVIE2NS(time_units, movie_rate) \
+	gst_util_uint64_scale(time_units, GST_SECOND, movie_rate)
+#define MEDIA2NS(time_units, media_rate) \
+	gst_util_uint64_scale(time_units, GST_SECOND, media_rate)
+
+
+
+
+/** FWD DECLS **/
+static gboolean atom_xml_moov_send(MoovDat * dat, AtomMoovSendDataCB send_cb, gpointer user_data);
+
+/** Helpers **/
+
+static guint64 atom_moov_get_start_ts(MoovDat * dat)
+{
+	guint64 ret = 0;
+	gint i;
+
+	for(i=0;i<MAX_TRACKS;i++) {
+		MoovTrak * trak = dat->tracks[i];
+		if(trak == NULL)
+			continue;
+		if(ret == 0) {
+			ret = trak->start_ts;
+		}
+		else {
+			if(trak->start_ts < ret)
+				ret = trak->start_ts;
+		}
+	}
+	return ret;
+}
+
+static FILE * atom_create_trak_tmp_file(gint trak_id, gint rand_num, const gchar * type, gchar ** filename)
+{
+	gchar * tmp, *path;
+	FILE * ret = NULL;
+
+	g_return_val_if_fail(type != NULL, NULL);
+	g_return_val_if_fail(filename != NULL, NULL);
+
+	tmp = g_strdup_printf("qtmux-atom-trak-%d-%s-%d.dat", trak_id, type, rand_num);
+	path = g_build_filename(g_get_tmp_dir(), tmp, NULL);
+
+	if(!(ret = fopen(path, "w"))) {
+		GST_ERROR("Failed to open '%s'. %s", path, strerror(errno));
+		g_free(path);
+	}
+	else
+		*filename = path;
+
+	g_free(tmp);
+		
+	return ret;
+}
+
+#define MOOV_TRACK_TMP_FILE_CREATE(type, trak_id, rand_num, err_label)				\
+	if(!(trak->fd_ ## type = atom_create_trak_tmp_file(trak_id, rand_num, #type, &trak->filename_ ## type))) { \
+		GST_ERROR("Failed to create tmp stbl entry file for %s", #type); \
+		goto err_label;													\
+	}
+
+static gboolean atom_create_trak_tmp_files(MoovTrak * trak)
+{
+	gint rand_num;
+
+	g_return_val_if_fail(trak != NULL, FALSE);
+
+	rand_num = g_random_int();
+	MOOV_TRACK_TMP_FILE_CREATE(stts, trak->trak_id, rand_num, err);
+	MOOV_TRACK_TMP_FILE_CREATE(stsc, trak->trak_id, rand_num, err);
+	MOOV_TRACK_TMP_FILE_CREATE(stsz, trak->trak_id, rand_num, err);
+	MOOV_TRACK_TMP_FILE_CREATE(stco, trak->trak_id, rand_num, err);
+	MOOV_TRACK_TMP_FILE_CREATE(stss, trak->trak_id, rand_num, err);
+	MOOV_TRACK_TMP_FILE_CREATE(ctts, trak->trak_id, rand_num, err);
+	return TRUE;
+ err:
+	return FALSE;
+}
+
+#define MOOV_TRACK_TMP_FILE_CLOSE(trak, type)	  \
+	if(trak->fd_ ## type) {						  \
+		fclose(trak->fd_ ## type);				  \
+		trak->fd_ ## type = NULL;				  \
+	}
+
+static void atom_close_trak_tmp_files(MoovTrak * trak)
+{
+	g_return_if_fail(trak != NULL);
+
+	MOOV_TRACK_TMP_FILE_CLOSE(trak, stts);
+	MOOV_TRACK_TMP_FILE_CLOSE(trak, stsc);
+	MOOV_TRACK_TMP_FILE_CLOSE(trak, stsz);
+	MOOV_TRACK_TMP_FILE_CLOSE(trak, stco);
+	MOOV_TRACK_TMP_FILE_CLOSE(trak, stss);
+	MOOV_TRACK_TMP_FILE_CLOSE(trak, ctts);
+}
+
+static MoovDat * atom_create_moov(const gchar * xmlfile, guint64 chunk_offset, gboolean largefile)
+{
+	MoovDat * dat;
+	FILE * fd;
+
+	g_return_val_if_fail(xmlfile != NULL, NULL);
+
+	if(!(fd = fopen(xmlfile, "r"))) {
+		GST_ERROR("Failed to open '%s'. %s", xmlfile, strerror(errno));
+		return NULL;
+	}
+
+	dat = g_new0(MoovDat, 1);
+	dat->filename = g_strdup(xmlfile);
+	dat->fd = fd;
+	dat->chunk_offset = chunk_offset;
+	dat->largefile = largefile;
+
+	return dat;
+}
+
+static void atom_moov_chunk_process(MoovDat * dat, guint32 trak_id, guint32 nsamples, guint32 delta, guint32 size,
+									guint64 chunk_offset, gboolean sync, gboolean do_pts, gint64 pts_offset)
+{
+	MoovTrak * trak;
+
+	g_return_if_fail(dat != NULL);
+
+	GST_LOG("Track: %u. chunk: %llu", trak_id, chunk_offset);
+
+	if(trak_id > MAX_TRACKS || !(trak = dat->tracks[trak_id])) {
+		GST_ERROR("Track '%d' does not exist", trak_id);
+		return;
+	}
+	
+	/* STTS ENTRY */
+	if(trak->stts_last_duration == delta) {
+		trak->stts_last_duration_nsamples += nsamples;
+	}
+	else {
+		if(trak->stts_last_duration_nsamples > 0) {
+			guint8 stts_entry[8] = { 0, };
+			GST_WRITE_UINT32_BE (stts_entry, trak->stts_last_duration_nsamples);
+			GST_WRITE_UINT32_BE (stts_entry+4, trak->stts_last_duration);
+			fwrite(&stts_entry, 1, sizeof(stts_entry), trak->fd_stts);
+			trak->stts_entry_count += 1;
+		}
+		trak->stts_last_duration = delta;
+		trak->stts_last_duration_nsamples = nsamples;
+	}
+	trak->stts_duration += (nsamples * delta);
+
+	/* STSZ ENTRY */
+	if(trak->fixed_sample_size == 0) {
+		guint8 * stsz_entries = g_new0(guint8, nsamples);
+		gint i;
+		for(i=0;i<nsamples;i++)
+			GST_WRITE_UINT32_BE (stsz_entries+(i*4), size);
+		fwrite(stsz_entries, 1, sizeof(guint32)*nsamples, trak->fd_stsz);
+		g_free(stsz_entries);
+		trak->stsz_entry_count += nsamples;
+	}
+
+	/* STCO / CO64 ENTRY */
+	if(dat->largefile) {
+		guint8 co64_entry[8] = { 0, };
+		GST_WRITE_UINT64_BE (co64_entry, chunk_offset + dat->chunk_offset);
+		fwrite(&co64_entry, 1, sizeof(co64_entry), trak->fd_stco);
+	}
+	else {
+		guint8 stco_entry[4] = { 0, };
+		GST_WRITE_UINT32_BE (stco_entry, (guint32)chunk_offset + dat->chunk_offset);
+		fwrite(&stco_entry, 1, sizeof(stco_entry), trak->fd_stco);
+	}
+	trak->stco_entry_count += 1;
+
+	/* STSC ENTRY */
+	if(trak->last_chunk_samples != nsamples) {
+		guint8 stsc_entry[12] = { 0, };
+		GST_WRITE_UINT32_BE (stsc_entry, trak->chunk_count + 1);
+		GST_WRITE_UINT32_BE (stsc_entry+4, nsamples);
+		GST_WRITE_UINT32_BE (stsc_entry+8, trak->data_ref_index);
+		fwrite(&stsc_entry, 1, sizeof(stsc_entry), trak->fd_stsc);
+		trak->stsc_entry_count += 1;
+	}
+
+	/* STSS ENTRY */
+	if(sync) {
+		guint8 stss_entry[4] = { 0, };
+		/* NOTE: This is a problem if there is more than 1 sample per chunk.
+		 * Currently not the case.
+		 */
+		GST_WRITE_UINT32_BE (stss_entry, trak->sample_count + nsamples);
+		fwrite(&stss_entry, 1, sizeof(stss_entry), trak->fd_stss);
+		trak->stss_entry_count += 1;
+	}
+
+	/* CTTS ENTRY */
+	if(do_pts) {
+		if(trak->ctts_last_offset != pts_offset) {
+			/* Write out previous entry */
+			if(trak->ctts_sample_count > 0) {
+				guint8 ctts_entry[8] = { 0, };
+				GST_WRITE_UINT32_BE (ctts_entry, trak->ctts_sample_count);
+				GST_WRITE_UINT32_BE (ctts_entry+4, trak->ctts_last_offset);
+				fwrite(&ctts_entry, 1, sizeof(ctts_entry), trak->fd_ctts);
+				trak->ctts_entry_count += 1;
+			}
+			/* Track new entry */
+			trak->ctts_sample_count = nsamples;
+			trak->ctts_last_offset = pts_offset;
+		}
+		else {
+			trak->ctts_sample_count += nsamples;
+		}
+	}
+
+	/* Totals housekeeping */
+	trak->sample_count += nsamples;
+	trak->chunk_count += 1;
+	trak->total_size += size;
+	trak->last_chunk_samples = nsamples;
+}
+
+static void atom_moov_start_ts_process(MoovDat * dat, guint32 trak_id, guint64 start_ts)
+{
+	MoovTrak * trak;
+
+	g_return_if_fail(dat != NULL);
+
+	if(trak_id > MAX_TRACKS || !(trak = dat->tracks[trak_id])) {
+		GST_ERROR("Track '%d' does not exist", trak_id);
+		return;
+	}
+
+	/* If this is the first start ts we get.. it is our
+	 * track start timestamp, otherwise its an offset marker
+	 */
+	if(trak->start_ts == 0) {
+		GST_LOG("Track: %u. start ts: %llu", trak_id, start_ts);
+		trak->start_ts = start_ts;
+	}
+	else {
+		guint64 total_dur, since_start;
+		MoovTrakOffset * offset;
+
+		total_dur = trak->stts_duration + trak->offsets_duration;
+		since_start = start_ts - trak->start_ts;
+		GST_LOG("Since Start NS: %llu", since_start);
+		since_start = NS2MEDIA(since_start, trak->timescale);
+		GST_LOG("Since Start MEDIA TIME: %llu", since_start);
+
+		if(since_start > total_dur) {
+			offset = g_new0(MoovTrakOffset, 1);
+			offset->trak_offset = trak->stts_duration;
+			offset->offset_delta = since_start - total_dur;
+			trak->offsets = g_slist_append(trak->offsets, offset);
+			trak->offsets_duration += offset->offset_delta;
+			GST_LOG("Track: %u. Offset delta: %llu (ns) at track offset: %llu (ns)",
+					trak_id, MEDIA2NS(offset->offset_delta, trak->timescale),
+					MEDIA2NS(trak->stts_duration, trak->timescale));
+		}
+		else {
+			GST_WARNING("Failed to add offset because time since start is less "
+						"than samples duration plus existing offsets");
+		}
+	}
+}
+
+static void atom_trak_finalize(MoovDat * dat, MoovTrak * trak)
+{
+	g_return_if_fail(trak != NULL);
+
+	/* CTTS ENTRY - FINALIZE */
+	if(trak->ctts_sample_count > 0) {
+		guint8 ctts_entry[8] = { 0, };
+		GST_WRITE_UINT32_BE (ctts_entry, trak->ctts_sample_count);
+		GST_WRITE_UINT32_BE (ctts_entry+4, trak->ctts_last_offset);
+		fwrite(&ctts_entry, 1, sizeof(ctts_entry), trak->fd_ctts);
+		trak->ctts_entry_count += 1;
+	}
+
+	/* STTS ENTRY - FINALIZE */
+	if(trak->stts_last_duration_nsamples > 0) {
+		guint8 stts_entry[8] = { 0, };
+		GST_WRITE_UINT32_BE (stts_entry, trak->stts_last_duration_nsamples);
+		GST_WRITE_UINT32_BE (stts_entry+4, trak->stts_last_duration);
+		fwrite(&stts_entry, 1, sizeof(stts_entry), trak->fd_stts);
+		trak->stts_entry_count += 1;
+	}
+
+	/* Update trak duration */
+	trak->tkhd_duration =
+		MEDIA2MOVIE(trak->stts_duration, dat->timescale, trak->timescale);
+
+	GST_INFO("Calculated trak[%d] duration: %llu. "
+			 "Scaled Dur: %llu Mov Timescale: %u Trak Timescale: %u",
+			 trak->trak_id, trak->tkhd_duration, trak->stts_duration, dat->timescale, trak->timescale);
+
+	/* Close stbl tmp files */
+	atom_close_trak_tmp_files(trak);
+}
+
+static void atom_moov_finalize(MoovDat * dat)
+{
+	gint i;
+	guint64 duration = 0;
+
+	g_return_if_fail(dat != NULL);
+
+	/* Finalize Tracks */
+	for(i=0;i<MAX_TRACKS;i++) {
+		MoovTrak * trak = dat->tracks[i];
+		if(trak == NULL)
+			continue;
+
+		atom_trak_finalize(dat, trak);
+
+		if(trak->tkhd_duration > duration)
+			duration = trak->tkhd_duration;
+	}
+
+	/* We update mvhd_duration after first run of atom_xml_build_moov
+	 * at which point we'll have edit list durations.. if any
+	 */
+	dat->mvhd_duration = duration;
+}
+
+
+static void atom_trak_free(MoovTrak * trak)
+{
+	if(!trak)
+		return;
+	atom_close_trak_tmp_files(trak);
+	/* TOOD: Re-enable after dev */
+#ifndef KEEP_TMP_FILES
+	g_unlink(trak->filename_stts);
+	g_unlink(trak->filename_stsc);
+	g_unlink(trak->filename_stsz);
+	g_unlink(trak->filename_stco);
+	g_unlink(trak->filename_stss);
+	g_unlink(trak->filename_ctts);
+#endif
+	g_free(trak->filename_stts);
+	g_free(trak->filename_stsc);
+	g_free(trak->filename_stsz);
+	g_free(trak->filename_stco);
+	g_free(trak->filename_stss);
+	g_free(trak->filename_ctts);
+
+	g_slist_foreach(trak->offsets, (GFunc)g_free, NULL);
+	g_slist_free(trak->offsets);
+
+	g_free(trak);
+}
+
+static void atom_moov_tag_free(MoovTag * tag)
+{
+	if(!tag)
+		return;
+	switch(tag->type) {
+	case TAG_DATA:
+		g_free(MOOV_TAG_DATA(tag)->data);
+		break;
+	case TAG_STRING:
+		g_free(MOOV_TAG_STRING(tag)->value);
+		break;
+	case TAG_3GP_STR:
+		g_free(MOOV_TAG_3GP_STRING(tag)->value);
+		break;
+	case TAG_3GP_STR_INT:
+		g_free(MOOV_TAG_3GP_STRING_INT(tag)->value);
+		break;
+	case TAG_3GP_LOCATION:
+		g_free(MOOV_TAG_3GP_LOCATION(tag)->location);
+		break;
+	case TAG_3GP_KEYWORD:
+		g_free(MOOV_TAG_3GP_KEYWORD(tag)->language);
+		g_free(MOOV_TAG_3GP_KEYWORD(tag)->keyword);
+		break;
+	case TAG_BLOB:
+		g_free(MOOV_TAG_BLOB(tag)->data);
+		break;
+	case TAG_UNKNOWN:
+	case TAG_UINT32:
+	case TAG_3GP_UINT:
+		break;
+	}
+	g_free(tag);
+}
+
+#define CASE(x) case x: return #x
+static const gchar * tagtype2str(MoovTagType type)
+{
+	switch(type) {
+		CASE(TAG_UNKNOWN);
+		CASE(TAG_DATA);
+		CASE(TAG_STRING);
+		CASE(TAG_UINT32);
+		CASE(TAG_3GP_STR);
+		CASE(TAG_3GP_STR_INT);
+		CASE(TAG_3GP_UINT);
+		CASE(TAG_3GP_LOCATION);
+		CASE(TAG_3GP_KEYWORD);
+		CASE(TAG_BLOB);
+	}
+	return "";
+}
+#undef CASE
+
+static void atom_moov_dat_free(MoovDat * dat, gboolean keep_moov_file)
+{
+	gint i;
+	if(!dat)
+		return;
+	for(i=0;i<MAX_TRACKS;i++)
+		atom_trak_free(dat->tracks[i]);
+	if(dat->fd)
+		fclose(dat->fd);
+	if(!keep_moov_file)
+		g_unlink(dat->filename);
+	g_free(dat->filename);
+	g_slist_foreach(dat->taglist, (GFunc)atom_moov_tag_free, NULL);
+	g_slist_foreach(dat->keywords, (GFunc)atom_moov_tag_free, NULL);
+	g_free(dat);
+}
+
+
+/*** XML Parse Code ***/
+
+static gboolean xml_get_value_pair(const char *** _attr, gchar ** name, gchar ** value)
+{
+	gchar *** attr = (gchar***)_attr;
+	if(!attr || !*attr || !name || !value)
+		return FALSE;
+	if((*attr)[0] && (*attr)[1]) {
+		*name = (*attr)[0];
+		*value = (*attr)[1];
+		*attr += 2;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_UINT16(gchar * value, guint16 * var, gint * scans)
+{
+	if(sscanf(value, "%hu", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_INT16(gchar * value, gint16 * var, gint * scans)
+{
+	if(sscanf(value, "%hd", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_UINT(gchar * value, guint * var, gint * scans)
+{
+	if(sscanf(value, "%u", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_UINT64(gchar * value, guint64 * var, gint * scans)
+{
+	if(sscanf(value, "%llu", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_INT64(gchar * value, gint64 * var, gint * scans)
+{
+	if(sscanf(value, "%lld", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_BOOL(gchar * value, gboolean * var, gint * scans)
+{
+	if(sscanf(value, "%d", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_DOUBLE(gchar * value, gdouble * var, gint * scans)
+{
+	if(sscanf(value, "%lf", var) == 1) {
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_STR(gchar * value, gchar ** ret, gint * scans)
+{
+	if(value) {
+		*ret = g_strdup(value);
+		if(scans)
+			*scans += 1;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean SCAN_STR_BASE64(gchar * value, guint8 ** data, gint * scans)
+{
+	if(value) {
+		if((*data = atom_moov_base64_decode(value, NULL))) {
+			if(scans)
+				*scans += 1;
+			return TRUE;
+		}
+	}
+	return FALSE;	
+}
+
+#define RET_IF_MATCH(value, tag) if(strcmp(value, #tag)==0) return tag;
+
+static guint TAG_STR2TYPE(const gchar * value)
+{
+	guint ret = TAG_UNKNOWN;
+
+	g_return_val_if_fail(value != NULL, ret);
+
+	RET_IF_MATCH(value, TAG_DATA);
+	RET_IF_MATCH(value, TAG_STRING);
+	RET_IF_MATCH(value, TAG_UINT32);
+	RET_IF_MATCH(value, TAG_3GP_STR);
+	RET_IF_MATCH(value, TAG_3GP_STR_INT);
+	RET_IF_MATCH(value, TAG_3GP_UINT);
+	RET_IF_MATCH(value, TAG_3GP_LOCATION);
+	RET_IF_MATCH(value, TAG_3GP_KEYWORD);
+	RET_IF_MATCH(value, TAG_BLOB);
+
+	GST_ERROR("Unknown tag: %s", value); 
+
+	return TAG_UNKNOWN;
+}
+
+#define CASE_TAG(tag_type, scans, arg_count)							\
+	case tag_type:														\
+	if(scans != arg_count) {											\
+		GST_ERROR("Expected %d tag values for '%s'. Got %d", arg_count, #tag_type, scans);\
+		break;															\
+	}
+
+static void xml_start_event(void * userdata, const char * tag, const char ** attr)
+{
+	MoovDat * dat = (MoovDat*)userdata;
+	gchar *name=NULL, *value=NULL;
+	gint scans = 0;
+
+	g_return_if_fail(tag != NULL);
+	g_return_if_fail(dat != NULL);
+
+	/* Send ping to indicate we're still processing */
+	if(dat->ping_cb) {
+		/* Send ping every 250ms */
+		if(!GST_CLOCK_TIME_IS_VALID(dat->last_ping) ||
+		   (gst_util_get_timestamp() - dat->last_ping) >= (GST_SECOND / 4)) {
+			dat->ping_cb(dat->ping_userdata);
+			dat->last_ping = gst_util_get_timestamp();
+		}
+	}
+
+	/* Track Chunk Tag */
+	if(g_ascii_strcasecmp(tag, "TC") == 0) {
+		guint32 trak_id=0, nsamples=0, delta=0, size=0;
+		guint64 chunk_offset=0;
+		gint64 pts_offset=0;
+		gboolean sync=FALSE, do_pts=FALSE;
+
+		while(xml_get_value_pair(&attr, &name, &value)) {
+			if(g_ascii_strcasecmp(name, "I") == 0) {
+				SCAN_STR_UINT(value, &trak_id, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "N") == 0) {
+				SCAN_STR_UINT(value, &nsamples, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "D") == 0) {
+				SCAN_STR_UINT(value, &delta, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "S") == 0) {
+				SCAN_STR_UINT(value, &size, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "C") == 0) {
+				SCAN_STR_UINT64(value, &chunk_offset, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "Y") == 0) {
+				SCAN_STR_BOOL(value, &sync, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "P") == 0) {
+				SCAN_STR_BOOL(value, &do_pts, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "O") == 0) {
+				SCAN_STR_INT64(value, &pts_offset, &scans);
+			}
+		}
+		if(scans == 8)
+			atom_moov_chunk_process(dat, trak_id, nsamples, delta, size, chunk_offset, sync, do_pts, pts_offset);
+		else
+			GST_ERROR("Not all expected track chunk values were parsed");
+	}
+	/* Track Start Tag */
+	else if(g_ascii_strcasecmp(tag, "TS") == 0) {
+		guint32 trak_id=0;
+		guint64 start_ts=0;
+
+		while(xml_get_value_pair(&attr, &name, &value)) {
+			if(g_ascii_strcasecmp(name, "I") == 0) {
+				SCAN_STR_UINT(value, &trak_id, &scans);
+			}
+			else if(g_ascii_strcasecmp(name, "S") == 0) {
+				SCAN_STR_UINT64(value, &start_ts, &scans);
+			}
+		}
+		if(scans == 2)
+			atom_moov_start_ts_process(dat, trak_id, start_ts);
+		else
+			GST_ERROR("Not all expected track start values were parsed");
+	}
+	else if(g_ascii_strcasecmp(tag, "MOOV") == 0) {
+		while(xml_get_value_pair(&attr, &name, &value)) {
+			if(g_ascii_strcasecmp(name, "VERSION") == 0)
+				SCAN_STR_UINT(value, &dat->version, &scans);
+			else if(g_ascii_strcasecmp(name, "FLAVOR") == 0)
+				SCAN_STR_UINT(value, &dat->flavor, &scans);
+			else if(g_ascii_strcasecmp(name, "TIMESCALE") == 0)
+				SCAN_STR_UINT(value, &dat->timescale, &scans);
+		}
+		if(scans == 3) {
+			GST_INFO("MOOV PARSE SUCCESS - version: %u flavor: %u timescale: %u",
+							 dat->version, dat->flavor, dat->timescale);
+		}
+		else {
+			GST_ERROR("Not all expected moov values were parsed");
+		}
+	}
+	else if(g_ascii_strcasecmp(tag, "AT") == 0) {
+		MoovTrakAudio * atrak = g_new0(MoovTrakAudio, 1);
+
+		MOOV_TRAK(atrak)->is_video = FALSE;
+
+		while(xml_get_value_pair(&attr, &name, &value)) {
+			if(g_ascii_strcasecmp(name, "IX") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(atrak)->trak_id, &scans);
+			else if(g_ascii_strcasecmp(name, "TS") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(atrak)->timescale, &scans);
+			else if(g_ascii_strcasecmp(name, "RI") == 0)
+				SCAN_STR_UINT16(value, &MOOV_TRAK(atrak)->data_ref_index, &scans);
+			else if(g_ascii_strcasecmp(name, "FCC") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(atrak)->fourcc, &scans);
+			else if(g_ascii_strcasecmp(name, "VR") == 0)
+				SCAN_STR_UINT16(value, &atrak->version, &scans);
+			else if(g_ascii_strcasecmp(name, "CI") == 0)
+				SCAN_STR_UINT16(value, &atrak->compression_id, &scans);
+			else if(g_ascii_strcasecmp(name, "SS") == 0)
+				SCAN_STR_UINT16(value, &atrak->sample_size, &scans);
+			else if(g_ascii_strcasecmp(name, "CH") == 0)
+				SCAN_STR_UINT16(value, &atrak->channels, &scans);
+			else if(g_ascii_strcasecmp(name, "SPP") == 0)
+				SCAN_STR_UINT(value, &atrak->samples_per_packet, &scans);
+			else if(g_ascii_strcasecmp(name, "BPS") == 0)
+				SCAN_STR_UINT(value, &atrak->bytes_per_sample, &scans);
+			else if(g_ascii_strcasecmp(name, "BPP") == 0)
+				SCAN_STR_UINT(value, &atrak->bytes_per_packet, &scans);
+			else if(g_ascii_strcasecmp(name, "BPF") == 0)
+				SCAN_STR_UINT(value, &atrak->bytes_per_frame, &scans);
+			else if(g_ascii_strcasecmp(name, "FSS") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(atrak)->fixed_sample_size, &scans);
+			else if(g_ascii_strcasecmp(name, "AEXT") == 0)
+				SCAN_STR_UINT(value, &atrak->audio_ext, &scans);
+			else if(g_ascii_strcasecmp(name, "CDAT") == 0)
+				SCAN_STR_BASE64(value, &MOOV_TRAK(atrak)->codec_data, &scans);
+			else if(g_ascii_strcasecmp(name, "CDATSIZE") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(atrak)->codec_data_size, &scans);
+		}
+		if(scans != 16) {
+			GST_ERROR("Not all expected audio track values were parsed");
+			goto at_free;
+		}
+		if(MOOV_TRAK(atrak)->trak_id >= MAX_TRACKS) {
+			GST_ERROR("Trak index %d, is out of bounds", MOOV_TRAK(atrak)->trak_id);
+			goto at_free;
+		}
+		if(dat->tracks[MOOV_TRAK(atrak)->trak_id] != NULL) {
+			GST_LOG("Already have audio trak %u", MOOV_TRAK(atrak)->trak_id);
+			goto at_done;
+		}
+		else {
+			GST_INFO("AT PARSE SUCCESS - TRACK INDEX: %d", MOOV_TRAK(atrak)->trak_id);
+			if(!atom_create_trak_tmp_files(MOOV_TRAK(atrak)))
+				goto at_free;
+			dat->tracks[MOOV_TRAK(atrak)->trak_id] = MOOV_TRAK(atrak);
+			dat->track_count += 1;
+			goto at_done;
+		}
+
+	at_free:
+		atom_trak_free(MOOV_TRAK(atrak));
+	at_done:;
+	}
+	else if(g_ascii_strcasecmp(tag, "VT") == 0) {
+		MoovTrakVideo * vtrak = g_new0(MoovTrakVideo, 1);
+
+		MOOV_TRAK(vtrak)->is_video = TRUE;
+		MOOV_TRAK(vtrak)->fixed_sample_size = 0;
+
+		while(xml_get_value_pair(&attr, &name, &value)) {
+			if(g_ascii_strcasecmp(name, "IX") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(vtrak)->trak_id, &scans);
+			else if(g_ascii_strcasecmp(name, "TS") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(vtrak)->timescale, &scans);
+			else if(g_ascii_strcasecmp(name, "RI") == 0)
+				SCAN_STR_UINT16(value, &MOOV_TRAK(vtrak)->data_ref_index, &scans);
+			else if(g_ascii_strcasecmp(name, "FCC") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(vtrak)->fourcc, &scans);
+			else if(g_ascii_strcasecmp(name, "SFCC") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(vtrak)->sub_fourcc, &scans);
+			else if(g_ascii_strcasecmp(name, "FN") == 0)
+				SCAN_STR_UINT(value, &vtrak->par_n, &scans);
+			else if(g_ascii_strcasecmp(name, "FD") == 0)
+				SCAN_STR_UINT(value, &vtrak->par_n, &scans);
+			else if(g_ascii_strcasecmp(name, "W") == 0)
+				SCAN_STR_UINT(value, &vtrak->width, &scans);
+			else if(g_ascii_strcasecmp(name, "H") == 0)
+				SCAN_STR_UINT(value, &vtrak->height, &scans);
+			else if(g_ascii_strcasecmp(name, "DP") == 0)
+				SCAN_STR_UINT(value, &vtrak->depth, &scans);
+			else if(g_ascii_strcasecmp(name, "CTID") == 0)
+				SCAN_STR_UINT(value, &vtrak->color_table_id, &scans);
+			else if(g_ascii_strcasecmp(name, "FC") == 0)
+				SCAN_STR_UINT(value, &vtrak->frame_count, &scans);
+			else if(g_ascii_strcasecmp(name, "VEXT") == 0)
+				SCAN_STR_UINT(value, &vtrak->visual_ext, &scans);
+			else if(g_ascii_strcasecmp(name, "CDAT") == 0)
+				SCAN_STR_BASE64(value, &MOOV_TRAK(vtrak)->codec_data, &scans);
+			else if(g_ascii_strcasecmp(name, "CDATSIZE") == 0)
+				SCAN_STR_UINT(value, &MOOV_TRAK(vtrak)->codec_data_size, &scans);
+		}
+		if(scans != 15) {
+			GST_ERROR("Not all expected video track values were parsed");
+			goto vt_free;
+		}
+		if(MOOV_TRAK(vtrak)->trak_id >= MAX_TRACKS) {
+			GST_ERROR("Video track index %d, is out of bounds", MOOV_TRAK(vtrak)->trak_id);
+			goto vt_free;
+		}
+		if(dat->tracks[MOOV_TRAK(vtrak)->trak_id] != NULL) {
+			GST_LOG("Already have video trak %u", MOOV_TRAK(vtrak)->trak_id);
+			goto vt_free;
+		}
+		else {
+			GST_INFO("VT PARSE SUCCESS - TRACK INDEX: %d", MOOV_TRAK(vtrak)->trak_id);
+			if(!atom_create_trak_tmp_files(MOOV_TRAK(vtrak)))
+				goto vt_free;
+			dat->tracks[MOOV_TRAK(vtrak)->trak_id] = MOOV_TRAK(vtrak);
+			dat->track_count += 1;
+			goto vt_done;
+		}
+	vt_free:
+		atom_trak_free(MOOV_TRAK(vtrak));
+	vt_done:;
+	}
+	else if(g_ascii_strcasecmp(tag, "TAG") == 0) {
+		guint32 fourcc=0, flags=0, dat_size=0, uint32_value=0;
+		gchar * str_val=NULL, *str_loc=NULL,*str_lang=NULL,*str_kw=NULL;
+		gint16 int16_value=0;
+		guint16 uint16_value=0;
+		guint8 * data=NULL;
+		gdouble latitude=0, longitude=0, altitude=0;
+		MoovTagType tag_type = 0;
+		MoovTag * tag=NULL;
+
+		while(xml_get_value_pair(&attr, &name, &value)) {
+			if(g_ascii_strcasecmp(name, "TYPE") == 0)
+				tag_type = TAG_STR2TYPE(value);
+			else if(g_ascii_strcasecmp(name, "FOURCC") == 0)
+				SCAN_STR_UINT(value, &fourcc, &scans);
+			else if(g_ascii_strcasecmp(name, "FLAGS") == 0)
+				SCAN_STR_UINT(value, &flags, &scans);
+			else if(g_ascii_strcasecmp(name, "DATA") == 0)
+				SCAN_STR_BASE64(value, &data, &scans);
+			else if(g_ascii_strcasecmp(name, "SIZE") == 0)
+				SCAN_STR_UINT(value, &dat_size, &scans);
+			else if(g_ascii_strcasecmp(name, "STR_VAL") == 0)
+				SCAN_STR_STR(value, &str_val, &scans);
+			else if(g_ascii_strcasecmp(name, "UINT32_VAL") == 0)
+				SCAN_STR_UINT(value, &uint32_value, &scans);
+			else if(g_ascii_strcasecmp(name, "UINT16_VAL") == 0)
+				SCAN_STR_UINT16(value, &uint16_value, &scans);
+			else if(g_ascii_strcasecmp(name, "INT16_VAL") == 0)
+				SCAN_STR_INT16(value, &int16_value, &scans);
+			else if(g_ascii_strcasecmp(name, "LOC") == 0)
+				SCAN_STR_STR(value, &str_loc, &scans);
+			else if(g_ascii_strcasecmp(name, "LAT") == 0)
+				SCAN_STR_DOUBLE(value, &altitude, &scans);
+			else if(g_ascii_strcasecmp(name, "LONG") == 0)
+				SCAN_STR_DOUBLE(value, &longitude, &scans);
+			else if(g_ascii_strcasecmp(name, "ALT") == 0)
+				SCAN_STR_DOUBLE(value, &altitude, &scans);
+			else if(g_ascii_strcasecmp(name, "LANG") == 0)
+				SCAN_STR_STR(value, &str_lang, &scans);
+			else if(g_ascii_strcasecmp(name, "KEY") == 0)
+				SCAN_STR_STR(value, &str_kw, &scans);
+		}
+
+		switch(tag_type) {
+		case TAG_UNKNOWN:
+			break;
+		CASE_TAG(TAG_DATA, scans, 4);
+			tag = (MoovTag*)g_new0(MoovTagData, 1);
+			MOOV_TAG_DATA(tag)->type = tag_type;
+			MOOV_TAG_DATA(tag)->data = data; data = NULL;
+			MOOV_TAG_DATA(tag)->size = dat_size;
+			MOOV_TAG_DATA(tag)->fourcc = fourcc;
+			MOOV_TAG_DATA(tag)->flags = flags;
+			break;
+		CASE_TAG(TAG_STRING, scans, 2);
+			tag = (MoovTag*)g_new0(MoovTagString, 1);
+			MOOV_TAG_STRING(tag)->type = tag_type;
+			MOOV_TAG_STRING(tag)->fourcc = fourcc;
+			MOOV_TAG_STRING(tag)->value = str_val; str_val = NULL;
+			break;
+		CASE_TAG(TAG_UINT32, scans, 3);
+			tag = (MoovTag*)g_new0(MoovTagUint32, 1);
+			MOOV_TAG_UINT32(tag)->type = tag_type;
+			MOOV_TAG_UINT32(tag)->fourcc = fourcc;
+			MOOV_TAG_UINT32(tag)->flags = flags;
+			MOOV_TAG_UINT32(tag)->value = uint32_value;
+			break;
+		CASE_TAG(TAG_3GP_STR, scans, 2);
+			tag = (MoovTag*)g_new0(MoovTag3GPString, 1);
+			MOOV_TAG_3GP_STRING(tag)->type = tag_type;
+			MOOV_TAG_3GP_STRING(tag)->fourcc = fourcc;
+			MOOV_TAG_3GP_STRING(tag)->value = str_val; str_val = NULL;
+			break;
+		CASE_TAG(TAG_3GP_STR_INT, scans, 3);
+			tag = (MoovTag*)g_new0(MoovTag3GPStringInt, 1);
+			MOOV_TAG_3GP_STRING_INT(tag)->type = tag_type;
+			MOOV_TAG_3GP_STRING_INT(tag)->fourcc = fourcc;
+			MOOV_TAG_3GP_STRING_INT(tag)->value = str_val; str_val = NULL;
+			MOOV_TAG_3GP_STRING_INT(tag)->ivalue = int16_value;
+			break;
+		CASE_TAG(TAG_3GP_UINT, scans, 2);
+			tag = (MoovTag*)g_new0(MoovTag3GPUint, 1);
+			MOOV_TAG_3GP_UINT(tag)->type = tag_type;
+			MOOV_TAG_3GP_UINT(tag)->fourcc = fourcc;
+			MOOV_TAG_3GP_UINT(tag)->value = uint16_value;
+			break;
+		CASE_TAG(TAG_3GP_LOCATION, scans, 5);
+			tag = (MoovTag*)g_new0(MoovTag3GPLocation, 1);
+			MOOV_TAG_3GP_LOCATION(tag)->type = tag_type;
+			MOOV_TAG_3GP_LOCATION(tag)->fourcc = fourcc;
+			MOOV_TAG_3GP_LOCATION(tag)->location = str_loc; str_loc = NULL;
+			MOOV_TAG_3GP_LOCATION(tag)->latitude = latitude;
+			MOOV_TAG_3GP_LOCATION(tag)->longitude = longitude;
+			MOOV_TAG_3GP_LOCATION(tag)->altitude = altitude;
+			break;
+		CASE_TAG(TAG_3GP_KEYWORD, scans, 3);
+			tag = (MoovTag*)g_new0(MoovTag3GPKeyword, 1);
+			MOOV_TAG_3GP_KEYWORD(tag)->type = tag_type;
+			MOOV_TAG_3GP_KEYWORD(tag)->language = str_lang; str_lang = NULL;
+			MOOV_TAG_3GP_KEYWORD(tag)->keyword = str_kw; str_kw = NULL;
+			MOOV_TAG_3GP_KEYWORD(tag)->fourcc = fourcc;
+			break;
+		CASE_TAG(TAG_BLOB, scans, 2);
+			tag = (MoovTag*)g_new0(MoovTagBlob, 1);
+			MOOV_TAG_BLOB(tag)->type = tag_type;
+			MOOV_TAG_BLOB(tag)->data = data; data = NULL;
+			MOOV_TAG_BLOB(tag)->size = dat_size;
+			break;
+		}
+		g_free(data);
+		g_free(str_val);
+		g_free(str_loc);
+		g_free(str_lang);
+		g_free(str_kw);
+
+		if(tag) {
+			GST_LOG("Processed tag: %s", tagtype2str(tag_type));
+			if(tag_type == TAG_3GP_KEYWORD)
+				dat->keywords = g_slist_append(dat->keywords, tag);
+			else
+				dat->taglist = g_slist_append(dat->taglist, tag);
+		}
+	}
+}
+
+static void xml_end_event(void * userdata, const char * tag)
+{
+
+}
+
+/** Public MOOV XML API **/
+
+gboolean atom_moov_process(const gchar * filename, guint64 chunk_offset, gboolean largefile,
+						   guint64 * bsent, guint64 * duration, gboolean keep_xml_file, AtomMoovSendDataCB cb,
+						   AtomMoovProcPingCB ping_cb, gpointer user_data)
+{
+	XML_Parser p = 0;
+	gchar xmlbuf[1024*4];
+	size_t retval;
+	gint done = 0;
+	gboolean ret = FALSE;
+	MoovDat * dat;
+
+	g_return_val_if_fail(filename != NULL, FALSE);
+
+	GST_INFO("Process MOOV atom. Chunk Offset: %llu", chunk_offset);
+
+	if(!(dat = atom_create_moov(filename, chunk_offset, largefile)))
+		return FALSE;
+	dat->ping_cb = ping_cb;
+	dat->ping_userdata = user_data;
+	dat->last_ping = GST_CLOCK_TIME_NONE;
+
+	GST_INFO("Start XML Parse");
+
+	p = XML_ParserCreate(NULL);
+	if(!p)
+		return FALSE;
+	XML_SetElementHandler(p, xml_start_event, xml_end_event);
+	XML_SetUserData(p, dat);
+
+	while((retval = fread(xmlbuf, 1, sizeof(xmlbuf), dat->fd)) > 0) {
+		done = (feof(dat->fd) != 0) ? 1 : 0;
+		if(XML_Parse(p, xmlbuf, retval, done) == XML_STATUS_ERROR) {
+			GST_INFO("Parse Error: %s. Probably missing 'MOOV' end tag.",
+					 XML_ErrorString(XML_GetErrorCode(p)));
+			break;
+		}
+	}
+
+	atom_moov_finalize(dat);
+
+	GST_INFO("END XML Parse");
+
+	XML_ParserFree(p);
+
+	ret = atom_xml_moov_send(dat, cb, user_data);
+
+	if(duration) {
+		*duration = dat->mvhd_duration;
+		*duration = MOVIE2NS(*duration, dat->timescale);
+		GST_INFO("Movie duration: %llu (ms)", *duration / 1000000);
+	}
+
+	atom_moov_dat_free(dat, keep_xml_file);
+
+	return ret;
+}
+
+static gboolean atom_moov_xml_find_tag_from_end(FILE * fd, const gchar * start, const gchar * end, gchar ** tag)
+{
+	guint64 tag_e = 0;
+	guint64 pos = 0;
+	guint64 len = 0;
+	guint64 bytes;
+	gboolean have_s=FALSE,have_e=FALSE;
+	gchar tbuf[64];
+	gint s_len, e_len;
+
+	g_return_val_if_fail(fd != NULL, FALSE);
+	g_return_val_if_fail(start != NULL, FALSE);
+	g_return_val_if_fail(end != NULL, FALSE);
+	g_return_val_if_fail(strlen(start) < 64, FALSE);
+	g_return_val_if_fail(strlen(end) < 64, FALSE);
+	g_return_val_if_fail(tag != NULL, FALSE);
+
+	s_len = strlen(start);
+	e_len = strlen(end);
+
+	/* seek to end */
+	if(fseek(fd, 0, SEEK_END) != 0) {
+		GST_ERROR("Failed to seek to end");
+		goto end;
+	}
+
+	/* file length */
+	len = ftell(fd);
+
+	/* find last TC tag line */
+	while(pos < len) {
+		if(fseek(fd, len - (++pos), SEEK_SET) != 0) {
+			GST_ERROR("Failed to seek");
+			goto end;
+		}
+		if(!have_e) {
+			if((bytes = fread(&tbuf, 1, e_len, fd)) < 1) {
+				GST_ERROR("Failed to read");
+				goto end;
+			}
+			if(bytes < e_len)
+				continue;
+			tbuf[e_len] = '\0';
+			if(strcmp(tbuf, end)==0) {
+				have_e = TRUE;
+				tag_e = (len - pos) + e_len;
+			}
+			continue;
+		}
+		if(!have_s) {
+			if((bytes = fread(&tbuf, 1, s_len, fd)) < 1) {
+				GST_ERROR("Failed to read");
+				goto end;
+			}
+			if(bytes < s_len)
+				continue;
+			tbuf[s_len] = '\0';
+			if(strcmp(tbuf, start)==0) {
+				have_s = TRUE;
+				break;
+			}
+		}
+	}
+
+	if(have_s && have_e) {
+		gchar * retstr;
+		pos = len - pos;
+		if(fseek(fd, pos, SEEK_SET) != 0) {
+			GST_ERROR("Failed to seek");
+			goto end;
+		}
+		tag_e = tag_e - pos;
+		retstr = g_malloc0(tag_e+1);
+		if((bytes = fread(retstr, 1, tag_e, fd)) < 1) {
+			GST_ERROR("Failed to read");
+			g_free(retstr);
+			goto end;
+		}
+		*tag = retstr;
+		return TRUE;
+	}
+ end:
+	return FALSE;
+}
+
+/*
+ * Note: We don't want to parse the whole file here.. so we seek to
+ * the end, find the last TC tag, and parse size and offset.
+ */
+gboolean atom_moov_mdat_size_get(const gchar * filename, guint64 * mdat_size)
+{
+	FILE * fd = NULL;
+	gboolean ret = FALSE;
+	gchar * tag=NULL;
+	gchar *tmp, *tmp1;
+	gchar * sstr;
+	guint64 c_size=0, c_offset=0;
+
+	g_return_val_if_fail(filename != NULL, FALSE);
+	g_return_val_if_fail(mdat_size != NULL, FALSE);
+
+	fd = fopen(filename, "r");
+	if(!fd) {
+		GST_ERROR("Failed to open '%s'", filename);
+		goto end;
+	}
+
+	if(!atom_moov_xml_find_tag_from_end(fd, "<TC", "/>", &tag)) {
+		GST_ERROR("Failed to find chunk tag line");
+		goto end;
+	}
+
+	GST_DEBUG("Tag line: %s", tag);
+
+	/* Parse chunk size */
+	if((tmp = strstr(tag, "S='")) && (tmp1=strstr(tmp+3, "'"))) {
+		tmp += 3;
+		sstr = g_strndup(tmp, tmp1 - tmp);
+		if(sscanf(sstr, "%llu", &c_size) != 1) {
+			GST_ERROR("Failed to scan size from last chunk tag");
+			goto end;
+		}
+		g_free(sstr);
+	}
+
+	/* Parse chunk offset */
+	if((tmp = strstr(tag, "C='")) && (tmp1=strstr(tmp+3, "'"))) {
+		tmp += 3;
+		sstr = g_strndup(tmp, tmp1 - tmp);
+		if(sscanf(sstr, "%llu", &c_offset) != 1) {
+			GST_ERROR("Failed to scan offset from last chunk tag");
+			goto end;
+		}
+		g_free(sstr);
+	}
+
+	*mdat_size = c_offset + c_size;
+
+	GST_DEBUG("Size: %llu Offset: %llu Total Offset: %llu", c_size, c_offset, *mdat_size);
+
+	ret = TRUE;
+ end:
+	if(fd)
+		fclose(fd);
+	return ret;
+}
+
+
+/*** MOOV CONSTRUCTION & SEND ***/
+
+#define MSEND_BUF_SIZE (32*1024)
+
+typedef struct _MoovSend
+{
+	AtomMoovSendDataCB send_cb;
+	gpointer user_data;
+	guint8 * buffer;
+	guint buf_size;
+
+	guint8 * bptr;
+	guint bptr_size;
+} MoovSend;
+
+static guint msend_copy(MoovSend * msend, void * data, guint size)
+{
+	guint osize = size;
+
+	g_return_val_if_fail(msend != NULL, 0);
+	g_return_val_if_fail(data != NULL, 0);
+
+	while(size > 0) {
+		if(msend->bptr_size == 0) {
+			if(msend->buffer != NULL) {
+				//printf("msend: sending %d bytes\n", msend->buf_size);
+				if(!msend->send_cb(msend->user_data, msend->buffer, msend->buf_size)) {
+					GST_ERROR("Failed to send %u bytes", msend->buf_size);
+				}
+				msend->buffer = NULL;
+				msend->buf_size = 0;
+			}
+			//printf("msend: allocating: %d\n", MSEND_BUF_SIZE);
+			if(!(msend->buffer = msend->bptr = g_new0(guint8, MSEND_BUF_SIZE)))
+				goto err;
+			msend->buf_size = msend->bptr_size = MSEND_BUF_SIZE;
+		}
+		if(size > msend->bptr_size) {
+			//printf("msend: size: %d  ptrsize: %d\n", size, msend->bptr_size);
+			memcpy(msend->bptr, data, msend->bptr_size);
+			data += msend->bptr_size;
+			size -= msend->bptr_size;
+			msend->bptr_size = 0;
+			msend->bptr = NULL;
+		}
+		else {
+			//printf("msend: copy %d to bufptr size: %d to buf: %p\n", size, msend->bptr_size, msend->bptr);
+			memcpy(msend->bptr, data, size);
+			msend->bptr += size;
+			msend->bptr_size -= size;
+			size = 0;
+		}
+	}
+ err:
+	//printf("msend_copy: Got %d Sent: %d\n", osize, osize - size);
+	return osize - size;
+}
+
+static guint msend_file(MoovSend * msend, const gchar * filename)
+{
+	FILE * fd;
+	guint ret = 0;
+
+	g_return_val_if_fail(msend != NULL, 0);
+	g_return_val_if_fail(filename != NULL, 0);
+
+	GST_DEBUG("Sending file: %s", filename);
+
+	if((fd = fopen(filename, "r"))) {
+		size_t retval;
+		guint8 buf[32 * 1024];
+			
+		while((retval = fread(buf, 1, sizeof(buf), fd)) > 0) {
+			ret += msend_copy(msend, buf, retval);
+		}
+		if(ferror(fd) != 0) {
+			GST_ERROR("Error reading file '%s'", filename);
+		}
+		fclose(fd);
+	}
+	else {
+		GST_ERROR("Failed to open '%s'. %s", filename, strerror(errno));
+	}
+
+	return ret;
+}
+
+static guint msend_uint8(MoovSend * msend, guint8 prop)
+{
+	g_return_val_if_fail(msend != NULL, 0);
+	return msend_copy(msend, &prop, sizeof(guint8));
+}
+
+static guint msend_uint16(MoovSend * msend, guint16 prop)
+{
+	g_return_val_if_fail(msend != NULL, 0);
+	prop = GUINT16_TO_BE (prop);
+	return msend_copy(msend, &prop, sizeof(guint16));
+}
+
+static guint msend_uint32(MoovSend * msend, guint32 prop)
+{
+	g_return_val_if_fail(msend != NULL, 0);
+	prop = GUINT32_TO_BE (prop);
+	return msend_copy(msend, &prop, sizeof(guint32));
+}
+
+static guint msend_uint64(MoovSend * msend, guint64 prop)
+{
+	g_return_val_if_fail(msend != NULL, 0);
+	prop = GUINT64_TO_BE (prop);
+	return msend_copy(msend, &prop, sizeof(guint64));
+}
+
+static guint msend_uint8_multi(MoovSend * msend, guint8 prop, gint num)
+{
+	gint i;
+	guint ret = 0;
+	g_return_val_if_fail(msend != NULL, 0);
+	for(i=0;i<num;i++)
+		ret += msend_uint8(msend, prop);
+	return ret;
+}
+
+static guint msend_fourcc(MoovSend * msend, guint32 prop)
+{
+	g_return_val_if_fail(msend != NULL, 0);
+	prop = GUINT32_TO_LE (prop);
+	return msend_copy(msend, &prop, sizeof(guint32));
+}
+
+static guint msend_atom_header(MoovSend * msend, guint32 size, guint32 type)
+{
+	guint ret = 0;
+	g_return_val_if_fail(msend != NULL, 0);
+	ret += msend_uint32(msend, size);
+	ret += msend_fourcc(msend, type);
+	return ret;
+}
+
+static guint msend_atom_header_full(MoovSend * msend, guint32 size, guint32 type,
+									guint8 ver, guint8 flag1, guint8 flag2, guint8 flag3)
+{
+	guint ret = 0;
+	g_return_val_if_fail(msend != NULL, 0);
+	ret += msend_atom_header(msend, size, type);
+	ret += msend_uint8(msend, ver);
+	/* flags */
+	ret += msend_uint8(msend, flag1);
+	ret += msend_uint8(msend, flag2);
+	ret += msend_uint8(msend, flag3);
+	return ret;
+}
+
+static guint msend_atom_times(MoovSend * msend, guint64 ctime, guint64 mtime, guint32 timescale, guint64 duration, gboolean _64bit)
+{
+	guint ret = 0;
+	g_return_val_if_fail(msend != NULL, 0);
+	if(_64bit) {
+		ret += msend_uint64(msend, ctime);
+		ret += msend_uint64(msend, mtime);
+		ret += msend_uint32(msend, timescale);
+		ret += msend_uint64(msend, duration);
+	}
+	else {
+		ret += msend_uint32(msend, (guint32)ctime);
+		ret += msend_uint32(msend, (guint32)mtime);
+		ret += msend_uint32(msend, timescale);
+		ret += msend_uint32(msend, (guint32)duration);
+	}
+	return ret;
+}
+
+static guint msend_matrix_4byte(MoovSend * msend, guint32 * matrix, guint size)
+{
+	guint ret = 0;
+	gint i;
+	
+	g_return_val_if_fail(msend != NULL, 0);
+	g_return_val_if_fail(matrix != NULL, 0);
+	g_return_val_if_fail((size % 4) == 0, 0); 
+
+	size = size / 4;
+
+	for(i=0;i<size;i++)
+		ret += msend_uint32(msend, matrix[i]);
+
+	return ret;
+}
+
+typedef struct _MoovTrackSizes
+{
+	guint trak_size;
+	guint tkhd_size;
+	guint edts_size;
+	guint edts_entries;
+	guint mdia_size;
+	guint _mdhd_size;
+	guint _hdlr_size;
+	guint _minf_size;
+	guint __vmhd_size;
+	guint __smhd_size;
+	guint __hmhd_size;
+	guint __hdlr_size;
+	guint __dinf_size;
+	guint ___dref_size;
+	guint __stbl_size;
+	guint ___stsd_size;
+	guint ____stsd_desc_size;
+	guint ___stts_size;
+	guint ___stss_size;
+	guint ___stsc_size;
+	guint ___stsz_size;
+	guint ___ctts_size;
+	guint ___stco_size;
+} MoovTrackSizes;
+
+typedef struct _MoovSizes
+{
+	guint moov_size;
+	guint _mvhd_size;
+	guint _udta_size;
+	guint __meta_size;
+	guint ___ilst_size;
+	MoovTrackSizes * trak_sizes[MAX_TRACKS];
+} MoovSizes;
+
+#define ATOM_HEADER_SIZE          8
+#define ATOM_HEADER_FULL_SIZE     12
+#define MVHD_ATOM_SIZE            108
+#define TKHD_ATOM_SIZE            92
+#define EDTS_ATOM_SIZE            8
+#define ELST_ATOM_SIZE            16   /* + table */
+#define ELST_ATOM_ENTRY_SIZE      12
+#define ELST_ATOM_ENTRY_64_SIZE   20
+#define MDHD_ATOM_SIZE            32
+#define HDLR_ATOM_SIZE            32   /* + component name string size */
+#define VMHD_ATOM_SIZE            20
+#define SMHD_ATOM_SIZE            16
+#define DREF_ATOM_SIZE            16   /* + variable number of dref items */
+#define ALIS_ATOM_SIZE            12   /* + variable size data section */
+#define URL_ATOM_SIZE             12   /* + variable size url string */
+#define STSD_ATOM_SIZE            16   /* + variable number of entries */
+#define STSD_SDESC_ATOM_SIZE      16   /* + media specifc data */
+#define STSD_SDESC_VIDEO_SIZE     70   /* + extensions */
+#define STSD_SDESC_AUDIO_V0_SIZE  20   /* + extensions */
+#define STSD_SDESC_AUDIO_V1_SIZE  36   /* + extensions */
+#define STTS_ATOM_SIZE            16   /* + table */
+#define STTS_ATOM_ENTRY_SIZE      8
+#define STSS_ATOM_SIZE            16   /* + table */
+#define STSS_ATOM_ENTRY_SIZE      4
+#define STSC_ATOM_SIZE            16   /* + table */
+#define STSC_ATOM_ENTRY_SIZE      12
+#define STCO_ATOM_SIZE            16   /* + table */
+#define STCO_ATOM_ENTRY_SIZE      4
+#define CO64_ATOM_ENTRY_SIZE      8
+#define STSZ_ATOM_SIZE            20
+#define STSZ_ATOM_ENTRY_SIZE      4
+#define CTTS_ATOM_SIZE            16
+#define CTTS_ATOM_ENTRY_SIZE      8
+
+typedef enum {
+	STTS = 0,
+	STSS,
+	STSC,
+	STSZ,
+	CTTS,
+	STCO,
+} StblType;
+
+#define MSEND_CHECK_EXPECTED(expected, actual, _info)					\
+	if(expected != actual) {											\
+		const gchar * info = _info;										\
+		GST_ERROR("Atom size sent %s%s%s, does not match expected (%u/%u)",	\
+				  info?"(":"",info?info:"", info?")":"", expected, actual); \
+	}
+
+static guint atom_xml_build_stbl_table(StblType type, MoovDat * dat, MoovSend * msend, MoovTrak * trak, MoovTrackSizes * tsizes)
+{
+	guint ret = 0;
+	guint entry_count = 0, size=0, fourcc=0;
+	guint * tsize = NULL;
+	const gchar * filename = NULL;
+	const gchar * type_str = NULL;
+
+	g_return_val_if_fail(dat != NULL, 0);
+	g_return_val_if_fail(trak != NULL, 0);
+
+	switch(type) {
+	case STTS:
+		entry_count = trak->stts_entry_count;
+		size = entry_count * STTS_ATOM_ENTRY_SIZE;
+		filename = trak->filename_stts;
+		tsize = &tsizes->___stts_size;
+		fourcc = FOURCC_stts;
+		type_str = "STTS";
+		break;
+	case STSS:
+		entry_count = trak->stss_entry_count;
+		size = entry_count * STSS_ATOM_ENTRY_SIZE;
+		filename = trak->filename_stss;
+		tsize = &tsizes->___stss_size;
+		fourcc = FOURCC_stss;
+		type_str = "STSS";
+		break;
+	case STSC:
+		entry_count = trak->stsc_entry_count;
+		size = entry_count * STSC_ATOM_ENTRY_SIZE;
+		filename = trak->filename_stsc;
+		tsize = &tsizes->___stsc_size;
+		fourcc = FOURCC_stsc;
+		type_str = "STSC";
+		break;
+	case STSZ:
+		entry_count = trak->stsz_entry_count;
+		size = entry_count * STSZ_ATOM_ENTRY_SIZE;
+		filename = trak->filename_stsz;
+		tsize = &tsizes->___stsz_size;
+		fourcc = FOURCC_stsz;
+		type_str = "STSZ";
+		break;
+	case CTTS:
+		entry_count = trak->ctts_entry_count;
+		size = entry_count * CTTS_ATOM_ENTRY_SIZE;
+		filename = trak->filename_ctts;
+		tsize = &tsizes->___ctts_size;
+		fourcc = FOURCC_ctts;
+		type_str = "CTTS";
+		break;
+	case STCO:
+		entry_count = trak->stco_entry_count;
+		if(dat->largefile) {
+			size = entry_count * CO64_ATOM_ENTRY_SIZE;
+			fourcc = FOURCC_co64;
+		}
+		else {
+			size = entry_count * STCO_ATOM_ENTRY_SIZE;
+			fourcc = FOURCC_stco;
+		}
+		filename = trak->filename_stco;
+		tsize = &tsizes->___stco_size;
+		type_str = "STCO";
+		break;
+	}
+
+	if(entry_count == 0)
+		return 0;
+
+	if(!msend) {
+		ret = ATOM_HEADER_FULL_SIZE;
+		ret += 4;        /* number of entries */
+		if(type == STSZ)
+			ret += 4;    /* sample size */
+		ret += size;
+		*tsize = ret;
+	}
+	else {
+		ret += msend_atom_header_full(msend, *tsize, fourcc, 0, 0, 0, 0);
+		if(type == STSZ)
+			ret += msend_uint32(msend, trak->fixed_sample_size);
+		ret += msend_uint32(msend, entry_count);
+		ret += msend_file(msend, filename);
+	}
+
+	MSEND_CHECK_EXPECTED(*tsize, ret, type_str);
+
+	return ret;
+}
+
+static guint atom_xml_build_esds_ext(MoovSend * msend, MoovTrak * trak, MoovTrackSizes * tsizes, 
+									 guint8 object_type, guint8 stream_type)
+{
+	AtomInfo * ai;
+	guint8 * data = NULL;
+	guint64 size = 0, offset = 0;
+	guint bytes = 0, ret = 0;
+	GstBuffer * buf = NULL;
+
+	if(trak->codec_data && trak->codec_data_size > 0) {
+		buf = gst_buffer_new();
+		GST_BUFFER_DATA(buf) = trak->codec_data;
+		GST_BUFFER_SIZE(buf) = trak->codec_data_size;
+	}
+
+	ai = build_esds_extension(trak->trak_id, object_type, stream_type, buf);
+	bytes = (guint32)atom_info_copy_data(ai, &data, &size, &offset);
+
+	if(buf) {
+		if(msend) {
+			GST_BUFFER_MALLOCDATA(buf) = GST_BUFFER_DATA(buf);
+			trak->codec_data = NULL;
+			trak->codec_data_size = 0;
+		}
+		gst_buffer_unref(buf);
+	}
+
+	if(!msend) {
+		ret = bytes;
+	}
+	else {
+		ret += msend_copy(msend, data, bytes);
+	}
+
+	atom_info_free(ai);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_mov_aac_ext(MoovSend * msend, MoovTrak * trak, MoovTrackSizes * tsizes)
+{
+	AtomInfo * ai;
+	guint8 * data = NULL;
+	guint64 size = 0, offset = 0;
+	guint bytes = 0, ret = 0;
+	GstBuffer * buf = NULL;
+
+	if(trak->codec_data && trak->codec_data_size > 0) {
+		buf = gst_buffer_new();
+		GST_BUFFER_DATA(buf) = trak->codec_data;
+		GST_BUFFER_SIZE(buf) = trak->codec_data_size;
+	}
+
+	ai = build_mov_aac_extension(trak->trak_id, buf);
+	bytes = (guint32)atom_info_copy_data(ai, &data, &size, &offset);
+
+	if(buf) {
+		if(msend) {
+			GST_BUFFER_MALLOCDATA(buf) = GST_BUFFER_DATA(buf);
+			trak->codec_data = NULL;
+			trak->codec_data_size = 0;
+		}
+		gst_buffer_unref(buf);
+	}
+
+	if(!msend) {
+		ret = bytes;
+	}
+	else {
+		ret += msend_copy(msend, data, bytes);
+	}
+
+	atom_info_free(ai);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_amr_ext(MoovSend * msend, MoovTrackSizes * tsizes)
+{
+	AtomInfo * ai;
+	guint8 * data = NULL;
+	guint64 size = 0, offset = 0;
+	guint bytes = 0, ret = 0;
+
+	ai = build_amr_extension();
+	bytes = (guint32)atom_info_copy_data(ai, &data, &size, &offset);
+
+	if(!msend) {
+		ret = bytes;
+	}
+	else {
+		ret += msend_copy(msend, data, bytes);
+	}
+
+	atom_info_free(ai);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_h263_ext(MoovSend * msend, MoovTrackSizes * tsizes)
+{
+	AtomInfo * ai;
+	guint8 * data = NULL;
+	guint64 size = 0, offset = 0;
+	guint bytes = 0, ret = 0;
+
+	ai = build_h263_extension();
+	bytes = (guint32)atom_info_copy_data(ai, &data, &size, &offset);
+
+	if(!msend) {
+		ret = bytes;
+	}
+	else {
+		ret += msend_copy(msend, data, bytes);
+	}
+
+	atom_info_free(ai);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_codec_data_ext(MoovSend * msend, MoovTrak * trak, MoovTrackSizes * tsizes, guint32 fourcc)
+{
+	AtomInfo * ai;
+	guint8 * data = NULL;
+	guint64 size = 0, offset = 0;
+	guint bytes = 0, ret = 0;
+	GstBuffer * buf = NULL;
+
+	if(trak->codec_data && trak->codec_data_size > 0) {
+		buf = gst_buffer_new();
+		GST_BUFFER_DATA(buf) = trak->codec_data;
+		GST_BUFFER_SIZE(buf) = trak->codec_data_size;
+	}
+
+	ai = build_codec_data_extension(fourcc, buf);
+	bytes = (guint32)atom_info_copy_data(ai, &data, &size, &offset);
+
+	if(buf) {
+		if(msend) {
+			GST_BUFFER_MALLOCDATA(buf) = GST_BUFFER_DATA(buf);
+			trak->codec_data = NULL;
+			trak->codec_data_size = 0;
+		}
+		gst_buffer_unref(buf);
+	}
+
+	if(!msend) {
+		ret = bytes;
+	}
+	else {
+		ret += msend_copy(msend, data, bytes);
+	}
+
+	atom_info_free(ai);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_jp2h_ext(MoovSend * msend, MoovTrakVideo * vtrak, MoovTrackSizes * tsizes)
+{
+	AtomInfo * ai;
+	guint8 * data = NULL;
+	guint64 size = 0, offset = 0;
+	guint bytes = 0, ret = 0;
+
+	if(!(ai = build_jp2h_extension(vtrak->width, vtrak->height, MOOV_TRAK(vtrak)->fourcc)))
+		return 0;
+	bytes = (guint32)atom_info_copy_data(ai, &data, &size, &offset);
+
+	if(!msend) {
+		ret = bytes;
+	}
+	else {
+		ret += msend_copy(msend, data, bytes);
+	}
+
+	atom_info_free(ai);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_audio_extension(MoovSend * msend, MoovTrakAudio * atrak, MoovTrackSizes * tsizes)
+{
+	g_return_val_if_fail(atrak != NULL, 0);
+
+	switch(atrak->audio_ext) {
+	case ATOM_CTX_AUDIO_EXT_NONE:
+		return 0;
+	case ATOM_CTX_AUDIO_EXT_MP1_P3:
+		return atom_xml_build_esds_ext(msend, MOOV_TRAK(atrak), tsizes,
+								   ESDS_OBJECT_TYPE_MPEG1_P3, ESDS_STREAM_TYPE_AUDIO);
+	case ATOM_CTX_AUDIO_EXT_AAC:
+		return atom_xml_build_mov_aac_ext(msend, MOOV_TRAK(atrak), tsizes);
+	case ATOM_CTX_AUDIO_EXT_MP4_P3:
+		return atom_xml_build_esds_ext(msend, MOOV_TRAK(atrak), tsizes,
+								   ESDS_OBJECT_TYPE_MPEG4_P3, ESDS_STREAM_TYPE_AUDIO);
+	case ATOM_CTX_AUDIO_EXT_AMR:
+		return atom_xml_build_amr_ext(msend, tsizes);
+	}
+
+	return 0;
+}
+
+static guint atom_xml_build_video_extension(MoovSend * msend, MoovTrakVideo * vtrak, MoovTrackSizes * tsizes)
+{
+	g_return_val_if_fail(vtrak != NULL, 0);
+
+	switch(vtrak->visual_ext) {
+	case ATOM_CTX_VISUAL_EXT_NONE:
+		return 0;
+	case ATOM_CTX_VISUAL_EXT_H263:
+		return atom_xml_build_h263_ext(msend, tsizes);
+	case ATOM_CTX_VISUAL_EXT_MP4_P2:
+		return atom_xml_build_esds_ext(msend, MOOV_TRAK(vtrak), tsizes,
+								   ESDS_OBJECT_TYPE_MPEG4_P2, ESDS_STREAM_TYPE_VISUAL);
+	case ATOM_CTX_VISUAL_EXT_AVCC:
+		return atom_xml_build_codec_data_ext(msend, MOOV_TRAK(vtrak), tsizes, FOURCC_avcC);
+	case ATOM_CTX_VISUAL_EXT_JP2H:
+		return atom_xml_build_jp2h_ext(msend, vtrak, tsizes);
+		break;
+	}
+
+	return 0;
+}
+
+static guint atom_xml_build_stsd_audio(MoovDat * dat, MoovSend * msend, MoovTrakAudio * atrak, MoovTrackSizes * tsizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+	g_return_val_if_fail(atrak != NULL, 0);
+
+	if(!msend) {
+		ret = STSD_SDESC_ATOM_SIZE;
+		if(atrak->version == 0)
+			ret += STSD_SDESC_AUDIO_V0_SIZE;
+		else
+			ret += STSD_SDESC_AUDIO_V1_SIZE;
+		ret += atom_xml_build_audio_extension(msend, atrak, tsizes);
+		tsizes->____stsd_desc_size = ret;
+	}
+	else {
+		guint8 reserved[6];
+
+		memset(&reserved, 0, sizeof(reserved));
+
+		/* General Sample Desc */
+		ret += msend_atom_header(msend, tsizes->____stsd_desc_size, MOOV_TRAK(atrak)->fourcc);
+		ret += msend_copy(msend, reserved, sizeof(reserved));
+		ret += msend_uint16(msend, MOOV_TRAK(atrak)->data_ref_index);
+		/* Audio Sample Desc v0 */
+		ret += msend_uint16(msend, atrak->version);            /* version            */
+		ret += msend_uint16(msend, 0);                         /* revision level     */
+		ret += msend_uint32(msend, 0);                         /* vendor             */
+		ret += msend_uint16(msend, atrak->channels);           /* channels           */
+		ret += msend_uint16(msend, atrak->sample_size);        /* sample size        */
+		ret += msend_uint16(msend, atrak->compression_id);     /* compression id     */
+		ret += msend_uint16(msend, 0);                         /* packet size        */
+		ret += msend_uint32(msend, MOOV_TRAK(atrak)->timescale << 16); /* sample rate */
+		/* Audio Sample Desc v1 */
+		if(atrak->version > 0) {
+			ret += msend_uint32(msend, atrak->samples_per_packet); /* samples per packet */
+			ret += msend_uint32(msend, atrak->bytes_per_sample);   /* bytes per sample   */
+			ret += msend_uint32(msend, atrak->bytes_per_packet);   /* bytes per packet   */
+			ret += msend_uint32(msend, atrak->bytes_per_frame);    /* bytes per frame    */
+		}
+		/* Audio extensions */
+		ret += atom_xml_build_audio_extension(msend, atrak, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->____stsd_desc_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_stsd_video(MoovDat * dat, MoovSend * msend, MoovTrakVideo * vtrak, MoovTrackSizes * tsizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+	g_return_val_if_fail(vtrak != NULL, 0);
+
+	if(!msend) {
+		ret = STSD_SDESC_ATOM_SIZE;
+		ret += STSD_SDESC_VIDEO_SIZE;
+		ret += atom_xml_build_video_extension(msend, vtrak, tsizes);
+		tsizes->____stsd_desc_size = ret;
+	}
+	else {
+		guint8 reserved[6], compressor[32];
+		guint squal=0, tqual=0;
+
+		memset(&reserved, 0, sizeof(reserved));
+		memset(&compressor, 0, sizeof(compressor));
+		if(dat->flavor == ATOMS_TREE_FLAVOR_MOV) {
+			tqual = 512;
+			squal = 512;
+		}
+		/* General Sample Desc */
+		ret += msend_atom_header(msend, tsizes->____stsd_desc_size, MOOV_TRAK(vtrak)->fourcc);
+		ret += msend_copy(msend, reserved, sizeof(reserved));
+		ret += msend_uint16(msend, MOOV_TRAK(vtrak)->data_ref_index);
+		/* Video Sample Desc */
+		ret += msend_uint16(msend, 0);                  /* version          */
+		ret += msend_uint16(msend, 0);                  /* revision level   */
+		ret += msend_uint32(msend, 0);                  /* vendor           */
+		ret += msend_uint32(msend, tqual);              /* temporal quality */
+		ret += msend_uint32(msend, squal);              /* spacial quality  */
+		ret += msend_uint16(msend, vtrak->width);       /* width            */
+		ret += msend_uint16(msend, vtrak->height);      /* height           */
+		ret += msend_uint32(msend, 72 << 16);           /* horizontal res   */
+		ret += msend_uint32(msend, 72 << 16);           /* vertical res     */
+		ret += msend_uint32(msend, 0);                  /* data size        */
+		ret += msend_uint16(msend, vtrak->frame_count); /* frame count      */
+		ret += msend_copy(msend, compressor, sizeof(compressor));
+		ret += msend_uint16(msend, vtrak->depth);       /* pixel depth      */
+		ret += msend_uint16(msend, vtrak->color_table_id); /* color table id   */
+		/* Video Extensions */
+		ret += atom_xml_build_video_extension(msend, vtrak, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->____stsd_desc_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_stsd(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = STSD_ATOM_SIZE;
+		/* single entry */
+		if(trak->is_video)
+			ret += atom_xml_build_stsd_video(dat, msend, MOOV_TRAK_VIDEO(trak), tsizes);
+		else
+			ret += atom_xml_build_stsd_audio(dat, msend, MOOV_TRAK_AUDIO(trak), tsizes);
+		tsizes->___stsd_size = ret;
+	}
+	else {
+		ret += msend_atom_header_full(msend, tsizes->___stsd_size, FOURCC_stsd, 0, 0, 0, 0);
+		ret += msend_uint32(msend, 1);  /* num of entries */
+		if(trak->is_video)
+			ret += atom_xml_build_stsd_video(dat, msend, MOOV_TRAK_VIDEO(trak), tsizes);
+		else
+			ret += atom_xml_build_stsd_audio(dat, msend, MOOV_TRAK_AUDIO(trak), tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->___stsd_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_stbl(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = ATOM_HEADER_SIZE;
+		ret += atom_xml_build_stsd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_stbl_table(STTS, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STSS, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STSC, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STSZ, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(CTTS, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STCO, dat, msend, trak, tsizes);
+		tsizes->__stbl_size = ret;
+	}
+	else {
+		ret += msend_atom_header(msend, tsizes->__stbl_size, FOURCC_stbl);
+		ret += atom_xml_build_stsd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_stbl_table(STTS, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STSS, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STSC, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STSZ, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(CTTS, dat, msend, trak, tsizes);
+		ret += atom_xml_build_stbl_table(STCO, dat, msend, trak, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->__stbl_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_alis(MoovSend * msend, gpointer alis_data, guint32 data_size)
+{
+	guint ret = 0;
+	
+	if(!msend) {
+		ret = ALIS_ATOM_SIZE;
+		ret += data_size;
+	}
+	else {
+		ret += msend_atom_header_full(msend, ALIS_ATOM_SIZE + data_size, FOURCC_alis, 0, 0, 0, 1);
+		if(data_size > 0)
+			ret += msend_copy(msend, alis_data, data_size);
+	}
+
+	return ret;
+}
+
+static guint atom_xml_build_url(MoovSend * msend, gchar * url)
+{
+	guint ret = 0;
+	guint url_size;
+
+	url = (url==NULL) ? "" : url;
+	url_size = strlen(url);
+
+	if(!msend) {
+		ret = URL_ATOM_SIZE;
+		ret += url_size;
+	}
+	else {
+		ret += msend_atom_header_full(msend, URL_ATOM_SIZE + url_size, FOURCC_url_, 0, 0, 0, 1);
+		ret += msend_copy(msend, url, url_size);
+	}
+
+	return ret;
+}
+
+static guint atom_xml_build_dref(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!msend) {
+		ret = DREF_ATOM_SIZE;
+		/* Single DREF entry .. */
+		if(dat->flavor == ATOMS_TREE_FLAVOR_MOV)
+			ret += atom_xml_build_alis(msend, NULL, 0);
+		else
+			ret += atom_xml_build_url(msend, NULL);
+		tsizes->___dref_size = ret;
+	}
+	else {
+		ret += msend_atom_header_full(msend, tsizes->___dref_size, FOURCC_dref, 0, 0, 0, 0);
+		ret += msend_uint32(msend, 1);  /* num of entries */
+		if(dat->flavor == ATOMS_TREE_FLAVOR_MOV)
+			ret += atom_xml_build_alis(msend, NULL, 0);
+		else
+			ret += atom_xml_build_url(msend, NULL);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->___dref_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_dinf(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!msend) {
+		ret = ATOM_HEADER_SIZE;
+		ret += atom_xml_build_dref(dat, msend, trak_index, tsizes);
+		tsizes->__dinf_size = ret;
+	}
+	else {
+		ret += msend_atom_header(msend, tsizes->__dinf_size, FOURCC_dinf);
+		ret += atom_xml_build_dref(dat, msend, trak_index, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->__dinf_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_minf_hdlr(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+	gchar * cn;
+	guint cn_size;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(dat->flavor != ATOMS_TREE_FLAVOR_MOV)
+		return 0;
+
+	cn = (trak->component_name==NULL) ? "" : trak->component_name;
+	cn_size = strlen(cn) + 1;
+
+	if(!msend) {
+		ret = HDLR_ATOM_SIZE;
+		ret += cn_size;
+		tsizes->__hdlr_size = ret;
+	}
+	else {
+		ret += msend_atom_header_full(msend, tsizes->__hdlr_size, FOURCC_hdlr, 0, 0, 0, 0);
+		ret += msend_fourcc(msend, FOURCC_dhlr);
+		ret += msend_fourcc(msend, FOURCC_alis);
+		ret += msend_uint32(msend, 0); /* manufacturer    */
+		ret += msend_uint32(msend, 0); /* component flags */
+		ret += msend_uint32(msend, 0); /* flags mask      */
+		ret += msend_copy(msend, cn, cn_size);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->__hdlr_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_smhd(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = SMHD_ATOM_SIZE;
+		tsizes->__smhd_size = ret;
+	}
+	else {
+		ret += msend_atom_header_full(msend, tsizes->__smhd_size, FOURCC_smhd, 0, 0, 0, 0);
+		ret += msend_uint16(msend, 0);       /* balance       */
+		ret += msend_uint16(msend, 0);       /* reserved      */
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->__smhd_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_vmhd(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = VMHD_ATOM_SIZE;
+		tsizes->__vmhd_size = ret;
+	}
+	else {
+		guint opcolor = 0;
+		if(dat->flavor == ATOMS_TREE_FLAVOR_MOV)
+			opcolor = 32768;
+		ret += msend_atom_header_full(msend, tsizes->__vmhd_size, FOURCC_vmhd, 0, 0, 0, 1);
+		ret += msend_uint16(msend, 0);       /* graphics mode */
+		ret += msend_uint16(msend, opcolor); /* opcolor       */
+		ret += msend_uint16(msend, opcolor); /* opcolor       */
+		ret += msend_uint16(msend, opcolor); /* opcolor       */
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->__vmhd_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_minf(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = ATOM_HEADER_SIZE;
+		if(trak->is_video)
+			ret += atom_xml_build_vmhd(dat, msend, trak_index, tsizes);
+		else
+			ret += atom_xml_build_smhd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_minf_hdlr(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_dinf(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_stbl(dat, msend, trak_index, tsizes);
+		tsizes->_minf_size = ret;
+	}
+	else {
+		ret = msend_atom_header(msend, tsizes->_minf_size, FOURCC_minf);
+		if(trak->is_video)
+			ret += atom_xml_build_vmhd(dat, msend, trak_index, tsizes);
+		else
+			ret += atom_xml_build_smhd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_minf_hdlr(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_dinf(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_stbl(dat, msend, trak_index, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->_minf_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_mdia_hdlr(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+	gchar * cn;
+	guint cn_size;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+	cn = (trak->component_name==NULL) ? "" : trak->component_name;
+	cn_size = strlen(cn) + 1;
+
+	if(!msend) {
+		ret = HDLR_ATOM_SIZE;
+		ret += cn_size;
+		tsizes->_hdlr_size = ret;
+	}
+	else {
+		ret += msend_atom_header_full(msend, tsizes->_hdlr_size, FOURCC_hdlr, 0, 0, 0, 0);
+		ret += msend_fourcc(msend, (dat->flavor==ATOMS_TREE_FLAVOR_MOV) ? FOURCC_mhlr : 0);
+		ret += msend_fourcc(msend, trak->is_video ? FOURCC_vide : FOURCC_soun);
+		ret += msend_uint32(msend, 0); /* manufacturer    */
+		ret += msend_uint32(msend, 0); /* component flags */
+		ret += msend_uint32(msend, 0); /* flags mask      */
+		ret += msend_copy(msend, cn, cn_size);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->_hdlr_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_mdhd(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = (trak->mdhd_version==0) ? MDHD_ATOM_SIZE : MDHD_ATOM_SIZE + 12;
+		tsizes->_mdhd_size = ret;
+	}
+	else {
+		gboolean _64bit = (trak->mdhd_version==0) ? FALSE : TRUE;
+		ret += msend_atom_header_full(msend, tsizes->_mdhd_size, FOURCC_mdhd, trak->mdhd_version, 0, 0, 0);
+		ret += msend_atom_times(msend, dat->creation_time, dat->modification_time,
+								trak->timescale, trak->stts_duration, _64bit);
+		ret += msend_uint16(msend, 0); /* language */
+		ret += msend_uint16(msend, 0); /* quality  */
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->_mdhd_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_mdia(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = ATOM_HEADER_SIZE;
+		ret += atom_xml_build_mdhd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_mdia_hdlr(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_minf(dat, msend, trak_index, tsizes);
+		tsizes->mdia_size = ret;
+	}
+	else {
+		ret = msend_atom_header(msend, tsizes->mdia_size, FOURCC_mdia);
+		ret += atom_xml_build_mdhd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_mdia_hdlr(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_minf(dat, msend, trak_index, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->mdia_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_tkhd(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = (trak->tkhd_version==0) ? TKHD_ATOM_SIZE : TKHD_ATOM_SIZE + 12;
+		tsizes->tkhd_size = ret;
+	}
+	else {
+		gboolean _64bit = (trak->tkhd_version==0) ? FALSE : TRUE;
+		guint32 matrix[9];
+		guint32 dwidth=0, dheight=0;
+		guint16 volume = 0;
+
+		memset(&matrix, 0, sizeof(matrix));
+		matrix[0] = 1 << 16;
+		matrix[4] = 1 << 16;
+		matrix[8] = 16384 << 16;
+		if(!trak->is_video)
+			volume = 0x0100;
+
+		ret += msend_atom_header_full(msend, tsizes->tkhd_size, FOURCC_tkhd, trak->tkhd_version, 0, 0, 7);
+		if(_64bit) {
+			ret += msend_uint64(msend, dat->creation_time);
+			ret += msend_uint64(msend, dat->modification_time);
+			ret += msend_uint32(msend, trak_index);
+			ret += msend_uint32(msend, 0); /* reserved */
+			ret += msend_uint64(msend, trak->tkhd_duration);
+		}
+		else {
+			ret += msend_uint32(msend, (guint32)dat->creation_time);
+			ret += msend_uint32(msend, (guint32)dat->modification_time);
+			ret += msend_uint32(msend, trak_index);
+			ret += msend_uint32(msend, 0); /* reserved */
+			ret += msend_uint32(msend, (guint32)trak->tkhd_duration);
+		}
+		ret += msend_uint32(msend, 0); /* reserved  */
+		ret += msend_uint32(msend, 0); /* reserved  */
+		ret += msend_uint16(msend, 0); /* layer     */
+		ret += msend_uint16(msend, 0); /* alt group */
+		ret += msend_uint16(msend, volume); /* volume    */
+		ret += msend_uint16(msend, 0); /* reserved  */
+		ret += msend_matrix_4byte(msend, matrix, sizeof(matrix)); /* matrix     */
+		if(trak->is_video) {
+			gint par_n = 0, par_d = 0;
+
+			dwidth = MOOV_TRAK_VIDEO(trak)->width;
+			dheight = MOOV_TRAK_VIDEO(trak)->height;			
+			par_n = MOOV_TRAK_VIDEO(trak)->par_n;
+			par_d = MOOV_TRAK_VIDEO(trak)->par_d;
+
+			if(!((par_n != 1 || par_d != 1) && (par_n != par_d))) {
+				par_n = 0;
+				par_d = 0;
+			}
+			/* ISO file spec says track header w/h indicates track's visual
+			 * presentation (so this together with pixels w/h implicitly
+			 * defines PAR)
+			 */
+			if(par_n && par_d && dat->flavor != ATOMS_TREE_FLAVOR_MOV) {
+				if(par_n > par_d)
+					dwidth = dwidth * par_n / par_d;
+				else
+					dwidth = dwidth * par_n / par_d;
+			}
+		}
+		ret += msend_uint32(msend, dwidth << 16);  /* width */
+		ret += msend_uint32(msend, dheight << 16); /* height */
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->tkhd_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_elst(MoovDat * dat, MoovSend * msend, MoovTrak * trak, gboolean bit64,
+								 guint64 mov_time_dur, guint64 media_start, guint32 play_rate)
+{
+	guint ret = 0;
+
+	if(!msend) {
+		if(bit64)
+			return ELST_ATOM_ENTRY_64_SIZE;
+		else
+			return ELST_ATOM_ENTRY_SIZE;
+	}
+	else {
+		guint64 dur, start;
+		dur = MOVIE2NS(mov_time_dur, dat->timescale); dur /= 1000000;
+		start = MEDIA2NS(media_start, trak->timescale); start /= 1000000;
+		if(bit64) {
+			ret += msend_uint64(msend, mov_time_dur);
+			ret += msend_uint64(msend, media_start);
+		}
+		else {
+			ret += msend_uint32(msend, (guint32)mov_time_dur);
+			ret += msend_uint32(msend, (guint32)media_start);
+		}
+		ret += msend_uint32(msend, play_rate);
+		if(media_start == -1)
+			GST_DEBUG("[trak:%u] Insert edit [empt]: Duration: %llu(ms)", trak->trak_id, dur);
+		else
+			GST_DEBUG("[trak:%u] Insert edit [real]: Duration: %llu(ms), Media Offset: %llu(ms)", trak->trak_id, dur, start);
+	}
+
+	return ret;
+}
+
+static gboolean atom_xml_edts_is_64bit(MoovDat * dat, MoovTrak * trak, guint movie_start_ts)
+{
+	guint64 largest_duration = 0;
+	guint64 largest_starttime = 0;
+	guint64 duration = 0;
+	guint64 last_toffset = 0;
+	gboolean ret = FALSE;
+	GSList * lst;
+
+	g_return_val_if_fail(dat != NULL, FALSE);
+	g_return_val_if_fail(trak != NULL, FALSE);
+
+	lst = trak->offsets;
+
+	/* Find the largest elst (movie time) duration, and (media time) start time */
+	if(movie_start_ts > 0 && movie_start_ts < trak->start_ts) {
+		duration = trak->start_ts - movie_start_ts;
+		duration = NS2MOVIE(duration, dat->timescale);
+		if(duration > largest_duration)
+			largest_duration = duration;
+	}
+	while(lst) {
+		MoovTrakOffset * offset = (MoovTrakOffset*)lst->data;
+		lst = lst->next;
+		if(!offset)
+			continue;
+		if(offset->trak_offset > last_toffset) {
+			duration = offset->trak_offset - last_toffset;
+			duration = MEDIA2MOVIE(duration, dat->timescale, trak->timescale);
+			if(duration > largest_duration)
+				largest_duration = duration;
+			if(last_toffset > largest_starttime)
+				largest_starttime = last_toffset;
+		}
+		if(offset->trak_offset < trak->stts_duration) {
+			duration = MEDIA2MOVIE(offset->offset_delta,
+								   dat->timescale,
+								   trak->timescale);
+			if(duration > largest_duration)
+				largest_duration = duration;
+		}
+		last_toffset = offset->trak_offset;
+	}
+	if(last_toffset < trak->stts_duration) {
+		duration = trak->stts_duration - last_toffset;
+		duration = MEDIA2MOVIE(duration,
+							   dat->timescale,
+							   trak->timescale);
+		if(duration > largest_duration)
+			largest_duration = duration;
+		if(last_toffset > largest_starttime)
+			largest_starttime = last_toffset;
+	}
+
+	/* Find the largest (media time) start time */
+	if(largest_duration > G_MAXUINT32 || largest_starttime > G_MAXUINT32)
+		ret = TRUE;
+
+	GST_DEBUG("Largest elst duration: %llu", largest_duration);
+	GST_DEBUG("Largest elst start time: %llu", largest_starttime);
+	GST_DEBUG("Need 64bit: %d", ret);
+
+	return ret;
+}
+
+static guint atom_xml_build_edts(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+	GSList * lst;
+	guint64 last_toffset = 0;
+	guint64 total_trak_duration = 0;
+	guint entries = 0;
+	guint movie_start_ts;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+	lst = trak->offsets;
+
+	movie_start_ts = atom_moov_get_start_ts(dat);
+
+	if(!lst && trak->start_ts == movie_start_ts)
+		return 0;
+
+	if(!msend) {
+		ret += EDTS_ATOM_SIZE;
+		ret += ELST_ATOM_SIZE;
+		/* 32 or 64 bit elst atoms? */
+		dat->elst_64bit = atom_xml_edts_is_64bit(dat, trak, movie_start_ts);
+		if(dat->elst_64bit)
+			GST_WARNING("64 bit elst atom entries required, may not work in (Apple) QuickTime/iTunes");
+	}
+	else {
+		ret += msend_atom_header(msend, tsizes->edts_size, FOURCC_edts);
+		ret += msend_atom_header_full(msend, tsizes->edts_size - EDTS_ATOM_SIZE, FOURCC_elst, dat->elst_64bit?1:0, 0, 0, 0);
+		ret += msend_uint32(msend, tsizes->edts_entries); /* table entries */
+	}
+
+	/* Insert initial empty edit if needed */
+	
+	if(movie_start_ts > 0 && movie_start_ts < trak->start_ts) {
+		guint64 duration;
+		duration = trak->start_ts - movie_start_ts;
+		duration = NS2MOVIE(duration, dat->timescale);
+		ret += atom_xml_build_elst(dat, msend, trak, dat->elst_64bit,
+								   duration,
+								   -1,
+								   1 << 16);
+		entries += 1;
+		total_trak_duration += duration;
+	}
+
+	while(lst) {
+		MoovTrakOffset * offset = (MoovTrakOffset*)lst->data;
+		lst = lst->next;
+
+		if(!offset)
+			continue;
+
+		/* Insert real edit if track has advanced since last empty edit */
+		if(offset->trak_offset > last_toffset) {
+			guint64 duration = offset->trak_offset - last_toffset;
+			duration = MEDIA2MOVIE(duration, dat->timescale, trak->timescale);
+			ret += atom_xml_build_elst(dat, msend, trak, dat->elst_64bit,
+									   duration,
+									   last_toffset,
+									   1 << 16);
+			entries += 1;
+			total_trak_duration += duration;
+		}
+
+		/* Last edit should never be an empty edit */
+		if(offset->trak_offset < trak->stts_duration) {
+			guint64 duration = MEDIA2MOVIE(offset->offset_delta,
+										   dat->timescale,
+										   trak->timescale);
+			ret += atom_xml_build_elst(dat, msend, trak, dat->elst_64bit,
+									   duration,
+									   -1,
+									   1 << 16);
+			entries += 1;
+			total_trak_duration += duration;
+		}
+
+		last_toffset = offset->trak_offset;
+	}
+
+	/* Final real edit */
+	if(last_toffset < trak->stts_duration) {
+		guint64 duration = trak->stts_duration - last_toffset;
+		duration = MEDIA2MOVIE(duration,
+							   dat->timescale,
+							   trak->timescale);
+		ret += atom_xml_build_elst(dat, msend, trak, dat->elst_64bit,
+								   duration,
+								   last_toffset,
+								   1 << 16);
+		entries += 1;
+		total_trak_duration += duration;
+	}
+
+	if(!msend) {
+		tsizes->edts_size = ret;
+		tsizes->edts_entries = entries;
+		trak->edts_duration = total_trak_duration;
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->edts_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_trak(MoovDat * dat, MoovSend * msend, guint trak_index, MoovTrackSizes * tsizes)
+{
+	MoovTrak * trak;
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	trak = dat->tracks[trak_index];
+
+	if(!msend) {
+		ret = ATOM_HEADER_SIZE;
+		ret += atom_xml_build_tkhd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_edts(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_mdia(dat, msend, trak_index, tsizes);
+		tsizes->trak_size = ret;
+	}
+	else {
+		ret += msend_atom_header(msend, tsizes->trak_size, FOURCC_trak);
+		ret += atom_xml_build_tkhd(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_edts(dat, msend, trak_index, tsizes);
+		ret += atom_xml_build_mdia(dat, msend, trak_index, tsizes);
+	}
+
+	MSEND_CHECK_EXPECTED(tsizes->trak_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_mvhd(MoovDat * dat, MoovSend * msend, MoovSizes * msizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!msend) {
+		ret = (dat->mvhd_version==0) ? MVHD_ATOM_SIZE : MVHD_ATOM_SIZE + 12;
+		msizes->_mvhd_size = ret;
+	}
+	else {
+		guint32 matrix[9];
+		guint32 next_tid;
+		gboolean _64bit;
+
+		next_tid = dat->track_count + 1;
+		_64bit = (dat->mvhd_version==0) ? FALSE : TRUE;
+		memset(&matrix, 0, sizeof(matrix));
+		matrix[0] = 1 << 16;
+		matrix[4] = 1 << 16;
+		matrix[8] = 16384 << 16;
+
+		ret += msend_atom_header_full(msend, msizes->_mvhd_size, FOURCC_mvhd, dat->mvhd_version, 0, 0, 0);
+		ret += msend_atom_times(msend, dat->creation_time, dat->modification_time,
+								dat->timescale, dat->mvhd_duration, _64bit);
+		ret += msend_uint32(msend, 1 << 16);       /* preferred rate     */
+		ret += msend_uint16(msend, 1 << 8);        /* preferred volume   */
+		ret += msend_uint8_multi(msend, 0, 10);    /* reserved           */
+		ret += msend_matrix_4byte(msend, matrix, sizeof(matrix)); /* matrix     */
+		ret += msend_uint32(msend, 0);             /* preview time       */
+		ret += msend_uint32(msend, 0);             /* preview duration   */
+		ret += msend_uint32(msend, 0);             /* poster time        */
+		ret += msend_uint32(msend, 0);             /* selection time     */
+		ret += msend_uint32(msend, 0);             /* selection duration */
+		ret += msend_uint32(msend, 0);             /* current time       */
+		ret += msend_uint32(msend, next_tid);      /* next track id      */
+	}
+
+	MSEND_CHECK_EXPECTED(msizes->_mvhd_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_tag_data(MoovDat * dat, MoovSend * msend, guint fourcc, guint8 * data, guint datasize, guint flags)
+{
+	guint ret = 0;
+	guint tag_size = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+	g_return_val_if_fail(data != NULL, 0);
+	g_return_val_if_fail(datasize > 0, 0);
+
+	tag_size += ATOM_HEADER_SIZE;
+	tag_size += ATOM_HEADER_FULL_SIZE;
+	tag_size += 4; /* reserved */
+	tag_size += datasize;
+
+	if(!msend) {
+		ret = tag_size;
+	}
+	else {
+		ret += msend_atom_header(msend, tag_size, fourcc);
+		ret += msend_atom_header_full(msend,
+									  tag_size - ATOM_HEADER_SIZE,
+									  FOURCC_data,
+									  0,
+									  flags & 0xFF,
+									  flags & 0xFF00,
+									  flags & 0xFF0000);
+		ret += msend_uint32(msend, 0); /* reserved */
+		ret += msend_copy(msend, data, datasize);
+	}
+
+	return ret;
+}
+
+static guint atom_xml_build_3gp_tag(MoovDat * dat, MoovSend * msend, guint fourcc, guint8 * data, guint datasize,
+									guint8 ver, guint8 flag1, guint8 flag2, guint8 flag3, gboolean full)
+{
+	guint ret = 0;
+	guint tag_size = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+	g_return_val_if_fail(data != NULL, 0);
+	g_return_val_if_fail(datasize > 0, 0);
+
+	if(full)
+		tag_size += ATOM_HEADER_FULL_SIZE;
+	else
+		tag_size += ATOM_HEADER_SIZE;
+	tag_size += datasize;
+
+	if(!msend) {
+		ret = tag_size;
+	}
+	else {
+		if(full)
+			ret += msend_atom_header_full(msend, tag_size, fourcc, ver, flag1, flag2, flag3);
+		else
+			ret += msend_atom_header(msend, tag_size, fourcc);
+		ret += msend_copy(msend, data, datasize);
+	}
+
+	return ret;
+}
+
+static guint atom_xml_build_3gp_tag_string_int(MoovDat * dat, MoovSend * msend, guint fourcc, gchar * value, gint16 ivalue)
+{
+	guint8 * data=NULL;
+	gint size=0, len=0;
+	guint ret = 0;
+
+	if(value) {
+		len = strlen(value);
+		size = len + 3;
+	}
+	if(ivalue >= 0) {
+		size += 2;
+		if(size == 2)
+			size--;
+	}
+
+	if(msend) {
+		data = g_malloc(size + 3);
+		/* language tag and null-terminated UTF-8 string */
+		if(value) {
+			GST_WRITE_UINT16_BE(data, language_code(GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+			/* include 0 terminator */
+			memcpy(data + 2, value, len + 1);
+		}
+		/* 16-bit unsigned int if standalone, otherwise 8-bit */
+		if(ivalue >= 0) {
+			if(size == 2)
+				GST_WRITE_UINT16_BE(data + size - 2, ivalue);
+			else
+				GST_WRITE_UINT8(data + size - 2, ivalue & 0xFF);
+		}
+	}
+
+	ret = atom_xml_build_3gp_tag(dat, msend, fourcc, data, size, 0, 0, 0, 0, TRUE);
+	g_free(data);
+
+	return ret;
+}
+
+static guint atom_xml_build_3gp_tag_location(MoovDat * dat, MoovSend * msend, guint fourcc,
+											 gchar * loc, gdouble lat, gdouble lon, gdouble alt)
+{
+	gint size = 0, len = 0;
+	guint8 *data=NULL, *ddata=NULL;
+	guint ret=0;
+
+	if(loc)
+		len = strlen(loc);
+	size += len + 1 + 2;
+
+	/* role + (long, lat, alt) + body + notes */
+	size += 1 + 3 * 4 + 1 + 1;
+
+	if(msend) {
+		data = ddata = g_malloc(size);
+
+		GST_WRITE_UINT16_BE(data, language_code(GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+		if(loc)
+			memcpy(data + 2, loc, len);
+		GST_WRITE_UINT8(data + 2 + len, 0);
+		data += len + 1 + 2;
+		/* role */
+		GST_WRITE_UINT8(data, 0);
+		/* long, lat, alt */
+		GST_WRITE_UINT32_BE(data + 1, (guint32) (lon * 65536.0));
+		GST_WRITE_UINT32_BE(data + 5, (guint32) (lat * 65536.0));
+		GST_WRITE_UINT32_BE(data + 9, (guint32) (alt * 65536.0));
+		/* neither astronomical body nor notes */
+		GST_WRITE_UINT16_BE(data + 13, 0);
+	}
+
+	ret = atom_xml_build_3gp_tag(dat, msend, fourcc, ddata, size, 0, 0, 0, 0, TRUE);
+	g_free(ddata);
+
+	return ret;
+}
+
+static guint atom_xml_build_3gp_tag_keywords(MoovDat * dat, MoovSend * msend)
+{
+	GSList * lst;
+	guint ret=0, size=0;
+	guint8 cnt=0;
+	guint fourcc = 0;
+	gchar * lang = NULL;
+	guint8 *data=NULL, *ddata=NULL;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!dat->keywords)
+		return 0;
+
+	lst = dat->keywords;
+	while(lst) {
+		MoovTag3GPKeyword * tag = (MoovTag3GPKeyword*)lst->data;
+		lst = lst->next;
+		if(!tag)
+			continue;
+		if(tag->type != TAG_3GP_KEYWORD) {
+			GST_ERROR("Expected keyword tag");
+			continue;
+		}
+		if(!tag->keyword) {
+			GST_ERROR("NULL keyword tag");
+			continue;
+		}
+		if(fourcc == 0)
+			fourcc = tag->fourcc;
+		if(!lang && tag->language)
+			lang = tag->language;
+		size += strlen(tag->keyword) + 1 + 1;
+		cnt += 1;
+	}
+
+	/* language tag + count + keywords */
+	size += 2 + 1;
+
+	if(msend) {
+		data = ddata = g_malloc(size);
+
+		/* language tag */
+		GST_WRITE_UINT16_BE(data, ((lang!=NULL) ? language_code(lang) : 0));
+		/* count */
+		GST_WRITE_UINT8(data + 2, cnt);
+		data += 3;
+
+		lst = dat->keywords;
+		while(lst) {
+			MoovTag3GPKeyword * tag = (MoovTag3GPKeyword*)lst->data;
+			gint len;
+			lst = lst->next;
+			if(!tag)
+				continue;
+			if(tag->type != TAG_3GP_KEYWORD) {
+				GST_ERROR("Expected keyword tag");
+				continue;
+			}
+			if(!tag->keyword) {
+				GST_ERROR("NULL keyword tag");
+				continue;
+			}
+			len = strlen(tag->keyword);
+			/* size */
+			GST_WRITE_UINT8(data, len + 1);
+			memcpy(data + 1, tag->keyword, len + 1);
+			data += len + 2;
+		}
+	}
+
+	ret = atom_xml_build_3gp_tag(dat, msend, fourcc, ddata, size, 0, 0, 0, 0, TRUE);
+	g_free(ddata);
+
+	return size;
+}
+
+static guint atom_xml_build_tags(MoovDat * dat, MoovSend * msend)
+{
+	guint ret = 0;
+	GSList * lst;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!dat->taglist && !dat->keywords)
+		return 0;
+
+	lst = dat->taglist;
+	while(lst) {
+		MoovTag * tag = (MoovTag*)lst->data;
+		lst = lst->next;
+		if(!tag)
+			continue;
+
+		switch(tag->type) {
+		case TAG_DATA:
+			ret += atom_xml_build_tag_data(dat, msend,
+										   MOOV_TAG_DATA(tag)->fourcc,
+										   MOOV_TAG_DATA(tag)->data,
+										   MOOV_TAG_DATA(tag)->size,
+										   MOOV_TAG_DATA(tag)->flags);
+			break;
+		case TAG_STRING:
+			ret += atom_xml_build_tag_data(dat, msend,
+										   MOOV_TAG_STRING(tag)->fourcc,
+										   (guint8*)MOOV_TAG_STRING(tag)->value,
+										   MOOV_TAG_STRING(tag)->value?strlen(MOOV_TAG_STRING(tag)->value):0,
+										   METADATA_TEXT_FLAG);
+			break;
+		case TAG_UINT32: {
+			guint8 data[8] = { 0, };
+			gint size;
+			if(MOOV_TAG_UINT32(tag)->flags) {
+				GST_WRITE_UINT16_BE(data, MOOV_TAG_UINT32(tag)->value);
+				size = 2;
+			}
+			else {
+				GST_WRITE_UINT32_BE(data+2, MOOV_TAG_UINT32(tag)->value);
+				size = 8;
+			}
+			ret += atom_xml_build_tag_data(dat, msend,
+										   MOOV_TAG_UINT32(tag)->fourcc,
+										   data, 
+										   size,
+										   MOOV_TAG_UINT32(tag)->flags);
+			break;
+		}
+		case TAG_3GP_STR_INT:
+			ret += atom_xml_build_3gp_tag_string_int(dat, msend,
+													 MOOV_TAG_3GP_STRING_INT(tag)->fourcc,
+													 MOOV_TAG_3GP_STRING_INT(tag)->value,
+													 MOOV_TAG_3GP_STRING_INT(tag)->ivalue);
+			break;
+		case TAG_3GP_STR:
+			ret += atom_xml_build_3gp_tag_string_int(dat, msend,
+													 MOOV_TAG_3GP_STRING_INT(tag)->fourcc,
+													 MOOV_TAG_3GP_STRING_INT(tag)->value,
+													 -1);
+			break;
+		case TAG_3GP_UINT:
+			ret += atom_xml_build_3gp_tag_string_int(dat, msend,
+													 MOOV_TAG_3GP_UINT(tag)->fourcc,
+													 NULL,
+													 MOOV_TAG_3GP_UINT(tag)->value);
+			break;
+		case TAG_3GP_LOCATION:
+			ret += atom_xml_build_3gp_tag_location(dat, msend,
+												   MOOV_TAG_3GP_LOCATION(tag)->fourcc,
+												   MOOV_TAG_3GP_LOCATION(tag)->location,
+												   MOOV_TAG_3GP_LOCATION(tag)->latitude,
+												   MOOV_TAG_3GP_LOCATION(tag)->longitude,
+												   MOOV_TAG_3GP_LOCATION(tag)->altitude);
+			break;
+		case TAG_BLOB: {
+			guint len;
+			guint32 fourcc;
+			if(MOOV_TAG_BLOB(tag)->size < 8 || !MOOV_TAG_BLOB(tag)->data) {
+				GST_ERROR("blob tag error. NULL data or size is less than 8");
+				break;
+			}
+			len = GST_READ_UINT32_BE(MOOV_TAG_BLOB(tag)->data);
+			fourcc = GST_READ_UINT32_LE(MOOV_TAG_BLOB(tag)->data + 4);
+			if(len > MOOV_TAG_BLOB(tag)->size) {
+				GST_ERROR("blob tag error. len > size");
+				break;
+			}
+			ret += atom_xml_build_3gp_tag(dat, msend,
+										  fourcc,
+										  MOOV_TAG_BLOB(tag)->data + 8,
+										  len - 8,
+										  0, 0, 0, 0, FALSE);
+			break;
+		}
+		case TAG_UNKNOWN:
+		case TAG_3GP_KEYWORD: /* Handled below */
+			break;
+		}
+	}
+
+	ret += atom_xml_build_3gp_tag_keywords(dat, msend);
+
+	return ret;
+}
+
+static guint atom_xml_build_ilst(MoovDat * dat, MoovSend * msend, MoovSizes * msizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!msend)
+		ret += ATOM_HEADER_SIZE;
+	else
+		ret += msend_atom_header(msend, msizes->___ilst_size, FOURCC_ilst);
+
+	ret += atom_xml_build_tags(dat, msend);
+
+	if(!msend)
+		msizes->___ilst_size = ret;
+
+	MSEND_CHECK_EXPECTED(msizes->___ilst_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_meta_hdlr(MoovDat * dat, MoovSend * msend, MoovSizes * msizes)
+{
+	guint ret = 0;
+	gint hdlr_size;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	hdlr_size = HDLR_ATOM_SIZE + 1; /* NULL terminated string */
+
+	if(!msend) {
+		ret = hdlr_size;
+	}
+	else {
+		ret += msend_atom_header_full(msend, hdlr_size, FOURCC_hdlr, 0, 0, 0, 0);
+		ret += msend_fourcc(msend,  FOURCC_mhlr);
+		ret += msend_fourcc(msend, FOURCC_mdir);
+		ret += msend_uint32(msend, 0); /* manufacturer    */
+		ret += msend_uint32(msend, 0); /* component flags */
+		ret += msend_uint32(msend, 0); /* flags mask      */
+		ret += msend_copy(msend, "", 1);
+	}
+
+	return ret;
+}
+
+static guint atom_xml_build_meta(MoovDat * dat, MoovSend * msend, MoovSizes * msizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!msend)
+		ret += ATOM_HEADER_FULL_SIZE;
+	else
+		ret += msend_atom_header_full(msend, msizes->__meta_size, FOURCC_meta, 0, 0, 0, 0);
+
+	ret += atom_xml_build_meta_hdlr(dat, msend, msizes);
+	ret += atom_xml_build_ilst(dat, msend, msizes);
+
+	if(!msend)
+		msizes->__meta_size = ret;
+
+	MSEND_CHECK_EXPECTED(msizes->__meta_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_udta(MoovDat * dat, MoovSend * msend, MoovSizes * msizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!dat->taglist && !dat->keywords)
+		return 0;
+
+	if(!msend)
+		ret += ATOM_HEADER_SIZE;
+	else
+		ret += msend_atom_header(msend, msizes->_udta_size, FOURCC_udta);
+
+	if(dat->flavor != ATOMS_TREE_FLAVOR_3GP)
+		ret += atom_xml_build_meta(dat, msend, msizes);
+	else
+		ret += atom_xml_build_tags(dat, msend);
+
+	if(!msend)
+		msizes->_udta_size = ret;
+
+	MSEND_CHECK_EXPECTED(msizes->_udta_size, ret, NULL);
+
+	return ret;
+}
+
+static guint atom_xml_build_moov(MoovDat * dat, MoovSend * msend, MoovSizes * msizes)
+{
+	guint ret = 0;
+
+	g_return_val_if_fail(dat != NULL, 0);
+
+	if(!msend) {
+		gint i;
+		msizes->moov_size = ATOM_HEADER_SIZE;
+		msizes->moov_size += atom_xml_build_mvhd(dat, msend, msizes);
+		for(i=0;i<MAX_TRACKS;i++) {
+			if(!dat->tracks[i])
+				continue;
+			msizes->trak_sizes[i] = g_new0(MoovTrackSizes, 1);
+			msizes->moov_size += atom_xml_build_trak(dat, msend, i, msizes->trak_sizes[i]);
+		}
+		msizes->moov_size += atom_xml_build_udta(dat, msend, msizes);
+		ret = msizes->moov_size;
+	}
+	else {
+		gint i;
+		ret += msend_atom_header(msend, msizes->moov_size, FOURCC_moov);
+		ret += atom_xml_build_mvhd(dat, msend, msizes);
+		for(i=0;i<MAX_TRACKS;i++) {
+			if(!msizes->trak_sizes[i])
+				continue;
+			ret += atom_xml_build_trak(dat, msend, i, msizes->trak_sizes[i]);
+		}
+		ret += atom_xml_build_udta(dat, msend, msizes);
+	}
+
+	MSEND_CHECK_EXPECTED(msizes->moov_size, ret, NULL);
+
+	return ret;
+}
+
+static gboolean atom_xml_moov_send(MoovDat * dat, AtomMoovSendDataCB send_cb, gpointer user_data)
+{
+	MoovSizes * msizes;
+	MoovSend * msend;
+	gint i;
+	guint64 duration=0;
+
+	g_return_val_if_fail(dat != NULL, FALSE);
+	g_return_val_if_fail(send_cb != NULL, FALSE);
+
+	msizes = g_new0(MoovSizes, 1);
+	msend = g_new0(MoovSend, 1);
+	msend->send_cb = send_cb;
+	msend->user_data = user_data;
+
+	/* Collect atom sizes */
+	atom_xml_build_moov(dat, NULL, msizes);
+
+	GST_INFO("MOOV ATOM SIZE: %u", msizes->moov_size);
+
+	/* Reset durations for tracks using edit lists */
+	for(i=0;i<MAX_TRACKS;i++) {
+		if(dat->tracks[i] == NULL)
+			continue;
+		if(dat->tracks[i]->edts_duration > 0) {
+			GST_DEBUG("Updating trak duration with edit list duration: %llu to %llu",
+					 MOVIE2NS(dat->tracks[i]->tkhd_duration, dat->timescale),
+					 MOVIE2NS(dat->tracks[i]->edts_duration, dat->timescale));
+			dat->tracks[i]->tkhd_duration = dat->tracks[i]->edts_duration;
+		}
+		if(dat->tracks[i]->tkhd_duration > duration)
+			duration = dat->tracks[i]->tkhd_duration;
+	}
+	dat->mvhd_duration = duration;
+
+	/* Now build and send moov atom */
+	atom_xml_build_moov(dat, msend, msizes);
+
+	/* Send remaining data in msend */
+	if(msend->buffer != NULL) {
+		guint buf_size = msend->buf_size - msend->bptr_size;
+		msend->send_cb(msend->user_data, msend->buffer, buf_size);
+		msend->buffer = NULL;
+		msend->buf_size = 0;
+	}
+
+	GST_INFO("DONE SENDING MOOV");
+
+	/* free size data */
+	for(i=0;i<MAX_TRACKS;i++) {
+		if(msizes->trak_sizes[i])
+			g_free(msizes->trak_sizes[i]);
+	}
+	g_free(msizes);
+
+	return TRUE;
+}
+
+
+/** Exported Utility Functions **/
+
+static char base64_charset[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+guint8 * atom_moov_base64_decode(const gchar * buf, guint * size)
+{
+	char *res, *save, *foo, val;
+	const char *end;
+	int index;
+
+	if (!buf)
+		return NULL;
+
+	index = strlen(buf)*6 / 8 + 1;
+	save = res = g_malloc(index);
+	memset(res, 0, index);
+	if(size)
+		*size = index;
+	index = 0;
+
+	if (!save)
+		return NULL;
+
+	end = buf + strlen(buf);
+
+	while (*buf && buf < end) {
+		if (!(foo = strchr(base64_charset, *buf)))
+			foo = base64_charset;
+		val = (int)(foo - base64_charset);
+		buf++;
+		switch (index) {
+			case 0:
+				*res |= val << 2;
+				break;
+			case 1:
+				*res++ |= val >> 4;
+				*res |= val << 4;
+				break;
+			case 2:
+				*res++ |= val >> 2;
+				*res |= val << 6;
+				break;
+			case 3:
+				*res++ |= val;
+				break;
+		}
+		index++;
+		index %= 4;
+	}
+	*res = 0;
+
+	return (guint8*)save;
+}
+
+gchar * atom_moov_base64_encode(const guint8 * buf, guint len)
+{
+	char *res, *save;
+	int k, t;
+
+	g_return_val_if_fail(buf != NULL, NULL);
+	g_return_val_if_fail(len > 0, NULL);
+
+	save = res = g_malloc((len*8) / 6 + 4);
+
+	for (k = 0; k < len/3; ++k) {
+		*res++ = base64_charset[*buf >> 2];
+		t = ((*buf & 0x03) << 4);
+		buf++;
+		*res++ = base64_charset[t | (*buf >> 4)];
+		t = ((*buf & 0x0F) << 2);
+		buf++;
+		*res++ = base64_charset[t | (*buf >> 6)];
+		*res++ = base64_charset[*buf++ & 0x3F];
+	}
+
+	switch (len % 3) {
+		case 2:
+			*res++ = base64_charset[*buf >> 2];
+			t =  ((*buf & 0x03) << 4);
+			buf++;
+			*res++ = base64_charset[t | (*buf >> 4)];
+			*res++ = base64_charset[((*buf++ & 0x0F) << 2)];
+			break;
+		case 1:
+			*res++ = base64_charset[*buf >> 2];
+			*res++ = base64_charset[(*buf++ & 0x03) << 4];
+			break;
+	}
+	*res++ = '=';
+	*res++ = '=';
+	*res = 0;
+	return save;
+}
Index: gst/qtmux/atom-context-xml.c
===================================================================
--- gst/qtmux/atom-context-xml.c	(revision 0)
+++ gst/qtmux/atom-context-xml.c	(revision 476)
@@ -0,0 +1,448 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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.
+ */
+#include <gst/gst.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include "atom-context.h"
+#include "atom-moov-xml.h"
+#include "properties.h"
+#include "fourcc.h"
+#include "ftypcc.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_qtmux_atom_ctx_debug);
+#define GST_CAT_DEFAULT gst_qtmux_atom_ctx_debug
+
+#define D(ctx) ctx->dbg_elem
+#define SEND(ctx, data, size) ctx->send_cb(ctx->send_data, data, size)
+
+
+struct _AtomContext
+{
+	FILE *            fd;
+	AtomsTreeFlavor   flavor;
+	guint32           timescale;
+	gchar *           prop_filename;
+	gchar *           used_filename;
+
+	/* Session State */
+	gboolean          started;
+	guint             next_trak_id;
+
+	/* Data Send */
+	AtomCtxSendDataCB send_cb;
+	AtomCtxProcPingCB ping_cb;
+	gpointer send_data;
+};
+
+
+
+/** Private Atom Context Code **/
+
+static gchar * atom_ctx_default_xml_file()
+{
+	gchar *tmp, *ret;
+	tmp = g_strdup_printf("qtmux-moov-backup-%u.xml", (guint)g_random_int()); 
+	ret =  g_build_filename(g_get_tmp_dir(), tmp, NULL);
+	g_free(tmp);
+	return ret;
+}
+
+/** Public Atom Context Code **/
+
+AtomContext * atom_ctx_new(AtomsTreeFlavor flavor, AtomCtxSendDataCB send_cb, AtomCtxProcPingCB ping_cb, gpointer user_data)
+{
+	AtomContext * ret;
+
+	GST_INFO("Atom Context Reset");
+
+	ret = g_new0(AtomContext, 1);
+	ret->flavor = flavor;
+	ret->send_cb = send_cb;
+	ret->ping_cb = ping_cb;
+	ret->send_data = user_data;
+	ret->started = FALSE;
+	ret->next_trak_id = 1;
+
+	return ret;
+}
+
+void atom_ctx_free(AtomContext * context)
+{
+	if(context->fd)
+		fclose(context->fd);
+	g_free(context->prop_filename);
+	g_free(context->used_filename);
+	g_free(context);
+}
+
+void atom_ctx_reset(AtomContext * context)
+{
+	g_return_if_fail(context != NULL);
+
+	GST_INFO("Atom Context Reset");
+
+	if(context->fd)
+		fclose(context->fd);
+	context->fd = NULL;
+	context->started = FALSE;
+	context->next_trak_id = 1;
+}
+
+void atom_ctx_timescale_set(AtomContext * context, guint32 timescale)
+{
+	g_return_if_fail(context != NULL);
+	context->timescale = timescale;
+}
+
+void atom_ctx_filename_set(AtomContext * context, const gchar * filename)
+{
+	g_return_if_fail(context != NULL);
+
+	g_free(context->prop_filename);
+	context->prop_filename = NULL;
+
+	if(filename)
+		context->prop_filename = g_strdup(filename);
+}
+
+void atom_ctx_start(AtomContext * context)
+{
+	g_return_if_fail(context != NULL);
+
+	if(context->started)
+		return;
+
+	GST_INFO("Started..");
+
+	g_return_if_fail(context->fd == NULL);
+
+	g_free(context->used_filename);
+	context->used_filename = NULL;
+
+	if(context->prop_filename)
+		context->used_filename = g_strdup(context->prop_filename);
+	else
+		context->used_filename = atom_ctx_default_xml_file();
+
+	context->fd = fopen(context->used_filename, "w");
+
+	g_fprintf(context->fd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+
+	/* NOTE: Update version if tag/values change */
+	g_fprintf(context->fd, "<MOOV VERSION='1' FLAVOR='%u' TIMESCALE='%u'>\n",
+			  context->flavor,
+			  context->timescale);
+	fflush(context->fd);
+
+	context->started = TRUE;
+}
+
+guint atom_ctx_track_add(AtomContext * context)
+{
+	g_return_val_if_fail(context != NULL, 0);
+	return context->next_trak_id++;
+}
+
+void atom_ctx_track_audio_set(AtomContext * context, guint trak_id, AtomContextAudioEntry * entry)
+{
+	gchar * codec_data_b64 = NULL;
+	guint cdat_size = 0;
+
+	g_return_if_fail(context != NULL);
+	g_return_if_fail(entry != NULL);
+
+	atom_ctx_start(context);
+
+	/* base64 encode codec data */
+	if(entry->codec_data) {
+		codec_data_b64 = atom_moov_base64_encode(entry->codec_data, entry->codec_data_size);
+		cdat_size = entry->codec_data_size;
+	}
+
+	g_fprintf(context->fd,
+			  "<AT IX='%u' TS='%u' RI='%u' FCC='%u' VR='%hu' CI='%hu' "
+			  "SS='%hu' CH='%hu' SPP='%u' BPS='%u' BPP='%u' BPF='%u' FSS='%u' AEXT='%u' "
+			  "CDAT='%s' CDATSIZE='%u'/>\n",
+			  trak_id, entry->sample_rate, 1, entry->fourcc, entry->version, entry->compression_id,
+			  entry->sample_size, entry->channels, entry->samples_per_packet, entry->bytes_per_sample,
+			  entry->bytes_per_packet, entry->bytes_per_frame, entry->sample_fixed_size,
+			  entry->audio_ext, codec_data_b64?codec_data_b64:"", cdat_size);
+	fflush(context->fd);
+	g_free(codec_data_b64);
+}
+
+void atom_ctx_track_video_set(AtomContext * context, guint trak_id, AtomContextVisualEntry * entry)
+{
+	gchar * codec_data_b64 = NULL;
+	guint cdat_size = 0;
+
+	g_return_if_fail(context != NULL);
+	g_return_if_fail(entry != NULL);
+
+	atom_ctx_start(context);
+
+	/* base64 encode codec data */
+	if(entry->codec_data) {
+		codec_data_b64 = atom_moov_base64_encode(entry->codec_data, entry->codec_data_size);
+		cdat_size = entry->codec_data_size;
+	}
+
+	g_fprintf(context->fd,
+			  "<VT IX='%u' TS='%u' RI='%u' FCC='%u' SFCC='%u' FN='%u' FD='%u' "
+			  "W='%u' H='%u' DP='%u' CTID='%u' FC='%u' VEXT='%u' CDAT='%s' CDATSIZE='%u'/>\n",
+			  trak_id, entry->timescale, 1, entry->fourcc, entry->sub_fourcc, entry->par_n,
+			  entry->par_d, entry->width, entry->height, entry->depth, entry->color_table_id,
+			  entry->frame_count, entry->visual_ext, codec_data_b64?codec_data_b64:"", cdat_size);
+	fflush(context->fd);
+	g_free(codec_data_b64);
+}
+
+void atom_ctx_samples_add(AtomContext * context, guint trak_id, guint32 nsamples, guint32 delta, guint32 size,
+						  guint64 chunk_offset, gboolean sync, gboolean do_pts, gint64 pts_offset)
+{
+	g_return_if_fail(context != NULL);
+	g_return_if_fail(context->fd != NULL);
+
+	g_fprintf(context->fd,
+			  "<TC I='%u' N='%u' D='%u' S='%u' C='%llu' Y='%u' P='%u' O='%lld'/>\n",
+			  trak_id, nsamples, delta, size, chunk_offset, sync, do_pts, pts_offset);
+	fflush(context->fd);
+}
+
+void atom_ctx_start_ts_add(AtomContext * context, guint trak_id, guint64 start_ts)
+{
+	g_return_if_fail(context != NULL);
+	g_return_if_fail(context->fd != NULL);
+
+	g_fprintf(context->fd, "<TS I='%u' S='%llu'/>\n", trak_id, start_ts);
+	fflush(context->fd);
+}
+
+gboolean atom_ctx_ftyp_send(AtomContext * context, guint32 major, guint32 version, GList * brands, guint64 * bytes_sent)
+{
+	guint32 size = 0;
+	guint64 offset = 0;
+	guint64 dsize = 0;
+	guint8 * data = NULL;
+	
+	GST_INFO("Sending ftyp atom");
+
+	size = 20;
+	if(brands)
+		size += (g_list_length(brands)*4);
+
+	/* type & size */
+	prop_copy_uint32(size, &data, &dsize, &offset);
+	prop_copy_fourcc(FOURCC_ftyp, &data, &dsize, &offset);
+	/* major brand */
+	prop_copy_fourcc(major, &data, &dsize, &offset);
+	prop_copy_uint32(version, &data, &dsize, &offset);
+	/* Compatible brands - Major is at index 0 */
+	prop_copy_fourcc(major, &data, &dsize, &offset);
+	/* brands list */
+	while(brands) {
+		prop_copy_fourcc((guint32)brands->data, &data, &dsize, &offset);
+		brands = brands->next;
+	}
+
+	if(SEND(context, data, offset)) {
+		if(bytes_sent)
+			*bytes_sent += offset;
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean atom_ctx_mdat_header_send(AtomContext * context, guint64 mdat_size, guint64 * bytes_sent)
+{
+	guint32 psize = 0;
+	guint64 offset = 0;
+	guint64 dsize = 0;
+	guint8 * data = NULL;
+
+	GST_INFO("Sending mdat header. Size: '%llu'", mdat_size);
+
+	/* Include header */
+	mdat_size += 8;
+
+	psize = (mdat_size > G_MAXUINT32) ? 1 : (guint32)mdat_size;
+
+	if(psize != 1) {
+		prop_copy_uint32(8, &data, &dsize, &offset);
+		prop_copy_fourcc(FOURCC_free, &data, &dsize, &offset);
+	}
+	prop_copy_uint32(psize, &data, &dsize, &offset);
+	prop_copy_fourcc(FOURCC_mdat, &data, &dsize, &offset);
+	if(psize == 1) {
+		/* Increase header size for 64bit extension */
+		mdat_size += 8;
+		prop_copy_uint64(mdat_size, &data, &dsize, &offset);
+	}
+
+	if(SEND(context, data, offset)) {
+		if(bytes_sent)
+			*bytes_sent += offset;
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean atom_ctx_moov_send(AtomContext * context, guint64 mdat_pos, gboolean largefile, gboolean keep_xml_file, guint64 * bytes_sent)
+{
+	guint64 chunk_offset;
+	gboolean ret;
+	guint64 duration = 0;
+
+	g_return_val_if_fail(context != NULL, FALSE);
+
+	g_fprintf(context->fd, "</MOOV>\n");
+	fclose(context->fd);
+	context->fd = NULL;
+
+	g_return_val_if_fail(context->used_filename != NULL, FALSE);
+
+	/* Our moov chunk offset is always mdat position + 16
+	 * (either free:8 + mdat:8 or mdat:16 
+	 */
+	chunk_offset = mdat_pos + 16;
+
+	ret = atom_moov_process(context->used_filename,
+							chunk_offset,
+							largefile,
+							bytes_sent,
+							&duration,
+							keep_xml_file,
+							context->send_cb,
+							context->ping_cb,
+							context->send_data);
+
+	return ret;
+}
+
+/** Tags .. **/
+
+void atom_ctx_tag_add(AtomContext * context, guint32 fourcc, guint32 flags, const guint8 * data, guint size)
+{
+	gchar * b64 = "", *_b64=NULL;
+
+	if(data)
+		b64 = _b64 = atom_moov_base64_encode(data, size);
+	else
+		size = 0;
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_DATA' FOURCC='%u' FLAGS='%u' DATA='%s' SIZE='%u'/>\n",
+			  fourcc, flags, b64, size);
+	fflush(context->fd);
+	g_free(_b64);
+}
+
+void atom_ctx_tag_str_add(AtomContext * context, guint32 fourcc, const gchar *value)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_STRING' FOURCC='%u' STR_VAL='%s'/>\n", fourcc, value?value:"");
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_uint_add(AtomContext * context, guint32 fourcc, guint32 flags, guint32 value)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_UINT32' FOURCC='%u' FLAGS='%u' UINT32_VAL='%u'/>\n",
+			  fourcc, flags, value);
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_3gp_str_add(AtomContext * context, guint32 fourcc, const gchar * value)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_3GP_STR' FOURCC='%u' STR_VAL='%s'/>\n", fourcc, value);
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_3gp_str_int_add(AtomContext * context, guint32 fourcc, const gchar * value, gint16 ivalue)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_3GP_STR_INT' FOURCC='%u' STR_VAL='%s' INT16_VAL='%d'/>\n", fourcc, value, ivalue);
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_3gp_uint_add(AtomContext * context, guint32 fourcc, guint16 value)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_3GP_UINT' FOURCC='%u' UINT16_VAL='%u'/>\n", fourcc, value);
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_3gp_location_add(AtomContext * context, guint32 fourcc, const gchar * location,
+								   gdouble latitude, gdouble longitude, gdouble altitude)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_3GP_LOCATION' FOURCC='%u' LOC='%s' LAT='%lf' LONG='%lf' ALT='%lf'/>\n",
+			  fourcc, location?location:"", latitude, longitude, altitude);
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_3gp_keyword_add(AtomContext * context, const gchar * lang, const gchar * keyword, guint32 fourcc)
+{
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_3GP_KEYWORD' LANG='%s' KEY='%s' FOURCC='%u'/>\n",
+			  lang?lang:"", keyword?keyword:"", fourcc);
+	fflush(context->fd);
+}
+
+void atom_ctx_tag_blob_add(AtomContext * context, guint8 * data, guint size)
+{
+	gchar * b64 = "", *_b64=NULL;
+	if(data)
+		b64 = _b64 = atom_moov_base64_encode(data, size);
+	else
+		size = 0;
+	g_fprintf(context->fd,
+			  "<TAG TYPE='TAG_BLOB' DATA='%s' SIZE='%u'/>\n", b64, size);
+	fflush(context->fd);
+	g_free(_b64);
+}
+
+
Index: gst/qtmux/atom-moov-xml.h
===================================================================
--- gst/qtmux/atom-moov-xml.h	(revision 0)
+++ gst/qtmux/atom-moov-xml.h	(revision 476)
@@ -0,0 +1,62 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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 _ATOM_MOOV_XML_H_
+#define _ATOM_MOOV_XML_H_
+#include <glib.h>
+#include <gst/gst.h>
+
+typedef gboolean (*AtomMoovSendDataCB)(gpointer userdata, guint8 * data, guint size);
+typedef void     (*AtomMoovProcPingCB)(gpointer userdata);
+
+gboolean atom_moov_process(const gchar * filename,
+						   guint64 chunk_offset, gboolean largefile, guint64 * bsent, guint64 * duration,
+						   gboolean keep_xml_file, AtomMoovSendDataCB cb, AtomMoovProcPingCB ping_cb, gpointer user_data);
+
+gboolean atom_moov_mdat_size_get(const gchar * filename, guint64 * mdat_size);
+
+guint8 * atom_moov_base64_decode(const gchar * buf, guint * size);
+gchar *  atom_moov_base64_encode(const guint8 * buf, guint len);
+
+
+#endif /* _ATOM_MOOV_XML_H_ */
Index: gst/qtmux/gstqtmuxrecover.c
===================================================================
--- gst/qtmux/gstqtmuxrecover.c	(revision 0)
+++ gst/qtmux/gstqtmuxrecover.c	(revision 476)
@@ -0,0 +1,308 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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.
+ */
+#include <stdio.h>
+#include <gmodule.h>
+#include <gst/gst.h>
+#include "gstqtmuxrecover.h"
+#include "atom-moov-xml.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_qtmux_atom_ctx_debug);
+#define GST_CAT_DEFAULT gst_qtmux_atom_ctx_debug
+
+#define ATOM_HDR_SIZE          (sizeof(guint32)*2)
+
+/** Atom parse functions **/
+
+static gboolean qtfix_read_bytes(FILE * fd, gpointer dest, size_t bytes, size_t * bytes_read)
+{
+	size_t retval;
+	gboolean ret = TRUE;
+
+	retval = fread(dest, sizeof(char), bytes, fd);
+	if(retval < bytes) {
+		if(feof(fd) == 0) {
+			GST_ERROR("Read only '%d' of '%d' bytes", retval, bytes);
+		}
+		ret = FALSE;
+	}
+	if(bytes_read)
+		*bytes_read = retval;
+	return ret;
+}
+
+static gboolean qtfix_read_uint32(FILE * fd, guint * dest, gboolean to_host_endian)
+{
+	g_return_val_if_fail(fd != NULL, FALSE);
+	g_return_val_if_fail(dest != NULL, FALSE);
+	if(qtfix_read_bytes(fd, dest, sizeof(guint), NULL)) {
+		if(to_host_endian)
+			*dest = GUINT32_FROM_BE(*dest);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean qtfix_read_uint64(FILE * fd, guint64 * dest, gboolean to_host_endian)
+{
+	g_return_val_if_fail(fd != NULL, FALSE);
+	g_return_val_if_fail(dest != NULL, FALSE);
+	if(qtfix_read_bytes(fd, dest, sizeof(guint64), NULL)) {
+		if(to_host_endian)
+			*dest = GUINT64_FROM_BE(*dest);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean qtfix_parse_next_atom(FILE * fd, guint64 * rsize, guint * rtype, guint64 * wsize, guint64 * pos, gboolean * is_extended)
+{
+	guint64 ret_size=0, seek_to=0;
+	guint size=0, type=0;
+	gboolean ret = FALSE;
+	size_t fdpos;
+
+	g_return_val_if_fail(fd != NULL, FALSE);
+	g_return_val_if_fail(rsize != NULL, FALSE);
+	g_return_val_if_fail(rtype != NULL, FALSE);
+
+	fdpos = ftell(fd);
+
+	if(!qtfix_read_uint32(fd, &size, TRUE))
+		goto end;
+	if(!qtfix_read_uint32(fd, &type, FALSE))
+		goto end;
+
+	GST_DEBUG("TYPE STR: %"GST_FOURCC_FORMAT " SIZE: %u @ POS: %d",
+			  GST_FOURCC_ARGS(type), size, fdpos);
+
+	/* Should we read 64 bit size? */
+	if(size == 1) {
+		if(!qtfix_read_uint64(fd, &ret_size, TRUE))
+			goto end;
+		GST_DEBUG("BIG SIZE: %llu", ret_size);
+		if(is_extended)
+			*is_extended = TRUE;
+		if(ret_size < (ATOM_HDR_SIZE*2)) {
+			GST_ERROR("ATOM SIZE (64bit) NOT BIG ENOUGH: %llu", ret_size);
+			goto end;
+		}
+		seek_to = ret_size - (ATOM_HDR_SIZE*2);
+	}
+	else {
+		if(is_extended)
+			*is_extended = FALSE;
+		if(size < ATOM_HDR_SIZE) {
+			GST_ERROR("ATOM SIZE (32bit) NOT BIG ENOUGH: %u", size);
+			goto end;
+		}
+		ret_size = size;
+		seek_to = size - ATOM_HDR_SIZE;
+	}
+
+	/* Return size of data only i.e from cur pos to end of atom */
+	*rsize = seek_to;
+	*rtype = type;
+	if(wsize)
+		*wsize = ret_size;
+	if(pos)
+		*pos = fdpos;
+
+	ret = TRUE;
+
+ end:
+	return ret;
+}
+
+static gboolean gst_qt_mux_recover_write_cb(gpointer userdata, guint8 * data, guint size)
+{
+	FILE * fd = (FILE*)userdata;
+	gboolean ret = FALSE;
+
+	g_return_val_if_fail(fd != NULL, FALSE);
+	g_return_val_if_fail(data != NULL, FALSE);
+
+	GST_DEBUG("Writing %u bytes to file", size);
+
+	if(fwrite(data, 1, size, fd) != size) {
+		GST_ERROR("Failed to write %u bytes", size);
+		ret = FALSE;
+		goto end;
+	}
+	ret = TRUE;
+ end:
+	g_free(data);
+	return ret;
+}
+
+gboolean gst_qt_mux_recover(const gchar * qtfile, const gchar * qtxmlfile, guint64 * duration)
+{
+	FILE * fd=NULL;
+	guint64 size=0, pos=0;
+	guint type=0;
+	gboolean has_mdat=FALSE, has_moov=FALSE, has_free=FALSE;
+	guint64 mdat_size=0, mdat_pos=0, free_pos=0, xmlmdatsize=0, end_pos=0;
+	gboolean is_ext = FALSE;
+	gboolean mdat_is_ext = FALSE;
+	guint64 chunk_offset = 0, bsent=0;
+	gboolean ret = FALSE, parse_stop = FALSE;
+	gboolean largefile;
+	guint32 dat32;
+	guint64 dat64;
+
+	g_return_val_if_fail(qtfile != NULL, FALSE);
+	g_return_val_if_fail(qtxmlfile != NULL, FALSE);
+
+	fd = fopen(qtfile, "r+");
+	if(!fd) {
+		GST_ERROR("Could not open '%s'", qtfile);
+		return FALSE;
+	}
+
+	if(!atom_moov_mdat_size_get(qtxmlfile, &xmlmdatsize)) {
+		GST_ERROR("Failed to determine mdat size from xml file");
+		goto end;
+	}
+
+	while(!parse_stop && qtfix_parse_next_atom(fd, &size, &type, NULL, &pos, &is_ext)) {
+		switch(type) {
+		case GST_MAKE_FOURCC('f', 'r', 'e', 'e'):
+			has_free = TRUE;
+			free_pos = pos;
+			goto _default;
+		case GST_MAKE_FOURCC('m', 'd', 'a', 't'):
+			has_mdat = TRUE;
+			mdat_size = size;
+			mdat_pos = pos;
+			mdat_is_ext = is_ext;
+			if(size <= 16) {
+				parse_stop = TRUE;
+				break;
+			}
+			goto _default;
+		case GST_MAKE_FOURCC('m', 'o', 'o', 'v'):
+			has_moov = TRUE;
+			goto _default;
+		_default:
+		default:
+			if(fseeko(fd, size, SEEK_CUR) != 0) {
+				GST_ERROR("Failed to seek '%llu' bytes. Atom: %" GST_FOURCC_FORMAT,
+						  size, GST_FOURCC_ARGS(type));
+				goto end;
+			}
+			else {
+				GST_INFO("Found atom '%" GST_FOURCC_FORMAT "', seeked '%llu' bytes.",
+						  GST_FOURCC_ARGS(type), size);
+			}
+		}
+	}
+
+	if(!has_mdat) {
+		GST_ERROR("Could not find an mdat atom. Giving up..");
+		goto end;
+	}
+
+	/* Get end pos */
+	fseeko(fd, 0, SEEK_END);
+	end_pos = ftell(fd);
+
+	if(mdat_size > 16 && has_moov) {
+		GST_INFO("We have a moov atom and a non-zero length mdat atom.. leaving as is");
+		ret = TRUE;
+		goto end;
+	}
+
+	GST_INFO("current mdat header size (inc. header): %llu", mdat_size);
+
+	/* mdat size if assuming it goes till EOF */
+	mdat_size = (end_pos - (mdat_pos + (mdat_is_ext ? 16 : 8)));
+	
+	GST_INFO("assumed mdat header size if to EOF (exc. header): %llu", mdat_size);
+
+	GST_INFO("XML moov backup references %llu bytes of mdat data", xmlmdatsize);
+
+	/* Only use as much of mdat data as is referenced in xml file */
+	if(mdat_size > xmlmdatsize)
+		mdat_size = xmlmdatsize;
+
+	largefile = (xmlmdatsize+8 > G_MAXUINT32) ? TRUE : FALSE;
+
+	if(largefile && !mdat_is_ext && has_free && (mdat_pos - free_pos) == 8)
+		fseek(fd, free_pos, SEEK_SET);
+	else {
+		if(largefile && !has_free && !mdat_is_ext)
+			GST_ERROR("Need to use extended mdat header, but do not have space for it");
+		fseek(fd, mdat_pos, SEEK_SET);
+	}
+
+	/* Re-write mdat header */
+	if(largefile)
+		dat32 = GUINT32_TO_BE(1);
+	else
+		dat32 = GUINT32_TO_BE((guint32)(mdat_size+8));
+	fwrite(&dat32, 1, sizeof(dat32), fd);
+	dat32 = GST_MAKE_FOURCC('m', 'd', 'a', 't');
+	fwrite(&dat32, 1, sizeof(dat32), fd);
+	if(largefile) {
+		dat64 = GUINT64_TO_BE((mdat_size+16));
+		fwrite(&dat64, 1, sizeof(dat64), fd);
+	}
+
+	/* Calulate chunk offset */
+	chunk_offset = ftell(fd);
+
+	/* Seek to end of mdat section */
+	fseek(fd, chunk_offset + mdat_size, SEEK_SET);
+
+	GST_INFO("Calling atom_moov_process");
+
+	if(atom_moov_process(qtxmlfile, chunk_offset, largefile, &bsent, duration, FALSE, gst_qt_mux_recover_write_cb, NULL, fd))
+		ret = TRUE;
+
+ end:
+	if(fd)
+		fclose(fd);
+
+	return ret;
+}
+
Index: gst/qtmux/atom-context.h
===================================================================
--- gst/qtmux/atom-context.h	(revision 0)
+++ gst/qtmux/atom-context.h	(revision 476)
@@ -0,0 +1,157 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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 _ATOM_CONTEXT_H_
+#define _ATOM_CONTEXT_H_
+#include <stdio.h>
+#include <glib.h>
+#include <gst/gst.h>
+
+
+typedef enum _AtomsTreeFlavor
+{
+  ATOMS_TREE_FLAVOR_MOV,
+  ATOMS_TREE_FLAVOR_ISOM,
+  ATOMS_TREE_FLAVOR_3GP
+} AtomsTreeFlavor;
+
+
+typedef gboolean (*AtomCtxSendDataCB)(gpointer userdata, guint8 * data, guint size);
+typedef void     (*AtomCtxProcPingCB)(gpointer userdata);
+
+typedef struct _AtomContext AtomContext;
+
+typedef enum {
+	ATOM_CTX_AUDIO_EXT_NONE = 0,
+	ATOM_CTX_AUDIO_EXT_MP1_P3,
+	ATOM_CTX_AUDIO_EXT_AAC,
+	ATOM_CTX_AUDIO_EXT_MP4_P3,
+	ATOM_CTX_AUDIO_EXT_AMR,
+} AtomContextAudioExt;
+
+typedef enum {
+	ATOM_CTX_VISUAL_EXT_NONE = 0,
+	ATOM_CTX_VISUAL_EXT_H263,
+	ATOM_CTX_VISUAL_EXT_MP4_P2,
+	ATOM_CTX_VISUAL_EXT_AVCC,
+	ATOM_CTX_VISUAL_EXT_JP2H,
+} AtomContextVisualExt;
+
+typedef struct
+{
+	guint32 fourcc;
+	guint16 version;
+	guint16 compression_id;
+	guint32 sample_rate;
+	guint16 channels;
+	guint16 sample_size;
+	guint32 sample_fixed_size;
+	guint32 bytes_per_packet;
+	guint32 samples_per_packet;
+	guint32 bytes_per_sample;
+	guint32 bytes_per_frame;
+
+	guint8 * codec_data;
+	guint codec_data_size;
+
+	AtomContextAudioExt audio_ext;
+} AtomContextAudioEntry;
+
+typedef struct
+{
+	guint32 fourcc;
+	guint32 sub_fourcc;  /* For jp2h ext */
+	guint width;
+	guint height;
+	guint depth;
+	guint frame_count;
+	guint timescale;
+	gint color_table_id;
+	guint par_n;
+	guint par_d;
+
+	guint8 * codec_data;
+	guint codec_data_size;
+
+	AtomContextVisualExt visual_ext;
+} AtomContextVisualEntry;
+
+
+#define ATOM_CTX_SEND_DATA_CB(func) ((AtomCtxSendDataCB)func)
+#define ATOM_CTX_PROC_PING_CB(func) ((AtomCtxProcPingCB)func)
+
+AtomContext * atom_ctx_new(AtomsTreeFlavor flavor, AtomCtxSendDataCB send_cb, AtomCtxProcPingCB ping_cb, gpointer user_data);
+void          atom_ctx_free(AtomContext * context);
+void          atom_ctx_reset(AtomContext * context);
+
+void          atom_ctx_timescale_set(AtomContext * context, guint32 timescale);
+void          atom_ctx_filename_set(AtomContext * context, const gchar * filename);
+
+void          atom_ctx_start(AtomContext * context);
+guint         atom_ctx_track_add(AtomContext * context);
+void          atom_ctx_track_audio_set(AtomContext * context, guint trak_id, AtomContextAudioEntry * entry);
+void          atom_ctx_track_video_set(AtomContext * context, guint trak_id, AtomContextVisualEntry * entry);
+
+void          atom_ctx_samples_add(AtomContext * context, guint trak_id, guint32 nsamples, guint32 delta, guint32 size,
+								   guint64 chunk_offset, gboolean sync, gboolean do_pts, gint64 pts_offset);
+void          atom_ctx_start_ts_add(AtomContext * context, guint trak_id, guint64 start_ts);
+
+gboolean      atom_ctx_ftyp_send(AtomContext * context, guint32 major, guint32 version, GList * brands, guint64 * bytes_sent);
+gboolean      atom_ctx_mdat_header_send(AtomContext * context, guint64 size, guint64 * bytes_sent);
+gboolean      atom_ctx_moov_send(AtomContext * context, guint64 mdat_pos, gboolean largefile, gboolean keep_xml_file, guint64 * bytes_sent);
+
+void          atom_ctx_tag_add(AtomContext * context, guint32 fourcc, guint32 flags,
+                               const guint8 * data, guint size);
+void          atom_ctx_tag_str_add(AtomContext * context, guint32 fourcc, const gchar *value);
+void          atom_ctx_tag_uint_add(AtomContext * context, guint32 fourcc, guint32 flags, guint32 value);
+void          atom_ctx_tag_3gp_str_add(AtomContext * context, guint32 fourcc, const gchar * value);
+void          atom_ctx_tag_3gp_str_int_add(AtomContext * context, guint32 fourcc,
+										   const gchar * value, gint16 ivalue);
+void          atom_ctx_tag_3gp_uint_add(AtomContext * context, guint32 fourcc, guint16 value);
+void          atom_ctx_tag_3gp_location_add(AtomContext * context, guint32 fourcc, const gchar * location,
+											gdouble latitude, gdouble longitude, gdouble altitude);
+void          atom_ctx_tag_3gp_keyword_add(AtomContext * context, const gchar * lang,
+										   const gchar * keyword, guint32 fourcc);
+void          atom_ctx_tag_blob_add(AtomContext * context, guint8 * data, guint size);
+
+#endif /* _ATOM_CONTEXT_H_ */
Index: gst/qtmux/gstqtmuxrecover.h
===================================================================
--- gst/qtmux/gstqtmuxrecover.h	(revision 0)
+++ gst/qtmux/gstqtmuxrecover.h	(revision 476)
@@ -0,0 +1,52 @@
+/* Quicktime muxer plugin for GStreamer
+ * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
+ * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
+ * Copyright (C) 2009 Roland Krikava <info@bluedigits.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, 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_QTMUX_RECOVER_H_
+#define _GST_QTMUX_RECOVER_H_
+#include <glib.h>
+
+typedef gboolean (*gst_qt_mux_recover_ptr)(const gchar * qtfile, const gchar * qtxmlfile, guint64 * duration);
+
+gboolean gst_qt_mux_recover(const gchar * qtfile, const gchar * qtxmlfile, guint64 * duration);
+
+#endif /* _GST_QTMUX_RECOVER_H_ */
Index: gst/qtmux/gstqtmuxmap.h
===================================================================
--- gst/qtmux/gstqtmuxmap.h	(revision 90)
+++ gst/qtmux/gstqtmuxmap.h	(working copy)
@@ -44,10 +44,9 @@
 #ifndef __GST_QT_MUX_MAP_H__
 #define __GST_QT_MUX_MAP_H__
 
-#include "atoms.h"
-
 #include <glib.h>
 #include <gst/gst.h>
+#include "atom-context.h" /* For AtomsTreeFlavor */
 
 typedef enum _GstQTMuxFormat
 {
@@ -73,7 +72,8 @@
 
 void            gst_qt_mux_map_format_to_header      (GstQTMuxFormat format, GstBuffer ** _prefix,
                                                       guint32 * _major, guint32 * verson,
-                                                      GList ** _compatible, AtomMOOV * moov);
+                                                      GList ** _compatible, gint video, gint audio,
+													  gboolean has_h264);
 
 AtomsTreeFlavor gst_qt_mux_map_format_to_flavor      (GstQTMuxFormat format);
 
Index: gst/qtmux/Makefile.in
===================================================================
--- gst/qtmux/Makefile.in	(revision 90)
+++ gst/qtmux/Makefile.in	(working copy)
@@ -36,8 +36,8 @@
 build_triplet = @build@
 host_triplet = @host@
 subdir = gst/qtmux
-DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
-	$(srcdir)/Makefile.in
+DIST_COMMON = $(libgstqtmux_include_HEADERS) $(noinst_HEADERS) \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in
 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 \
@@ -82,15 +82,19 @@
     *) f=$$p;; \
   esac;
 am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
-am__installdirs = "$(DESTDIR)$(plugindir)"
+am__installdirs = "$(DESTDIR)$(plugindir)" \
+	"$(DESTDIR)$(libgstqtmux_includedir)"
 pluginLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(plugin_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libgstqtmux_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libgstqtmux_la_OBJECTS = libgstqtmux_la-gstqtmux.lo \
 	libgstqtmux_la-atoms.lo libgstqtmux_la-descriptors.lo \
-	libgstqtmux_la-properties.lo libgstqtmux_la-gstqtmuxmap.lo
+	libgstqtmux_la-properties.lo libgstqtmux_la-gstqtmuxmap.lo \
+	libgstqtmux_la-atom-context-xml.lo \
+	libgstqtmux_la-atom-moov-xml.lo \
+	libgstqtmux_la-gstqtmuxrecover.lo
 libgstqtmux_la_OBJECTS = $(am_libgstqtmux_la_OBJECTS)
 libgstqtmux_la_LINK = $(LIBTOOL) --tag=CC \
 	$(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
@@ -110,7 +114,8 @@
 	$(LDFLAGS) -o $@
 SOURCES = $(libgstqtmux_la_SOURCES)
 DIST_SOURCES = $(libgstqtmux_la_SOURCES)
-HEADERS = $(noinst_HEADERS)
+libgstqtmux_includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(libgstqtmux_include_HEADERS) $(noinst_HEADERS)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -179,6 +184,7 @@
 EXEEXT = @EXEEXT@
 EXIF_CFLAGS = @EXIF_CFLAGS@
 EXIF_LIBS = @EXIF_LIBS@
+EXPAT_LIBS = @EXPAT_LIBS@
 F77 = @F77@
 FAAC_LIBS = @FAAC_LIBS@
 FAAD_IS_NEAAC = @FAAD_IS_NEAAC@
@@ -248,6 +254,7 @@
 HAVE_GSM = @HAVE_GSM@
 HAVE_JP2K = @HAVE_JP2K@
 HAVE_NAS = @HAVE_NAS@
+HAVE_QTMUX = @HAVE_QTMUX@
 HAVE_X = @HAVE_X@
 HAVE_X11 = @HAVE_X11@
 HAVE_X264 = @HAVE_X264@
@@ -461,16 +468,23 @@
 			atoms.c \
 			descriptors.c \
 			properties.c \
-			gstqtmuxmap.c
+			gstqtmuxmap.c \
+			atom-context-xml.c \
+			atom-moov-xml.c \
+			gstqtmuxrecover.c
 
 
 # flags used to compile this plugin
 # add other _CFLAGS and _LIBS as needed
-libgstqtmux_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
-libgstqtmux_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
-libgstqtmux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstqtmux_la_CFLAGS = $(EXPAT_CFLAGS) $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstqtmux_la_LIBADD = $(EXPAT_LIBS) $(GST_LIBS) $(GST_BASE_LIBS)
+libgstqtmux_la_LDFLAGS = -module -avoid-version $GST_ALL_LDFLAGS
 libgstqtmux_la_LIBTOOLFLAGS = --tag=disable-static
+libgstqtmux_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/qtmux
+libgstqtmux_include_HEADERS = \
+		gstqtmuxrecover.h
 
+
 # headers we need but don't want installed
 noinst_HEADERS = gstqtmux.h \
 		atoms.h \
@@ -478,7 +492,9 @@
 		properties.h \
 		fourcc.h \
 		ftypcc.h \
-		gstqtmuxmap.h
+		gstqtmuxmap.h \
+		atom-context.h \
+		atom-moov-xml.h
 
 all: all-am
 
@@ -549,10 +565,13 @@
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-atom-context-xml.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-atom-moov-xml.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-atoms.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-descriptors.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-gstqtmux.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-gstqtmuxmap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-gstqtmuxrecover.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstqtmux_la-properties.Plo@am__quote@
 
 .c.o:
@@ -611,12 +630,50 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -c -o libgstqtmux_la-gstqtmuxmap.lo `test -f 'gstqtmuxmap.c' || echo '$(srcdir)/'`gstqtmuxmap.c
 
+libgstqtmux_la-atom-context-xml.lo: atom-context-xml.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -MT libgstqtmux_la-atom-context-xml.lo -MD -MP -MF $(DEPDIR)/libgstqtmux_la-atom-context-xml.Tpo -c -o libgstqtmux_la-atom-context-xml.lo `test -f 'atom-context-xml.c' || echo '$(srcdir)/'`atom-context-xml.c
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libgstqtmux_la-atom-context-xml.Tpo $(DEPDIR)/libgstqtmux_la-atom-context-xml.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='atom-context-xml.c' object='libgstqtmux_la-atom-context-xml.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -c -o libgstqtmux_la-atom-context-xml.lo `test -f 'atom-context-xml.c' || echo '$(srcdir)/'`atom-context-xml.c
+
+libgstqtmux_la-atom-moov-xml.lo: atom-moov-xml.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -MT libgstqtmux_la-atom-moov-xml.lo -MD -MP -MF $(DEPDIR)/libgstqtmux_la-atom-moov-xml.Tpo -c -o libgstqtmux_la-atom-moov-xml.lo `test -f 'atom-moov-xml.c' || echo '$(srcdir)/'`atom-moov-xml.c
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libgstqtmux_la-atom-moov-xml.Tpo $(DEPDIR)/libgstqtmux_la-atom-moov-xml.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='atom-moov-xml.c' object='libgstqtmux_la-atom-moov-xml.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -c -o libgstqtmux_la-atom-moov-xml.lo `test -f 'atom-moov-xml.c' || echo '$(srcdir)/'`atom-moov-xml.c
+
+libgstqtmux_la-gstqtmuxrecover.lo: gstqtmuxrecover.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -MT libgstqtmux_la-gstqtmuxrecover.lo -MD -MP -MF $(DEPDIR)/libgstqtmux_la-gstqtmuxrecover.Tpo -c -o libgstqtmux_la-gstqtmuxrecover.lo `test -f 'gstqtmuxrecover.c' || echo '$(srcdir)/'`gstqtmuxrecover.c
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libgstqtmux_la-gstqtmuxrecover.Tpo $(DEPDIR)/libgstqtmux_la-gstqtmuxrecover.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='gstqtmuxrecover.c' object='libgstqtmux_la-gstqtmuxrecover.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(libgstqtmux_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstqtmux_la_CFLAGS) $(CFLAGS) -c -o libgstqtmux_la-gstqtmuxrecover.lo `test -f 'gstqtmuxrecover.c' || echo '$(srcdir)/'`gstqtmuxrecover.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
 clean-libtool:
 	-rm -rf .libs _libs
+install-libgstqtmux_includeHEADERS: $(libgstqtmux_include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(libgstqtmux_includedir)" || $(MKDIR_P) "$(DESTDIR)$(libgstqtmux_includedir)"
+	@list='$(libgstqtmux_include_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(am__strip_dir) \
+	  echo " $(libgstqtmux_includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libgstqtmux_includedir)/$$f'"; \
+	  $(libgstqtmux_includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libgstqtmux_includedir)/$$f"; \
+	done
 
+uninstall-libgstqtmux_includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(libgstqtmux_include_HEADERS)'; for p in $$list; do \
+	  f=$(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(libgstqtmux_includedir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(libgstqtmux_includedir)/$$f"; \
+	done
+
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
@@ -694,7 +751,7 @@
 check: check-am
 all-am: Makefile $(LTLIBRARIES) $(HEADERS)
 installdirs:
-	for dir in "$(DESTDIR)$(plugindir)"; do \
+	for dir in "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(libgstqtmux_includedir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
 install: install-am
@@ -742,7 +799,8 @@
 
 info-am:
 
-install-data-am: install-pluginLTLIBRARIES
+install-data-am: install-libgstqtmux_includeHEADERS \
+	install-pluginLTLIBRARIES
 
 install-dvi: install-dvi-am
 
@@ -778,7 +836,8 @@
 
 ps-am:
 
-uninstall-am: uninstall-pluginLTLIBRARIES
+uninstall-am: uninstall-libgstqtmux_includeHEADERS \
+	uninstall-pluginLTLIBRARIES
 
 .MAKE: install-am install-strip
 
@@ -788,13 +847,15 @@
 	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 uninstall uninstall-am uninstall-pluginLTLIBRARIES
+	install-html-am install-info install-info-am \
+	install-libgstqtmux_includeHEADERS 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 uninstall \
+	uninstall-am uninstall-libgstqtmux_includeHEADERS \
+	uninstall-pluginLTLIBRARIES
 
 # 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.
Index: gst/qtmux/gstqtmux.h
===================================================================
--- gst/qtmux/gstqtmux.h	(revision 90)
+++ gst/qtmux/gstqtmux.h	(working copy)
@@ -47,7 +47,7 @@
 #include <gst/base/gstcollectpads.h>
 
 #include "fourcc.h"
-#include "atoms.h"
+#include "atom-context.h"
 #include "gstqtmuxmap.h"
 
 G_BEGIN_DECLS
@@ -59,6 +59,7 @@
 #define GST_IS_QT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_MUX))
 #define GST_QT_MUX_CAST(obj) ((GstQTMux*)(obj))
 
+#define MAX_TRAK 5
 
 typedef struct _GstQTMux GstQTMux;
 typedef struct _GstQTMuxClass GstQTMuxClass;
@@ -77,14 +78,15 @@
   guint sample_size;
   /* make sync table entry */
   gboolean sync;
+  /* Track timescale */
+  guint32 trak_timescale;
 
   GstBuffer *last_buf;
   /* dts of last_buf */
   GstClockTime last_dts;
 
-  /* all the atom and chunk book-keeping is delegated here
-   * unowned/uncounted reference, parent MOOV owns */
-  AtomTRAK *trak;
+  /* AtomContext track ID */
+  guint trak_id;
 } GstQTPad;
 
 typedef enum _GstQTMuxState
@@ -105,29 +107,29 @@
   /* state */
   GstQTMuxState state;
 
-  /* size of header (prefix, atoms (ftyp, mdat)) */
-  guint64 header_size;
   /* accumulated size of raw media data (a priori not including mdat header) */
   guint64 mdat_size;
-  /* position of mdat extended size field (for later updating) */
+  /* position of mdat atom (for later updating) */
   guint64 mdat_pos;
 
   /* atom helper objects */
-  AtomsContext *context;
-  AtomFTYP *ftyp;
-  AtomMOOV *moov;
+  AtomContext *context;
 
-  /* fast start */
-  FILE *fast_start_file;
-
   /* properties */
   guint32 timescale;
   AtomsTreeFlavor flavor;
-  gboolean fast_start;
-  gboolean large_file;
   gboolean guess_pts;
-  gchar *fast_start_file_path;
+  gint audio_trak_count;
+  gint video_trak_count;
+  gboolean has_h264;
+  gchar * moov_file_path;
+  gboolean mux_by_timestamp;
+  gboolean moov_file_keep;
 
+  /* Track ids of previously requested pads */
+  gint audio_trak_ids[MAX_TRAK];
+  gint video_trak_ids[MAX_TRAK];
+
   /* for collect pads event handling function */
   GstPadEventFunction collect_event;
 };
Index: gst/qtmux/atoms.c
===================================================================
--- gst/qtmux/atoms.c	(revision 90)
+++ gst/qtmux/atoms.c	(working copy)
@@ -156,14 +156,20 @@
     return ai;
 }
 
+void
+atom_info_free(AtomInfo * ai)
+{
+    ai->free_func (ai->atom);
+    g_free (ai);
+}
+
 static void
 atom_info_list_free (GList * ai)
 {
   while (ai) {
     AtomInfo *info = (AtomInfo *) ai->data;
 
-    info->free_func (info->atom);
-    g_free (info);
+    atom_info_free(info);
     ai = g_list_delete_link (ai, ai);
   }
 }
@@ -1036,7 +1042,8 @@
 {
   atom_full_clear (&meta->header);
   atom_hdlr_clear (&meta->hdlr);
-  atom_ilst_free (meta->ilst);
+  if (meta->ilst)
+    atom_ilst_free (meta->ilst);
   meta->ilst = NULL;
   g_free (meta);
 }
@@ -1061,8 +1068,11 @@
 atom_udta_free (AtomUDTA * udta)
 {
   atom_clear (&udta->header);
-  atom_meta_free (udta->meta);
+  if (udta->meta)
+    atom_meta_free (udta->meta);
   udta->meta = NULL;
+  if (udta->entries)
+    atom_info_list_free (udta->entries);
   g_free (udta);
 }
 
@@ -1149,6 +1159,7 @@
   atom_mvhd_init (&(moov->mvhd));
   moov->udta = NULL;
   moov->traks = NULL;
+  moov->context = *context;
 }
 
 AtomMOOV *
@@ -1170,13 +1181,11 @@
 
   walker = moov->traks;
   while (walker) {
-    GList *aux = walker;
-
+    atom_trak_free ((AtomTRAK *) walker->data);
     walker = g_list_next (walker);
-    moov->traks = g_list_remove_link (moov->traks, aux);
-    atom_trak_free ((AtomTRAK *) aux->data);
-    g_list_free (aux);
   }
+  g_list_free (moov->traks);
+  moov->traks = NULL;
 
   if (moov->udta) {
     atom_udta_free (moov->udta);
@@ -1240,9 +1249,6 @@
      * would be a problem for size (re)write code, not to mention memory */
     g_return_val_if_fail (atom->type == FOURCC_mdat, 0);
     prop_copy_uint64 (atom->extended_size, buffer, size, offset);
-  } else {
-    /* just in case some trivially derived atom does not do so */
-    atom_write_size (buffer, size, offset, original_offset);
   }
 
   return *offset - original_offset;
@@ -1265,6 +1271,16 @@
   return *offset - original_offset;
 }
 
+guint64
+atom_info_copy_data(AtomInfo * ai, guint8 ** buffer, guint64 * size, guint64 * offset)
+{
+	guint64 original_offset = *offset;
+
+    if(!ai->copy_data_func(ai->atom, buffer, size, offset))
+      return 0;
+	return *offset - original_offset;
+}
+
 static guint64
 atom_info_list_copy_data (GList * ai, guint8 ** buffer, guint64 * size,
     guint64 * offset)
@@ -2163,6 +2179,10 @@
     if (!atom_meta_copy_data (udta->meta, buffer, size, offset)) {
       return 0;
     }
+  } else if (udta->entries) {
+    /* extra atoms */
+    if (!atom_info_list_copy_data (udta->entries, buffer, size, offset))
+      return 0;
   }
 
   atom_write_size (buffer, size, offset, original_offset);
@@ -2238,6 +2258,10 @@
 static void
 atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
 {
+  if (stsc->entries &&
+      ((STSCEntry *) stsc->entries->data)->samples_per_chunk == nsamples)
+    return;
+
   stsc->entries =
       g_list_prepend (stsc->entries, stsc_entry_new (first_chunk, nsamples, 1));
   stsc->n_entries++;
@@ -2517,17 +2541,19 @@
  * Meta tags functions
  */
 static void
-atom_moov_init_metatags (AtomMOOV * moov)
+atom_moov_init_metatags (AtomMOOV * moov, AtomsContext * context)
 {
   if (!moov->udta) {
     moov->udta = atom_udta_new ();
   }
-  if (!moov->udta->meta) {
-    moov->udta->meta = atom_meta_new ();
+  if (context->flavor != ATOMS_TREE_FLAVOR_3GP) {
+    if (!moov->udta->meta) {
+      moov->udta->meta = atom_meta_new ();
+    }
+    if (!moov->udta->meta->ilst) {
+      moov->udta->meta->ilst = atom_ilst_new ();
+    }
   }
-  if (!moov->udta->meta->ilst) {
-    moov->udta->meta->ilst = atom_ilst_new ();
-  }
 }
 
 static void
@@ -2543,11 +2569,14 @@
 static void
 atom_moov_append_tag (AtomMOOV * moov, AtomInfo * tag)
 {
-  AtomILST *ilst;
+  GList **entries;
 
-  atom_moov_init_metatags (moov);
-  ilst = moov->udta->meta->ilst;
-  ilst->entries = g_list_append (ilst->entries, tag);
+  atom_moov_init_metatags (moov, &moov->context);
+  if (moov->udta->meta)
+    entries = &moov->udta->meta->ilst->entries;
+  else
+    entries = &moov->udta->entries;
+  *entries = g_list_append (*entries, tag);
 }
 
 void
@@ -2621,6 +2650,87 @@
           atom_data_free));
 }
 
+void
+atom_moov_add_3gp_tag (AtomMOOV * moov, guint32 fourcc, guint8 * data,
+    guint size)
+{
+  AtomData *data_atom;
+  GstBuffer *buf;
+  guint8 *bdata;
+
+  /* need full atom */
+  buf = gst_buffer_new_and_alloc (size + 4);
+  bdata = GST_BUFFER_DATA (buf);
+  /* full atom: version and flags */
+  GST_WRITE_UINT32_BE (bdata, 0);
+  memcpy (bdata + 4, data, size);
+
+  data_atom = atom_data_new_from_gst_buffer (fourcc, buf);
+  gst_buffer_unref (buf);
+
+  atom_moov_append_tag (moov,
+      build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
+          atom_data_free));
+}
+
+guint16
+language_code (const char *lang)
+{
+  g_return_val_if_fail (lang != NULL, 0);
+  g_return_val_if_fail (strlen (lang) == 3, 0);
+
+  return (((lang[0] - 0x60) & 0x1F) << 10) + (((lang[1] - 0x60) & 0x1F) << 5) +
+      ((lang[2] - 0x60) & 0x1F);
+}
+
+void
+atom_moov_add_3gp_str_int_tag (AtomMOOV * moov, guint32 fourcc,
+    const gchar * value, gint16 ivalue)
+{
+  gint len = 0, size = 0;
+  guint8 *data;
+
+  if (value) {
+    len = strlen (value);
+    size = len + 3;
+  }
+
+  if (ivalue >= 0)
+    size += 2;
+
+  data = g_malloc (size + 3);
+  /* language tag and null-terminated UTF-8 string */
+  if (value) {
+    GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
+    /* include 0 terminator */
+    memcpy (data + 2, value, len + 1);
+  }
+  /* 16-bit unsigned int if standalone, otherwise 8-bit */
+  if (ivalue >= 0) {
+    if (size == 2)
+      GST_WRITE_UINT16_BE (data + size - 2, ivalue);
+    else {
+      GST_WRITE_UINT8 (data + size - 2, ivalue & 0xFF);
+      size--;
+    }
+  }
+
+  atom_moov_add_3gp_tag (moov, fourcc, data, size);
+  g_free (data);
+}
+
+void
+atom_moov_add_3gp_str_tag (AtomMOOV * moov, guint32 fourcc, const gchar * value)
+{
+  atom_moov_add_3gp_str_int_tag (moov, fourcc, value, -1);
+}
+
+void
+atom_moov_add_3gp_uint_tag (AtomMOOV * moov, guint32 fourcc, guint16 value)
+{
+  atom_moov_add_3gp_str_int_tag (moov, fourcc, NULL, value);
+}
+
 /*
  * Functions for specifying media types
  */
@@ -2783,6 +2893,9 @@
   atom_trak_set_audio_commons (trak, context, scale);
   ste = atom_trak_add_audio_entry (trak, context, entry->fourcc);
 
+  trak->is_video = FALSE;
+  trak->is_h264 = FALSE;
+
   ste->version = entry->version;
   ste->compression_id = entry->compression_id;
   ste->sample_size = entry->sample_size;
@@ -2801,16 +2914,61 @@
   atom_trak_set_constant_size_samples (trak, sample_size);
 }
 
+AtomInfo *
+build_pasp_extension (AtomTRAK * trak, gint par_width, gint par_height)
+{
+  AtomData *atom_data;
+  GstBuffer *buf;
+  guint8 *data;
+
+  buf = gst_buffer_new_and_alloc (8);
+  data = GST_BUFFER_DATA (buf);
+
+  /* ihdr = image header box */
+  GST_WRITE_UINT32_BE (data, par_width);
+  GST_WRITE_UINT32_BE (data + 4, par_height);
+
+  atom_data = atom_data_new_from_gst_buffer (FOURCC_pasp, buf);
+  gst_buffer_unref (buf);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
 void
 atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
     VisualSampleEntry * entry, guint32 scale, AtomInfo * ext)
 {
   SampleTableEntryMP4V *ste;
+  gint dwidth, dheight;
+  gint par_n = 0, par_d = 0;
 
-  atom_trak_set_video_commons (trak, context, scale, entry->width,
-      entry->height);
+  if ((entry->par_n != 1 || entry->par_d != 1) &&
+      (entry->par_n != entry->par_d)) {
+    par_n = entry->par_n;
+    par_d = entry->par_d;
+  }
+
+  dwidth = entry->width;
+  dheight = entry->height;
+  /* ISO file spec says track header w/h indicates track's visual presentation
+   * (so this together with pixels w/h implicitly defines PAR) */
+  if (par_n && (context->flavor != ATOMS_TREE_FLAVOR_MOV)) {
+    if (par_n > par_d) {
+      dwidth = entry->width * par_n / par_d;
+      dheight = entry->height;
+    } else {
+      dwidth = entry->width * par_n / par_d;
+      dheight = entry->height;
+    }
+  }
+
+  atom_trak_set_video_commons (trak, context, scale, dwidth, dheight);
   ste = atom_trak_add_video_entry (trak, context, entry->fourcc);
 
+  trak->is_video = TRUE;
+  trak->is_h264 = (entry->fourcc == FOURCC_avc1);
+
   ste->width = entry->width;
   ste->height = entry->height;
   ste->depth = entry->depth;
@@ -2819,19 +2977,22 @@
 
   if (ext)
     ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext);
+
+  /* QT spec has a pasp extension atom in stsd that can hold PAR */
+  if (par_n && (context->flavor == ATOMS_TREE_FLAVOR_MOV)) {
+    ste->extension_atoms = g_list_append (ste->extension_atoms,
+        build_pasp_extension (trak, par_n, par_d));
+  }
 }
 
 /* some sample description construction helpers */
 
 AtomInfo *
-build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
+build_esds_extension (guint32 track_id, guint8 object_type, guint8 stream_type,
     const GstBuffer * codec_data)
 {
-  guint32 track_id;
   AtomESDS *esds;
 
-  track_id = trak->tkhd.track_ID;
-
   esds = atom_esds_new ();
   esds->es.id = track_id & 0xFFFF;
   esds->es.dec_conf_desc.object_type = object_type;
@@ -2854,16 +3015,13 @@
 }
 
 AtomInfo *
-build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data)
+build_mov_aac_extension (guint32 track_id, const GstBuffer * codec_data)
 {
-  guint32 track_id;
   AtomWAVE *wave;
   AtomFRMA *frma;
   Atom *ext_atom;
   GstBuffer *buf;
 
-  track_id = trak->tkhd.track_ID;
-
   /* Add WAVE atom to the MP4A sample table entry */
   wave = atom_wave_new ();
 
@@ -2875,7 +3033,7 @@
 
   /* Add ESDS atom to WAVE */
   wave->extension_atoms = g_list_prepend (wave->extension_atoms,
-      build_esds_extension (trak, ESDS_OBJECT_TYPE_MPEG4_P3,
+      build_esds_extension (track_id, ESDS_OBJECT_TYPE_MPEG4_P3,
           ESDS_STREAM_TYPE_AUDIO, codec_data));
 
   /* Add MP4A atom to the WAVE:
@@ -2902,7 +3060,7 @@
 }
 
 AtomInfo *
-build_jp2h_extension (AtomTRAK * trak, gint width, gint height, guint32 fourcc)
+build_jp2h_extension (gint width, gint height, guint32 fourcc)
 {
   AtomData *atom_data;
   GstBuffer *buf;
Index: gst/qtmux/fourcc.h
===================================================================
--- gst/qtmux/fourcc.h	(revision 90)
+++ gst/qtmux/fourcc.h	(working copy)
@@ -104,6 +104,7 @@
 #define FOURCC_wave     GST_MAKE_FOURCC('w','a','v','e')
 #define FOURCC_appl     GST_MAKE_FOURCC('a','p','p','l')
 #define FOURCC_esds     GST_MAKE_FOURCC('e','s','d','s')
+#define FOURCC_pasp     GST_MAKE_FOURCC('p','a','s','p')
 #define FOURCC_hnti     GST_MAKE_FOURCC('h','n','t','i')
 #define FOURCC_rtp_     GST_MAKE_FOURCC('r','t','p',' ')
 #define FOURCC_sdp_     GST_MAKE_FOURCC('s','d','p',' ')
@@ -140,6 +141,7 @@
 #define FOURCC_drms     GST_MAKE_FOURCC('d','r','m','s')
 #define FOURCC_avc1     GST_MAKE_FOURCC('a','v','c','1')
 #define FOURCC_h263     GST_MAKE_FOURCC('h','2','6','3')
+#define FOURCC_s263     GST_MAKE_FOURCC('s','2','6','3')
 #define FOURCC_avcC     GST_MAKE_FOURCC('a','v','c','C')
 #define FOURCC_VP31     GST_MAKE_FOURCC('V','P','3','1')
 #define FOURCC_rle_     GST_MAKE_FOURCC('r','l','e',' ')
@@ -180,6 +182,15 @@
 #define FOURCC_titl     GST_MAKE_FOURCC('t','i','t','l')
 #define FOURCC__cmt     GST_MAKE_FOURCC(0xa9, 'c','m','t')
 
+/* 3gp tags */
+#define FOURCC_dscp     GST_MAKE_FOURCC('d','s','c','p')
+#define FOURCC_perf     GST_MAKE_FOURCC('p','e','r','f')
+#define FOURCC_auth     GST_MAKE_FOURCC('a','u','t','h')
+#define FOURCC_yrrc     GST_MAKE_FOURCC('y','r','r','c')
+#define FOURCC_albm     GST_MAKE_FOURCC('a','l','b','m')
+#define FOURCC_loci     GST_MAKE_FOURCC('l','o','c','i')
+#define FOURCC_kywd     GST_MAKE_FOURCC('k','y','w','d')
+
 G_END_DECLS
 
 #endif /* __FOURCC_H__ */
Index: gst/qtmux/Makefile.am
===================================================================
--- gst/qtmux/Makefile.am	(revision 90)
+++ gst/qtmux/Makefile.am	(working copy)
@@ -7,15 +7,22 @@
 			atoms.c \
 			descriptors.c \
 			properties.c \
-			gstqtmuxmap.c
+			gstqtmuxmap.c \
+			atom-context-xml.c \
+			atom-moov-xml.c \
+			gstqtmuxrecover.c
 
 # flags used to compile this plugin
 # add other _CFLAGS and _LIBS as needed
-libgstqtmux_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
-libgstqtmux_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
-libgstqtmux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstqtmux_la_CFLAGS = $(EXPAT_CFLAGS) $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstqtmux_la_LIBADD = $(EXPAT_LIBS) $(GST_LIBS) $(GST_BASE_LIBS)
+libgstqtmux_la_LDFLAGS = -module -avoid-version $GST_ALL_LDFLAGS
 libgstqtmux_la_LIBTOOLFLAGS = --tag=disable-static
 
+libgstqtmux_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/qtmux
+libgstqtmux_include_HEADERS = \
+		gstqtmuxrecover.h
+
 # headers we need but don't want installed
 noinst_HEADERS = gstqtmux.h \
 		atoms.h \
@@ -23,4 +30,6 @@
 		properties.h \
 		fourcc.h \
 		ftypcc.h \
-		gstqtmuxmap.h
+		gstqtmuxmap.h \
+		atom-context.h \
+		atom-moov-xml.h
Index: gst/qtmux/atoms.h
===================================================================
--- gst/qtmux/atoms.h	(revision 90)
+++ gst/qtmux/atoms.h	(working copy)
@@ -50,13 +50,17 @@
 #include "properties.h"
 #include "fourcc.h"
 #include "ftypcc.h"
+#include "atom-context.h"
 
+#if 0
 /* light-weight context that may influence header atom tree construction */
 typedef enum _AtomsTreeFlavor
 {
   ATOMS_TREE_FLAVOR_MOV,
-  ATOMS_TREE_FLAVOR_ISOM
+  ATOMS_TREE_FLAVOR_ISOM,
+  ATOMS_TREE_FLAVOR_3GP
 } AtomsTreeFlavor;
+#endif
 
 typedef struct _AtomsContext
 {
@@ -509,6 +513,9 @@
 {
   Atom header;
 
+  /* list of AtomInfo */
+  GList* entries;
+  /* or list is further down */
   AtomMETA *meta;
 } AtomUDTA;
 
@@ -518,10 +525,17 @@
 
   AtomTKHD tkhd;
   AtomMDIA mdia;
+
+  /* some helper info for structural conformity checks */
+  gboolean is_video;
+  gboolean is_h264;
 } AtomTRAK;
 
 typedef struct _AtomMOOV
 {
+  /* style */
+  AtomsContext context;
+
   Atom header;
 
   AtomMVHD mvhd;
@@ -598,6 +612,8 @@
   guint depth;
   guint frame_count;
   gint color_table_id;
+  guint par_n;
+  guint par_d;
 
   GstBuffer *codec_data;
 } VisualSampleEntry;
@@ -626,14 +642,15 @@
                                AtomInfo * ext);
 
 AtomInfo *   build_codec_data_extension  (guint32 fourcc, const GstBuffer * codec_data);
-AtomInfo *   build_mov_aac_extension     (AtomTRAK * trak, const GstBuffer * codec_data);
-AtomInfo *   build_esds_extension        (AtomTRAK * trak, guint8 object_type,
+AtomInfo *   build_mov_aac_extension     (guint32 trak_id, const GstBuffer * codec_data);
+AtomInfo *   build_esds_extension        (guint32 trak_id, guint8 object_type,
                                           guint8 stream_type, const GstBuffer * codec_data);
-AtomInfo *   build_jp2h_extension        (AtomTRAK * trak, gint width, gint height,
-                                          guint32 fourcc);
+AtomInfo *   build_jp2h_extension        (gint width, gint height, guint32 fourcc);
 AtomInfo *   build_amr_extension         ();
 AtomInfo *   build_h263_extension        ();
 
+guint64 atom_info_copy_data(AtomInfo * ai, guint8 ** buffer, guint64 * size, guint64 * offset);
+void    atom_info_free(AtomInfo * ai);
 
 /*
  * Meta tags functions
@@ -645,4 +662,14 @@
                                const guint8 * data, guint size);
 void atom_moov_add_blob_tag   (AtomMOOV *moov, guint8 *data, guint size);
 
+void atom_moov_add_3gp_str_tag       (AtomMOOV * moov, guint32 fourcc, const gchar * value);
+void atom_moov_add_3gp_uint_tag      (AtomMOOV * moov, guint32 fourcc, guint16 value);
+void atom_moov_add_3gp_str_int_tag   (AtomMOOV * moov, guint32 fourcc, const gchar * value,
+                                      gint16 ivalue);
+void atom_moov_add_3gp_tag           (AtomMOOV * moov, guint32 fourcc, guint8 * data,
+                                      guint size);
+
+#define GST_QT_MUX_DEFAULT_TAG_LANGUAGE   "eng"
+guint16  language_code               (const char * lang);
+
 #endif /* __ATOMS_H__ */
Index: gst/qtmux/gstqtmuxmap.c
===================================================================
--- gst/qtmux/gstqtmuxmap.c	(revision 90)
+++ gst/qtmux/gstqtmuxmap.c	(working copy)
@@ -40,6 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <string.h>
 
 #include "gstqtmuxmap.h"
 #include "fourcc.h"
@@ -201,6 +202,8 @@
 {
   if (format == GST_QT_MUX_FORMAT_QT)
     return ATOMS_TREE_FLAVOR_MOV;
+  else if (format == GST_QT_MUX_FORMAT_3GP)
+    return ATOMS_TREE_FLAVOR_3GP;
   else
     return ATOMS_TREE_FLAVOR_ISOM;
 }
@@ -210,12 +213,12 @@
 /* notes:
  * - avc1 brand is not used, since the specific extensions indicated by it
  *   are not used (e.g. sample groupings, etc)
- * - 3GPP2 specific formats not (yet) used, only 3GPP, so no need yet either
- *   for 3g2a (but later on, moov might be used to conditionally switch to
- *   3g2a if needed) */
+ * - TODO: maybe even more 3GPP brand fine-tuning ??
+ *   (but that might need ftyp rewriting at the end) */
 void
 gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
-    guint32 * _major, guint32 * _version, GList ** _compatible, AtomMOOV * moov)
+								 guint32 * _major, guint32 * _version, GList ** _compatible,
+								 gint video, gint audio, gboolean has_h264)
 {
   static guint32 qt_brands[] = { 0 };
   static guint32 mp4_brands[] = { FOURCC_mp41, FOURCC_isom, FOURCC_iso2, 0 };
@@ -244,9 +247,19 @@
       comp = mp4_brands;
       break;
     case GST_QT_MUX_FORMAT_3GP:
-      major = FOURCC_3gg7;
+    {
+      /* only track restriction really matters for Basic Profile */
+      if (video <= 1 && audio <= 1) {
+        /* it seems only newer spec knows about H264 */
+        major = has_h264 ? FOURCC_3gp6 : FOURCC_3gp4;
+        version = has_h264 ? 0x100 : 0x200;
+      } else {
+        major = FOURCC_3gg6;
+        version = 0x100;
+      }
       comp = gpp_brands;
       break;
+    }
     case GST_QT_MUX_FORMAT_MJ2:
       major = FOURCC_mjp2;
       comp = mjp2_brands;
Index: gst/qtmux/gstqtmux.c
===================================================================
--- gst/qtmux/gstqtmux.c	(revision 90)
+++ gst/qtmux/gstqtmux.c	(working copy)
@@ -69,6 +69,7 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#include "string.h"
 
 #include <glib/gstdio.h>
 
@@ -90,9 +91,14 @@
 
 #include "gstqtmux.h"
 
+/* Used by atoms-context-xml.c */
+GST_DEBUG_CATEGORY(gst_qtmux_atom_ctx_debug);
+
 GST_DEBUG_CATEGORY_STATIC (gst_qt_mux_debug);
 #define GST_CAT_DEFAULT gst_qt_mux_debug
 
+#define GST_QT_MUX_DEFAULT_TAG_LANGUAGE   "eng"
+
 /* QTMux signals and args */
 enum
 {
@@ -103,20 +109,26 @@
 enum
 {
   PROP_0,
-  PROP_LARGE_FILE,
   PROP_MOVIE_TIMESCALE,
   PROP_DO_CTTS,
   PROP_FLAVOR,
   PROP_FAST_START,
-  PROP_FAST_START_TEMP_FILE
+  PROP_FAST_START_TEMP_FILE,
+  PROP_MOOV_TEMP_FILE,
+  PROP_MUX_BY_TIMESTAMP,
+  PROP_MOOV_TEMP_FILE_KEEP,
 };
 
-#define MDAT_ATOM_HEADER_SIZE           16
-#define DEFAULT_LARGE_FILE              FALSE
-#define DEFAULT_MOVIE_TIMESCALE         600
+/* some spare for header size as well */
+#define MDAT_LARGE_FILE_LIMIT           ((guint64) 1024 * 1024 * 1024 * 2)
+
+#define DEFAULT_MOVIE_TIMESCALE         1000
 #define DEFAULT_DO_CTTS                 FALSE
 #define DEFAULT_FAST_START              FALSE
 #define DEFAULT_FAST_START_TEMP_FILE    NULL
+#define DEFAULT_MOOV_TEMP_FILE          NULL
+#define DEFAULT_MUX_BY_TIMESTAMP        FALSE
+#define DEFAULT_MOOV_TEMP_FILE_KEEP     FALSE
 
 static void gst_qt_mux_finalize (GObject * object);
 
@@ -141,6 +153,8 @@
     gpointer user_data);
 static GstFlowReturn gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad,
     GstBuffer * buf);
+static GstFlowReturn gst_qt_mux_send_buffer (GstQTMux * qtmux,
+    GstBuffer * buf, guint64 * offset);
 
 static GstElementClass *parent_class = NULL;
 
@@ -205,11 +219,6 @@
   gobject_class->get_property = gst_qt_mux_get_property;
   gobject_class->set_property = gst_qt_mux_set_property;
 
-  g_object_class_install_property (gobject_class, PROP_LARGE_FILE,
-      g_param_spec_boolean ("large-file", "Support for large files",
-          "Uses 64bits to some fields instead of 32bits, "
-          "providing support for large files",
-          DEFAULT_LARGE_FILE, G_PARAM_READWRITE));
   g_object_class_install_property (gobject_class, PROP_MOVIE_TIMESCALE,
       g_param_spec_uint ("movie-timescale", "Movie timescale",
           "Timescale to use in the movie (units per second)",
@@ -230,6 +239,20 @@
           "File that will be used temporarily to store data from the stream when "
           "creating a faststart file. If null a filepath will be created automatically",
           DEFAULT_FAST_START_TEMP_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  g_object_class_install_property (gobject_class, PROP_MOOV_TEMP_FILE,
+      g_param_spec_string ("moov-backup-file", "Backup file for storing moov atom info",
+          "File that will be used to backup moov atom data. In case of a premature end "
+          "to a recording, the moov atom can be regenerated from the xml moov backup file",
+          DEFAULT_MOOV_TEMP_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  g_object_class_install_property (gobject_class, PROP_MUX_BY_TIMESTAMP,
+      g_param_spec_boolean ("mux-by-timestamp", "Keep tracks synced by filling gaps",
+          "Use empty edit atoms, to fill gaps caused by stopping and starting media "
+          "on a given track. Sync is determined by buffer timestamps",
+          DEFAULT_MUX_BY_TIMESTAMP, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_MOOV_TEMP_FILE_KEEP,
+      g_param_spec_boolean ("moov-backup-file-keep", "Keep moov xml file",
+          "After successful moov generation, do not delete the moov xml file",
+          DEFAULT_MOOV_TEMP_FILE_KEEP, G_PARAM_READWRITE));
 
   gstelement_class->request_new_pad =
       GST_DEBUG_FUNCPTR (gst_qt_mux_request_new_pad);
@@ -246,64 +269,64 @@
   qtpad->sample_size = 0;
   qtpad->sync = FALSE;
   qtpad->last_dts = 0;
+  qtpad->trak_timescale = 0;
 
   if (qtpad->last_buf)
     gst_buffer_replace (&qtpad->last_buf, NULL);
 
-  /* reference owned elsewhere */
-  qtpad->trak = NULL;
+  /* Don't reset trak_id.. */
 }
 
 /*
  * Takes GstQTMux back to its initial state
  */
 static void
-gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc)
+gst_qt_mux_reset (GstQTMux * qtmux)
 {
   GSList *walk;
 
   qtmux->state = GST_QT_MUX_STATE_NONE;
-  qtmux->header_size = 0;
   qtmux->mdat_size = 0;
   qtmux->mdat_pos = 0;
+  qtmux->audio_trak_count = 0;
+  qtmux->video_trak_count = 0;
+  qtmux->has_h264 = FALSE;
 
-  if (qtmux->ftyp) {
-    atom_ftyp_free (qtmux->ftyp);
-    qtmux->ftyp = NULL;
-  }
-  if (qtmux->moov) {
-    atom_moov_free (qtmux->moov);
-    qtmux->moov = NULL;
-  }
-  if (qtmux->fast_start_file) {
-    fclose (qtmux->fast_start_file);
-    qtmux->fast_start_file = NULL;
-  }
-  gst_tag_setter_reset_tags (GST_TAG_SETTER (qtmux));
+  memset(qtmux->audio_trak_ids, 0, sizeof(qtmux->audio_trak_ids));
+  memset(qtmux->video_trak_ids, 0, sizeof(qtmux->video_trak_ids));
 
+  atom_ctx_reset(qtmux->context);
+
   /* reset pad data */
   for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
     GstQTPad *qtpad = (GstQTPad *) walk->data;
     gst_qt_mux_pad_reset (qtpad);
-
-    /* hm, moov_free above yanked the traks away from us,
-     * so do not free, but do clear */
-    qtpad->trak = NULL;
   }
+}
 
-  if (alloc) {
-    qtmux->moov = atom_moov_new (qtmux->context);
-    /* ensure all is as nice and fresh as request_new_pad would provide it */
-    for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
-      GstQTPad *qtpad = (GstQTPad *) walk->data;
+static gboolean
+gst_qt_mux_atom_ctx_send_cb(GstQTMux * qtmux, guint8 * data, guint size)
+{
+	GstBuffer * buf;
 
-      qtpad->trak = atom_trak_new (qtmux->context);
-      atom_moov_add_trak (qtmux->moov, qtpad->trak);
-    }
-  }
+	g_return_val_if_fail(data != NULL, FALSE);
+
+	buf = gst_buffer_new ();
+	GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+	GST_BUFFER_SIZE (buf) = size;
+
+	return (gst_qt_mux_send_buffer (qtmux, buf, NULL) == GST_FLOW_OK);
 }
 
 static void
+gst_qt_mux_atom_ctx_ping_cb(GstQTMux * qtmux)
+{
+	GstEvent * evt;
+	evt = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, NULL);
+	gst_pad_push_event (qtmux->srcpad, evt);
+}
+
+static void
 gst_qt_mux_init (GstQTMux * qtmux, GstQTMuxClass * qtmux_klass)
 {
   GstElementClass *klass = GST_ELEMENT_CLASS (qtmux_klass);
@@ -323,13 +346,15 @@
       (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_qt_mux_collected), qtmux);
 
   /* properties set to default upon construction */
+  qtmux->mux_by_timestamp = DEFAULT_MUX_BY_TIMESTAMP;
+  qtmux->moov_file_keep = DEFAULT_MOOV_TEMP_FILE_KEEP;
 
-  /* always need this */
-  qtmux->context =
-      atoms_context_new (gst_qt_mux_map_format_to_flavor (qtmux_klass->format));
-
-  /* internals to initial state */
-  gst_qt_mux_reset (qtmux, TRUE);
+  /* Remaining initializations */
+  qtmux->context = atom_ctx_new (gst_qt_mux_map_format_to_flavor(qtmux_klass->format),
+								 ATOM_CTX_SEND_DATA_CB(gst_qt_mux_atom_ctx_send_cb),
+								 ATOM_CTX_PROC_PING_CB(gst_qt_mux_atom_ctx_ping_cb),
+								 qtmux);
+  atom_ctx_timescale_set(qtmux->context, DEFAULT_MOVIE_TIMESCALE);
 }
 
 
@@ -338,20 +363,258 @@
 {
   GstQTMux *qtmux = GST_QT_MUX_CAST (object);
 
-  gst_qt_mux_reset (qtmux, FALSE);
+  gst_qt_mux_reset (qtmux);
 
-  if (qtmux->fast_start_file_path)
-    g_free (qtmux->fast_start_file_path);
+  if(qtmux->moov_file_path);
 
-  atoms_context_free (qtmux->context);
+  atom_ctx_free (qtmux->context);
   gst_object_unref (qtmux->collect);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-/* FIXME approach below is pretty Apple/MOV/MP4/iTunes specific,
- * and as such does not comply with e.g. 3GPP specs */
+static void
+gst_qt_mux_add_mp4_tag (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  switch (gst_tag_get_type (tag)) {
+      /* strings */
+    case G_TYPE_STRING:
+    {
+      gchar *str = NULL;
 
+      if (!gst_tag_list_get_string (list, tag, &str) || !str)
+        break;
+      GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+          GST_FOURCC_ARGS (fourcc), str);
+      atom_ctx_tag_str_add(qtmux->context, fourcc, str);
+      g_free (str);
+      break;
+    }
+      /* double */
+    case G_TYPE_DOUBLE:
+    {
+      gdouble value;
+
+      if (!gst_tag_list_get_double (list, tag, &value))
+        break;
+      GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u",
+          GST_FOURCC_ARGS (fourcc), (gint) value);
+      atom_ctx_tag_uint_add (qtmux->context, fourcc, 21, (guint32) value);
+      break;
+    }
+      /* paired unsigned integers */
+    case G_TYPE_UINT:
+    {
+      guint value;
+      guint count;
+
+      if (!gst_tag_list_get_uint (list, tag, &value) ||
+          !gst_tag_list_get_uint (list, tag2, &count))
+        break;
+      GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u/%u",
+          GST_FOURCC_ARGS (fourcc), value, count);
+      atom_ctx_tag_uint_add (qtmux->context, fourcc, 0,
+          value << 16 | (count & 0xFFFF));
+      break;
+    }
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static void
+gst_qt_mux_add_mp4_date (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  GDate *date = NULL;
+  GDateYear year;
+  GDateMonth month;
+  GDateDay day;
+  gchar *str;
+
+  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_DATE);
+
+  if (!gst_tag_list_get_date (list, tag, &date) || !date)
+    return;
+
+  year = g_date_get_year (date);
+  month = g_date_get_month (date);
+  day = g_date_get_day (date);
+
+  if (year == G_DATE_BAD_YEAR && month == G_DATE_BAD_MONTH &&
+      day == G_DATE_BAD_DAY) {
+    GST_WARNING_OBJECT (qtmux, "invalid date in tag");
+    return;
+  }
+
+  str = g_strdup_printf ("%u-%u-%u", year, month, day);
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+      GST_FOURCC_ARGS (fourcc), str);
+  atom_ctx_tag_str_add (qtmux->context, fourcc, str);
+}
+
+static void
+gst_qt_mux_add_mp4_cover (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  GValue value = { 0, };
+  GstBuffer *buf;
+  GstCaps *caps;
+  GstStructure *structure;
+  gint flags = 0;
+
+  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_BUFFER);
+
+  if (!gst_tag_list_copy_value (&value, list, tag))
+    return;
+
+  buf = gst_value_get_buffer (&value);
+  if (!buf)
+    goto done;
+
+  caps = gst_buffer_get_caps (buf);
+  if (!caps) {
+    GST_WARNING_OBJECT (qtmux, "preview image without caps");
+    goto done;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "preview image caps %" GST_PTR_FORMAT, caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_name (structure, "image/jpeg"))
+    flags = 13;
+  else if (gst_structure_has_name (structure, "image/png"))
+    flags = 14;
+  gst_caps_unref (caps);
+
+  if (!flags) {
+    GST_WARNING_OBJECT (qtmux, "preview image format not supported");
+    goto done;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT
+      " -> image size %d", GST_FOURCC_ARGS (fourcc), GST_BUFFER_SIZE (buf));
+  atom_ctx_tag_add (qtmux->context, fourcc, flags, GST_BUFFER_DATA (buf),
+      GST_BUFFER_SIZE (buf));
+done:
+  g_value_unset (&value);
+}
+
+static void
+gst_qt_mux_add_3gp_str (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  gchar *str = NULL;
+  guint number;
+
+  g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_STRING);
+  g_return_if_fail (!tag2 || gst_tag_get_type (tag2) == G_TYPE_UINT);
+
+  if (!gst_tag_list_get_string (list, tag, &str) || !str)
+    return;
+
+  if (tag2)
+    if (!gst_tag_list_get_uint (list, tag2, &number))
+      tag2 = NULL;
+
+  if (!tag2) {
+    GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+        GST_FOURCC_ARGS (fourcc), str);
+    atom_ctx_tag_3gp_str_add (qtmux->context, fourcc, str);
+  } else {
+    GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s/%d",
+        GST_FOURCC_ARGS (fourcc), str, number);
+    atom_ctx_tag_3gp_str_int_add (qtmux->context, fourcc, str, number);
+  }
+
+  g_free (str);
+}
+
+static void
+gst_qt_mux_add_3gp_date (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  GDate *date = NULL;
+  GDateYear year;
+
+  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_DATE);
+
+  if (!gst_tag_list_get_date (list, tag, &date) || !date)
+    return;
+
+  year = g_date_get_year (date);
+
+  if (year == G_DATE_BAD_YEAR) {
+    GST_WARNING_OBJECT (qtmux, "invalid date in tag");
+    return;
+  }
+
+  GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %d",
+      GST_FOURCC_ARGS (fourcc), year);
+  atom_ctx_tag_3gp_uint_add (qtmux->context, fourcc, year);
+}
+
+static void
+gst_qt_mux_add_3gp_location (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  gdouble latitude = -360, longitude = -360, altitude = 0;
+  gchar *location = NULL;
+  gboolean ret = FALSE;
+
+  g_return_if_fail (strcmp (tag, GST_TAG_GEO_LOCATION_NAME) == 0);
+
+  ret = gst_tag_list_get_string (list, tag, &location);
+  ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_LONGITUDE,
+      &longitude);
+  ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_LATITUDE,
+      &latitude);
+  ret |= gst_tag_list_get_double (list, GST_TAG_GEO_LOCATION_ELEVATION,
+      &altitude);
+
+  if (!ret)
+    return;
+
+  GST_DEBUG_OBJECT (qtmux, "Adding tag 'loci'");
+
+  atom_ctx_tag_3gp_location_add(qtmux->context, fourcc, location, latitude,
+      longitude, altitude);
+}
+
+static void
+gst_qt_mux_add_3gp_keywords (GstQTMux * qtmux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc)
+{
+  gchar *keywords = NULL;
+  gint i;
+  gchar **kwds;
+
+  g_return_if_fail (strcmp (tag, GST_TAG_KEYWORDS) == 0);
+
+  if (!gst_tag_list_get_string (list, tag, &keywords) || !keywords)
+    return;
+
+  kwds = g_strsplit (keywords, ",", 0);
+
+  for (i = 0; kwds[i]; ++i) {
+    GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
+        GST_FOURCC_ARGS (fourcc), kwds[i]);
+
+	atom_ctx_tag_3gp_keyword_add(qtmux->context,
+								 GST_QT_MUX_DEFAULT_TAG_LANGUAGE,
+								 kwds[i], fourcc);
+  }
+
+  g_strfreev(kwds);
+  g_free(keywords);
+}
+
+
+typedef void (*GstQTMuxAddTagFunc) (GstQTMux * mux, const GstTagList * list,
+    const char *tag, const char *tag2, guint32 fourcc);
+
 /*
  * Struct to record mappings from gstreamer tags to fourcc codes
  */
@@ -360,155 +623,80 @@
   guint32 fourcc;
   const gchar *gsttag;
   const gchar *gsttag2;
+  const GstQTMuxAddTagFunc func;
 } GstTagToFourcc;
 
 /* tag list tags to fourcc matching */
-static const GstTagToFourcc tag_matches[] = {
-  {FOURCC__alb, GST_TAG_ALBUM,},
-  {FOURCC__ART, GST_TAG_ARTIST,},
-  {FOURCC__cmt, GST_TAG_COMMENT,},
-  {FOURCC__wrt, GST_TAG_COMPOSER,},
-  {FOURCC__gen, GST_TAG_GENRE,},
-  {FOURCC__nam, GST_TAG_TITLE,},
-  {FOURCC__des, GST_TAG_DESCRIPTION,},
-  {FOURCC__too, GST_TAG_ENCODER,},
-  {FOURCC_cprt, GST_TAG_COPYRIGHT,},
-  {FOURCC_keyw, GST_TAG_KEYWORDS,},
-  {FOURCC__day, GST_TAG_DATE,},
-  {FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE,},
-  {FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT},
-  {FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT},
-  {FOURCC_covr, GST_TAG_PREVIEW_IMAGE,},
+static const GstTagToFourcc tag_matches_mp4[] = {
+  {FOURCC__alb, GST_TAG_ALBUM, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__ART, GST_TAG_ARTIST, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__cmt, GST_TAG_COMMENT, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__wrt, GST_TAG_COMPOSER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__gen, GST_TAG_GENRE, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__nam, GST_TAG_TITLE, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__des, GST_TAG_DESCRIPTION, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__too, GST_TAG_ENCODER, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_keyw, GST_TAG_KEYWORDS, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC__day, GST_TAG_DATE, NULL, gst_qt_mux_add_mp4_date},
+  {FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, gst_qt_mux_add_mp4_tag},
+  {FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT,
+      gst_qt_mux_add_mp4_tag},
+  {FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
+      gst_qt_mux_add_mp4_tag},
+  {FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, gst_qt_mux_add_mp4_cover},
   {0, NULL,}
 };
 
+static const GstTagToFourcc tag_matches_3gp[] = {
+  {FOURCC_titl, GST_TAG_TITLE, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_perf, GST_TAG_ARTIST, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_auth, GST_TAG_COMPOSER, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_gnre, GST_TAG_GENRE, NULL, gst_qt_mux_add_3gp_str},
+  {FOURCC_kywd, GST_TAG_KEYWORDS, NULL, gst_qt_mux_add_3gp_keywords},
+  {FOURCC_yrrc, GST_TAG_DATE, NULL, gst_qt_mux_add_3gp_date},
+  {FOURCC_albm, GST_TAG_ALBUM, GST_TAG_TRACK_NUMBER, gst_qt_mux_add_3gp_str},
+  {FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, gst_qt_mux_add_3gp_location},
+  {0, NULL,}
+};
+
 /* qtdemux produces these for atoms it cannot parse */
 #define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag"
 
 static void
 gst_qt_mux_add_metadata_tags (GstQTMux * qtmux, const GstTagList * list)
 {
+  GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
   guint32 fourcc;
   gint i;
   const gchar *tag, *tag2;
+  const GstTagToFourcc *tag_matches;
 
+  switch (qtmux_klass->format) {
+    case GST_QT_MUX_FORMAT_3GP:
+      tag_matches = tag_matches_3gp;
+      break;
+    case GST_QT_MUX_FORMAT_MJ2:
+      tag_matches = NULL;
+      break;
+    default:
+      /* sort of iTunes style for mp4 and QT (?) */
+      tag_matches = tag_matches_mp4;
+      break;
+  }
+
+  if (!tag_matches)
+    return;
+
   for (i = 0; tag_matches[i].fourcc; i++) {
     fourcc = tag_matches[i].fourcc;
     tag = tag_matches[i].gsttag;
     tag2 = tag_matches[i].gsttag2;
 
-    switch (gst_tag_get_type (tag)) {
-        /* strings */
-      case G_TYPE_STRING:
-      {
-        gchar *str = NULL;
-
-        if (!gst_tag_list_get_string (list, tag, &str) || !str)
-          break;
-        GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
-            GST_FOURCC_ARGS (fourcc), str);
-        atom_moov_add_str_tag (qtmux->moov, fourcc, str);
-        g_free (str);
-        break;
-      }
-        /* double */
-      case G_TYPE_DOUBLE:
-      {
-        gdouble value;
-
-        if (!gst_tag_list_get_double (list, tag, &value))
-          break;
-        GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u",
-            GST_FOURCC_ARGS (fourcc), (gint) value);
-        atom_moov_add_uint_tag (qtmux->moov, fourcc, 21, (gint) value);
-        break;
-      }
-        /* paired unsigned integers */
-      case G_TYPE_UINT:
-      {
-        guint value;
-        guint count;
-
-        if (!gst_tag_list_get_uint (list, tag, &value) ||
-            !gst_tag_list_get_uint (list, tag2, &count))
-          break;
-        GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %u/%u",
-            GST_FOURCC_ARGS (fourcc), value, count);
-        atom_moov_add_uint_tag (qtmux->moov, fourcc, 0,
-            value << 16 | (count & 0xFFFF));
-        break;
-      }
-      default:
-      {
-        if (gst_tag_get_type (tag) == GST_TYPE_DATE) {
-          GDate *date = NULL;
-          GDateYear year;
-          GDateMonth month;
-          GDateDay day;
-          gchar *str;
-
-          if (!gst_tag_list_get_date (list, tag, &date) || !date)
-            break;
-          year = g_date_get_year (date);
-          month = g_date_get_month (date);
-          day = g_date_get_day (date);
-
-          if (year == G_DATE_BAD_YEAR && month == G_DATE_BAD_MONTH &&
-              day == G_DATE_BAD_DAY) {
-            GST_WARNING_OBJECT (qtmux, "invalid date in tag");
-            break;
-          }
-
-          str = g_strdup_printf ("%u-%u-%u", year, month, day);
-          GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT " -> %s",
-              GST_FOURCC_ARGS (fourcc), str);
-          atom_moov_add_str_tag (qtmux->moov, fourcc, str);
-        } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
-          GValue value = { 0, };
-          GstBuffer *buf;
-          GstCaps *caps;
-          GstStructure *structure;
-          gint flags = 0;
-
-          if (!gst_tag_list_copy_value (&value, list, tag))
-            break;
-
-          buf = gst_value_get_buffer (&value);
-          if (!buf)
-            goto done;
-
-          caps = gst_buffer_get_caps (buf);
-          if (!caps) {
-            GST_WARNING_OBJECT (qtmux, "preview image without caps");
-            goto done;
-          }
-
-          GST_DEBUG_OBJECT (qtmux, "preview image caps %" GST_PTR_FORMAT, caps);
-
-          structure = gst_caps_get_structure (caps, 0);
-          if (gst_structure_has_name (structure, "image/jpeg"))
-            flags = 13;
-          else if (gst_structure_has_name (structure, "image/png"))
-            flags = 14;
-          gst_caps_unref (caps);
-
-          if (!flags) {
-            GST_WARNING_OBJECT (qtmux, "preview image format not supported");
-            goto done;
-          }
-
-          GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT
-              " -> image size %d", GST_FOURCC_ARGS (fourcc),
-              GST_BUFFER_SIZE (buf));
-          atom_moov_add_tag (qtmux->moov, fourcc, flags, GST_BUFFER_DATA (buf),
-              GST_BUFFER_SIZE (buf));
-        done:
-          g_value_unset (&value);
-        } else
-          g_assert_not_reached ();
-        break;
-      }
-    }
+    g_assert (tag_matches[i].func);
+    tag_matches[i].func (qtmux, list, tag, tag2, fourcc);
   }
 
   /* add unparsed blobs if present */
@@ -532,10 +720,14 @@
             GST_PTR_FORMAT, i, num_tags, GST_BUFFER_SIZE (buf), caps);
         s = gst_caps_get_structure (caps, 0);
         if (s && (style = gst_structure_get_string (s, "style"))) {
-          /* FIXME make into a parameter */
-          if (strcmp (style, "itunes") == 0) {
+          /* try to prevent some style tag ending up into another variant
+           * (todo: make into a list if more cases) */
+          if ((strcmp (style, "itunes") == 0 &&
+                  qtmux_klass->format == GST_QT_MUX_FORMAT_MP4) ||
+              (strcmp (style, "iso") == 0 &&
+                  qtmux_klass->format == GST_QT_MUX_FORMAT_3GP)) {
             GST_DEBUG_OBJECT (qtmux, "Adding private tag");
-            atom_moov_add_blob_tag (qtmux->moov, GST_BUFFER_DATA (buf),
+            atom_ctx_tag_blob_add (qtmux->context, GST_BUFFER_DATA (buf),
                 GST_BUFFER_SIZE (buf));
           }
         }
@@ -547,190 +739,26 @@
   return;
 }
 
-/*
- * Gets the tagsetter iface taglist and puts the known tags
- * into the output stream
- */
-static void
-gst_qt_mux_setup_metadata (GstQTMux * qtmux)
-{
-  const GstTagList *tags;
-
-  tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (qtmux));
-
-  GST_LOG_OBJECT (qtmux, "tags: %" GST_PTR_FORMAT, tags);
-
-  if (tags && !gst_tag_list_is_empty (tags)) {
-    GST_DEBUG_OBJECT (qtmux, "Formatting tags");
-    gst_qt_mux_add_metadata_tags (qtmux, tags);
-  } else {
-    GST_DEBUG_OBJECT (qtmux, "No tags received");
-  }
-}
-
 static GstFlowReturn
-gst_qt_mux_send_buffer (GstQTMux * qtmux, GstBuffer * buf, guint64 * offset,
-    gboolean mind_fast)
+gst_qt_mux_send_buffer (GstQTMux * qtmux, GstBuffer * buf, guint64 * offset)
 {
   GstFlowReturn res;
-  guint8 *data;
-  guint size;
 
   g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
 
-  data = GST_BUFFER_DATA (buf);
-  size = GST_BUFFER_SIZE (buf);
+  GST_LOG_OBJECT (qtmux, "sending buffer size %d", GST_BUFFER_SIZE (buf));
 
-  GST_LOG_OBJECT (qtmux, "sending buffer size %d", size);
+  gst_buffer_set_caps (buf, GST_PAD_CAPS (qtmux->srcpad));
+  res = gst_pad_push (qtmux->srcpad, buf);
 
-  if (mind_fast && qtmux->fast_start_file) {
-    gint ret;
-
-    GST_LOG_OBJECT (qtmux, "to temporary file");
-    ret = fwrite (data, sizeof (guint8), size, qtmux->fast_start_file);
-    gst_buffer_unref (buf);
-    if (ret != size)
-      goto write_error;
-    else
-      res = GST_FLOW_OK;
-  } else {
-    GST_LOG_OBJECT (qtmux, "downstream");
-
-    gst_buffer_set_caps (buf, GST_PAD_CAPS (qtmux->srcpad));
-    res = gst_pad_push (qtmux->srcpad, buf);
+  if (G_LIKELY (offset)) {
+    *offset += GST_BUFFER_SIZE (buf);
   }
 
-  if (offset)
-    *offset += size;
-
   return res;
-
-  /* ERRORS */
-write_error:
-  {
-    GST_ELEMENT_ERROR (qtmux, RESOURCE, WRITE,
-        ("Failed to write to temporary file"), GST_ERROR_SYSTEM);
-    return GST_FLOW_ERROR;
-  }
 }
 
-static GstFlowReturn
-gst_qt_mux_send_buffered_data (GstQTMux * qtmux, guint64 * offset)
-{
-  GstFlowReturn ret = GST_FLOW_OK;
-  GstBuffer *buf = NULL;
-
-  if (fflush (qtmux->fast_start_file))
-    goto flush_failed;
-
-#ifdef HAVE_FSEEKO
-  if (fseeko (qtmux->fast_start_file, (off_t) 0, SEEK_SET) != 0)
-    goto seek_failed;
-#elif defined (G_OS_UNIX) || defined (G_OS_WIN32)
-  if (lseek (fileno (qtmux->fast_start_file), (off_t) 0,
-          SEEK_SET) == (off_t) - 1)
-    goto seek_failed;
-#else
-  if (fseek (qtmux->fast_start_file, (long) 0, SEEK_SET) != 0)
-    goto seek_failed;
-#endif
-
-  /* hm, this could all take a really really long time,
-   * but there may not be another way to get moov atom first
-   * (somehow optimize copy?) */
-  GST_DEBUG_OBJECT (qtmux, "Sending buffered data");
-  while (ret == GST_FLOW_OK) {
-    gint r;
-    const int bufsize = 4096;
-
-    buf = gst_buffer_new_and_alloc (bufsize);
-    r = fread (GST_BUFFER_DATA (buf), sizeof (guint8), bufsize,
-        qtmux->fast_start_file);
-    if (r == 0)
-      break;
-    GST_BUFFER_SIZE (buf) = r;
-    GST_LOG_OBJECT (qtmux, "Pushing buffered buffer of size %d", r);
-    ret = gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
-    buf = NULL;
-  }
-  if (buf)
-    gst_buffer_unref (buf);
-
-exit:
-  /* best cleaning up effort, eat possible error */
-  fclose (qtmux->fast_start_file);
-  qtmux->fast_start_file = NULL;
-
-  /* FIXME maybe delete temporary file, or let the system handle that ? */
-
-  return ret;
-
-  /* ERRORS */
-flush_failed:
-  {
-    GST_ELEMENT_ERROR (qtmux, RESOURCE, WRITE,
-        ("Failed to flush temporary file"), GST_ERROR_SYSTEM);
-    ret = GST_FLOW_ERROR;
-    goto exit;
-  }
-seek_failed:
-  {
-    GST_ELEMENT_ERROR (qtmux, RESOURCE, SEEK,
-        ("Failed to seek temporary file"), GST_ERROR_SYSTEM);
-    ret = GST_FLOW_ERROR;
-    goto exit;
-  }
-}
-
 /*
- * Sends the initial mdat atom fields (size fields and fourcc type),
- * the subsequent buffers are considered part of it's data.
- * As we can't predict the amount of data that we are going to place in mdat
- * we need to record the position of the size field in the stream so we can
- * seek back to it later and update when the streams have finished.
- */
-static GstFlowReturn
-gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size)
-{
-  Atom *node_header;
-  GstBuffer *buf;
-  guint8 *data = NULL;
-  guint64 offset = 0;
-
-  GST_DEBUG_OBJECT (qtmux, "Sending mdat's atom header, "
-      "size %" G_GUINT64_FORMAT, size);
-
-  node_header = g_malloc0 (sizeof (Atom));
-  node_header->type = FOURCC_mdat;
-  /* use extended size */
-  node_header->size = 1;
-  node_header->extended_size = 0;
-  if (size)
-    node_header->extended_size = size;
-
-  size = offset = 0;
-  if (atom_copy_data (node_header, &data, &size, &offset) == 0)
-    goto serialize_error;
-
-  buf = gst_buffer_new ();
-  GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
-  GST_BUFFER_SIZE (buf) = offset;
-
-  g_free (node_header);
-
-  GST_LOG_OBJECT (qtmux, "Pushing mdat start");
-  return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
-
-  /* ERRORS */
-serialize_error:
-  {
-    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
-        ("Failed to serialize ftyp"));
-    return GST_FLOW_ERROR;
-  }
-}
-
-/*
  * We get the position of the mdat size field, seek back to it
  * and overwrite with the real value
  */
@@ -739,29 +767,24 @@
     guint64 mdat_size, guint64 * offset)
 {
   GstEvent *event;
-  GstBuffer *buf;
 
   /* seek and rewrite the header */
   event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
       mdat_pos, GST_CLOCK_TIME_NONE, 0);
   gst_pad_push_event (qtmux->srcpad, event);
 
-  buf = gst_buffer_new_and_alloc (sizeof (guint64));
-  GST_WRITE_UINT64_BE (GST_BUFFER_DATA (buf), mdat_size);
+  if(atom_ctx_mdat_header_send(qtmux->context, mdat_size, offset))
+    return GST_FLOW_OK;
 
-  return gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
+  return GST_FLOW_ERROR;
 }
 
 static GstFlowReturn
 gst_qt_mux_stop_file (GstQTMux * qtmux)
 {
   gboolean ret = GST_FLOW_OK;
-  GstBuffer *buffer = NULL;
-  guint64 offset = 0, size = 0;
-  guint8 *data;
   GSList *walk;
-  gboolean large_file;
-  guint32 timescale;
+  gboolean largefile = FALSE;
 
   GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
 
@@ -780,122 +803,35 @@
           gst_flow_get_name (ret));
   }
 
-  GST_OBJECT_LOCK (qtmux);
-  timescale = qtmux->timescale;
-  large_file = qtmux->large_file;
-  GST_OBJECT_UNLOCK (qtmux);
+  GST_LOG_OBJECT (qtmux, "Copying movie header into buffer.");
 
-  /* inform lower layers of our property wishes, and determine duration.
-   * Let moov take care of this using its list of traks;
-   * so that released pads are also included */
-  GST_DEBUG_OBJECT (qtmux, "Large file support: %d", large_file);
-  GST_DEBUG_OBJECT (qtmux, "Updating timescale to %" G_GUINT32_FORMAT,
-      timescale);
-  atom_moov_update_timescale (qtmux->moov, timescale);
-  atom_moov_set_64bits (qtmux->moov, large_file);
-  atom_moov_update_duration (qtmux->moov);
+  /* Lets figure out whether we need large file support */
+  largefile = (((qtmux->mdat_size+8) > G_MAXUINT32) ? TRUE : FALSE);
 
-  /* tags into file metadata */
-  gst_qt_mux_setup_metadata (qtmux);
+  /* Send the 'moov' atom */
+  if(!atom_ctx_moov_send (qtmux->context, qtmux->mdat_pos, largefile, qtmux->moov_file_keep, NULL))
+	  return GST_FLOW_ERROR;
 
-  /* if faststart, update the offset of the atoms in the movie with the offset
-   * that the movie headers before mdat will cause */
-  if (qtmux->fast_start_file) {
-    /* copy into NULL to obtain size */
-    offset = size = 0;
-    if (!atom_moov_copy_data (qtmux->moov, NULL, &size, &offset))
-      goto serialize_error;
-    GST_DEBUG_OBJECT (qtmux, "calculated moov atom size %" G_GUINT64_FORMAT,
-        size);
-    offset += qtmux->header_size + MDAT_ATOM_HEADER_SIZE;
-  } else
-    offset = qtmux->header_size;
-  atom_moov_chunks_add_offset (qtmux->moov, offset);
+  /* mdata needs update iff not using faststart */
+  GST_DEBUG_OBJECT (qtmux, "updating mdata size");
 
-  /* serialize moov */
-  offset = size = 0;
-  data = NULL;
-  GST_LOG_OBJECT (qtmux, "Copying movie header into buffer");
-  ret = atom_moov_copy_data (qtmux->moov, &data, &size, &offset);
-  if (!ret)
-    goto serialize_error;
+  ret = gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
+									 qtmux->mdat_size, NULL);
+  /* note; no seeking back to the end of file is done,
+   * since we longer write anything anyway */
 
-  buffer = gst_buffer_new ();
-  GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer) = data;
-  GST_BUFFER_SIZE (buffer) = offset;
-  /* note: as of this point, we no longer care about tracking written data size,
-   * since there is no more use for it anyway */
-  GST_DEBUG_OBJECT (qtmux, "Pushing movie atoms");
-  gst_qt_mux_send_buffer (qtmux, buffer, NULL, FALSE);
-
-  /* total mdat size as of now also includes the atom header */
-  qtmux->mdat_size += MDAT_ATOM_HEADER_SIZE;
-  /* if needed, send mdat atom and move buffered data into it */
-  if (qtmux->fast_start_file) {
-    /* mdat size = accumulated (buffered data) + mdat atom header */
-    ret = gst_qt_mux_send_mdat_header (qtmux, NULL, qtmux->mdat_size);
-    if (ret != GST_FLOW_OK)
-      return ret;
-    ret = gst_qt_mux_send_buffered_data (qtmux, NULL);
-    if (ret != GST_FLOW_OK)
-      return ret;
-  } else {
-    /* mdata needs update iff not using faststart */
-    GST_DEBUG_OBJECT (qtmux, "updating mdata size");
-    ret = gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
-        qtmux->mdat_size, NULL);
-    /* note; no seeking back to the end of file is done,
-     * since we longer write anything anyway */
-  }
-
   return ret;
-
-  /* ERRORS */
-serialize_error:
-  {
-    gst_buffer_unref (buffer);
-    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
-        ("Failed to serialize moov"));
-    return GST_FLOW_ERROR;
-  }
 }
 
 static GstFlowReturn
-gst_qt_mux_send_ftyp (GstQTMux * qtmux, guint64 * off)
-{
-  GstBuffer *buf;
-  guint64 size = 0, offset = 0;
-  guint8 *data = NULL;
-
-  GST_DEBUG_OBJECT (qtmux, "Sending ftyp atom");
-
-  if (!atom_ftyp_copy_data (qtmux->ftyp, &data, &size, &offset))
-    goto serialize_error;
-
-  buf = gst_buffer_new ();
-  GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
-  GST_BUFFER_SIZE (buf) = offset;
-
-  GST_LOG_OBJECT (qtmux, "Pushing ftyp");
-  return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
-
-  /* ERRORS */
-serialize_error:
-  {
-    GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
-        ("Failed to serialize ftyp"));
-    return GST_FLOW_ERROR;
-  }
-}
-
-static GstFlowReturn
 gst_qt_mux_start_file (GstQTMux * qtmux)
 {
   GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
   GstFlowReturn ret = GST_FLOW_OK;
   guint32 major, version;
-  GList *comp;
-  GstBuffer *prefix;
+  GList *comp = NULL;
+  GstBuffer *prefix = NULL;
+  guint64 bsent = 0;
 
   GST_DEBUG_OBJECT (qtmux, "starting file");
 
@@ -903,48 +839,35 @@
   gst_pad_push_event (qtmux->srcpad,
       gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
 
-  /* init and send context and ftyp based on current property state */
-  if (qtmux->ftyp)
-    atom_ftyp_free (qtmux->ftyp);
   gst_qt_mux_map_format_to_header (qtmux_klass->format, &prefix, &major,
-      &version, &comp, qtmux->moov);
-  qtmux->ftyp = atom_ftyp_new (qtmux->context, major, version, comp);
-  if (comp)
-    g_list_free (comp);
+     &version, &comp, qtmux->video_trak_count, qtmux->audio_trak_count,
+     qtmux->has_h264);
+
   if (prefix) {
-    ret = gst_qt_mux_send_buffer (qtmux, prefix, &qtmux->header_size, FALSE);
+    ret = gst_qt_mux_send_buffer (qtmux, prefix, &bsent);
     if (ret != GST_FLOW_OK)
       goto exit;
   }
-  ret = gst_qt_mux_send_ftyp (qtmux, &qtmux->header_size);
-  if (ret != GST_FLOW_OK)
-    goto exit;
 
+  if(!atom_ctx_ftyp_send(qtmux->context, major, version, comp, &bsent)) {
+	  ret = GST_FLOW_ERROR;
+	  goto exit;
+  }
+
   /* send mdat header if already needed, and mark position for later update */
   GST_OBJECT_LOCK (qtmux);
-  if (qtmux->fast_start) {
-    qtmux->fast_start_file = g_fopen (qtmux->fast_start_file_path, "wb+");
-    if (!qtmux->fast_start_file)
-      goto open_failed;
-  } else {
-    ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0);
-    /* mdat size position = current header pos - extended header size */
-    qtmux->mdat_pos = qtmux->header_size - sizeof (guint64);
-  }
+  qtmux->mdat_pos = bsent;
+  if(!atom_ctx_mdat_header_send(qtmux->context, 0, NULL))
+	  ret = GST_FLOW_ERROR;
   GST_OBJECT_UNLOCK (qtmux);
 
+  GST_DEBUG_OBJECT (qtmux, "starting file. done: %llu", bsent);
+
 exit:
-  return ret;
+  if (comp)
+    g_list_free (comp);
 
-  /* ERRORS */
-open_failed:
-  {
-    GST_ELEMENT_ERROR (qtmux, RESOURCE, OPEN_READ_WRITE,
-        (("Could not open temporary file \"%s\""), qtmux->fast_start_file_path),
-        GST_ERROR_SYSTEM);
-    GST_OBJECT_UNLOCK (qtmux);
-    return GST_FLOW_ERROR;
-  }
+  return ret;
 }
 
 /*
@@ -978,6 +901,14 @@
     }
 #endif
     pad->last_buf = buf;
+
+    if(qtmux->mux_by_timestamp) {
+      /*
+       * Notify the atom context of the track start timestamp, needed
+       * to determine duration (if any) of initial empty edit atom.
+       */
+      atom_ctx_start_ts_add(qtmux->context, pad->trak_id, GST_BUFFER_TIMESTAMP(buf));
+    }
     return GST_FLOW_OK;
   } else
     gst_buffer_ref (last_buf);
@@ -1005,8 +936,7 @@
 
   gst_buffer_replace (&pad->last_buf, buf);
 
-  last_dts = gst_util_uint64_scale (pad->last_dts,
-      atom_trak_get_timescale (pad->trak), GST_SECOND);
+  last_dts = gst_util_uint64_scale (pad->last_dts, pad->trak_timescale, GST_SECOND);
 
   /* raw audio has many samples per buffer (= chunk) */
   if (pad->sample_size) {
@@ -1027,11 +957,9 @@
       gint64 scaled_dts;
       pad->last_dts = GST_BUFFER_OFFSET_END (last_buf);
       if ((gint64) (pad->last_dts) < 0) {
-        scaled_dts = -gst_util_uint64_scale (-pad->last_dts,
-            atom_trak_get_timescale (pad->trak), GST_SECOND);
+        scaled_dts = -gst_util_uint64_scale (-pad->last_dts, pad->trak_timescale, GST_SECOND);
       } else {
-        scaled_dts = gst_util_uint64_scale (pad->last_dts,
-            atom_trak_get_timescale (pad->trak), GST_SECOND);
+        scaled_dts = gst_util_uint64_scale (pad->last_dts, pad->trak_timescale, GST_SECOND);
       }
       scaled_duration = scaled_dts - last_dts;
       last_dts = scaled_dts;
@@ -1041,7 +969,7 @@
        * this ensures sums of (scale)delta add up to converted timestamp,
        * which only deviates at most 1/scale from timestamp itself */
       scaled_duration = gst_util_uint64_scale (pad->last_dts + duration,
-          atom_trak_get_timescale (pad->trak), GST_SECOND) - last_dts;
+          pad->trak_timescale, GST_SECOND) - last_dts;
       pad->last_dts += duration;
     }
   }
@@ -1076,7 +1004,7 @@
     guint64 pts;
 
     pts = gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (last_buf),
-        atom_trak_get_timescale (pad->trak), GST_SECOND);
+        pad->trak_timescale, GST_SECOND);
     pts_offset = (gint64) (pts - last_dts);
     do_pts = TRUE;
     GST_LOG_OBJECT (qtmux, "Adding ctts entry for pad %s: %" G_GINT64_FORMAT,
@@ -1085,13 +1013,13 @@
 
   /* now we go and register this buffer/sample all over */
   /* note that a new chunk is started each time (not fancy but works) */
-  atom_trak_add_samples (pad->trak, nsamples, scaled_duration, sample_size,
+  atom_ctx_samples_add (qtmux->context, pad->trak_id, nsamples, scaled_duration, sample_size,
       chunk_offset, sync, do_pts, pts_offset);
 
   if (buf)
     gst_buffer_unref (buf);
 
-  return gst_qt_mux_send_buffer (qtmux, last_buf, &qtmux->mdat_size, TRUE);
+  return gst_qt_mux_send_buffer (qtmux, last_buf, &qtmux->mdat_size);
 
   /* ERRORS */
 bail:
@@ -1199,9 +1127,8 @@
   const GValue *value = NULL;
   const GstBuffer *codec_data = NULL;
   GstQTMuxFormat format;
-  AudioSampleEntry entry = { 0, };
-  AtomInfo *ext_atom = NULL;
-  gint constant_size = 0;
+  AtomContextAudioEntry entry = { 0, };
+  gboolean ret = FALSE;
 
   /* find stream data */
   qtpad = (GstQTPad *) gst_pad_get_element_private (pad);
@@ -1226,14 +1153,19 @@
 
   /* optional */
   value = gst_structure_get_value (structure, "codec_data");
-  if (value != NULL)
-    codec_data = gst_value_get_buffer (value);
+  if (value && (codec_data = gst_value_get_buffer (value))) {
+	  if(GST_BUFFER_SIZE(codec_data) > 0) {
+		  entry.codec_data = g_memdup(GST_BUFFER_DATA(codec_data),
+									  GST_BUFFER_SIZE(codec_data));
+		  entry.codec_data_size = GST_BUFFER_SIZE(codec_data);
+	  }
+  }
 
   qtpad->is_out_of_order = FALSE;
   qtpad->have_dts = FALSE;
 
   /* set common properties */
-  entry.sample_rate = rate;
+  qtpad->trak_timescale = entry.sample_rate = rate;
   entry.channels = channels;
   /* default */
   entry.sample_size = 16;
@@ -1260,9 +1192,7 @@
               entry.fourcc = FOURCC__mp3;
             else {
               entry.fourcc = FOURCC_mp4a;
-              ext_atom =
-                  build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG1_P3,
-                  ESDS_STREAM_TYPE_AUDIO, codec_data);
+			  entry.audio_ext = ATOM_CTX_AUDIO_EXT_MP1_P3;
             }
             entry.samples_per_packet = 1152;
             entry.bytes_per_sample = 2;
@@ -1284,11 +1214,9 @@
                 "non-LC AAC may not run well on (Apple) QuickTime/iTunes");
         }
         if (format == GST_QT_MUX_FORMAT_QT)
-          ext_atom = build_mov_aac_extension (qtpad->trak, codec_data);
+          entry.audio_ext = ATOM_CTX_AUDIO_EXT_AAC;
         else
-          ext_atom =
-              build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P3,
-              ESDS_STREAM_TYPE_AUDIO, codec_data);
+          entry.audio_ext = ATOM_CTX_AUDIO_EXT_MP4_P3;
         break;
       default:
         break;
@@ -1298,13 +1226,13 @@
     entry.sample_size = 16;
     entry.samples_per_packet = 160;
     entry.bytes_per_sample = 2;
-    ext_atom = build_amr_extension ();
+    entry.audio_ext = ATOM_CTX_AUDIO_EXT_AMR;
   } else if (strcmp (mimetype, "audio/AMR-WB") == 0) {
     entry.fourcc = FOURCC_sawb;
     entry.sample_size = 16;
     entry.samples_per_packet = 320;
     entry.bytes_per_sample = 2;
-    ext_atom = build_amr_extension ();
+    entry.audio_ext = ATOM_CTX_AUDIO_EXT_AMR;
   } else if (strcmp (mimetype, "audio/x-raw-int") == 0) {
     gint width;
     gint depth;
@@ -1313,13 +1241,19 @@
 
     if (!gst_structure_get_int (structure, "width", &width) ||
         !gst_structure_get_int (structure, "depth", &depth) ||
-        !gst_structure_get_boolean (structure, "signed", &sign) ||
-        !gst_structure_get_int (structure, "endianness", &endianness)) {
-      GST_DEBUG_OBJECT (qtmux,
-          "broken caps, width/depth/signed/endianness field missing");
+        !gst_structure_get_boolean (structure, "signed", &sign)) {
+      GST_DEBUG_OBJECT (qtmux, "broken caps, width/depth/signed field missing");
       goto refuse_caps;
     }
 
+    if (depth <= 8) {
+      endianness = G_BYTE_ORDER;
+    } else if (!gst_structure_get_boolean (structure,
+            "endianness", &endianness)) {
+      GST_DEBUG_OBJECT (qtmux, "broken caps, endianness field missing");
+      goto refuse_caps;
+    }
+
     /* spec has no place for a distinction in these */
     if (width != depth) {
       GST_DEBUG_OBJECT (qtmux, "width must be same as depth!");
@@ -1355,7 +1289,7 @@
         goto refuse_caps;
       }
     }
-    constant_size = (depth / 8) * channels;
+    entry.sample_fixed_size = (depth / 8) * channels;
   } else if (strcmp (mimetype, "audio/x-alaw") == 0) {
     entry.fourcc = FOURCC_alaw;
     entry.samples_per_packet = 1023;
@@ -1371,12 +1305,16 @@
 
   /* ok, set the pad info accordingly */
   qtpad->fourcc = entry.fourcc;
-  qtpad->sample_size = constant_size;
-  atom_trak_set_audio_type (qtpad->trak, qtmux->context, &entry,
-      entry.sample_rate, ext_atom, constant_size);
+  qtpad->sample_size = entry.sample_fixed_size;
 
+  qtmux->audio_trak_count += 1;
+
+  /* Configure the moov trak atom */
+  atom_ctx_track_audio_set (qtmux->context, qtpad->trak_id, &entry);
+
   gst_object_unref (qtmux);
-  return TRUE;
+  ret = TRUE;
+  goto end;
 
   /* ERRORS */
 refuse_caps:
@@ -1384,7 +1322,7 @@
     GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
         GST_PAD_NAME (pad), caps);
     gst_object_unref (qtmux);
-    return FALSE;
+	goto end;
   }
 refuse_renegotiation:
   {
@@ -1392,8 +1330,12 @@
         "pad %s refused renegotiation to %" GST_PTR_FORMAT,
         GST_PAD_NAME (pad), caps);
     gst_object_unref (qtmux);
-    return FALSE;
+	goto end;
   }
+
+ end:
+  g_free(entry.codec_data);
+  return ret;
 }
 
 /* scale rate up or down by factor of 10 to fit into [1000,10000] interval */
@@ -1419,14 +1361,13 @@
   const gchar *mimetype;
   gint width, height, depth = -1;
   gint framerate_num, framerate_den;
-  guint32 rate;
   const GValue *value = NULL;
   const GstBuffer *codec_data = NULL;
-  VisualSampleEntry entry = { 0, };
+  AtomContextVisualEntry entry = { 0, };
   GstQTMuxFormat format;
-  AtomInfo *ext_atom = NULL;
   gboolean sync = FALSE;
   int par_num, par_den;
+  gboolean ret = FALSE;
 
   /* find stream data */
   qtpad = (GstQTPad *) gst_pad_get_element_private (pad);
@@ -1457,26 +1398,32 @@
       &framerate_den);
   gst_structure_get_int (structure, "depth", &depth);
   value = gst_structure_get_value (structure, "codec_data");
-  if (value != NULL)
-    codec_data = gst_value_get_buffer (value);
+  if (value && (codec_data = gst_value_get_buffer (value))) {
+    if(GST_BUFFER_SIZE(codec_data) > 0) {
+	  entry.codec_data = g_memdup(GST_BUFFER_DATA(codec_data),
+								  GST_BUFFER_SIZE(codec_data));
+      entry.codec_data_size = GST_BUFFER_SIZE(codec_data);
+    }
+  }
 
   par_num = 1;
   par_den = 1;
   gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_num,
       &par_den);
-  /* FIXME: pixel-aspect-ratio */
 
   qtpad->is_out_of_order = FALSE;
 
   /* bring frame numerator into a range that ensures both reasonable resolution
    * as well as a fair duration */
-  rate = adjust_rate (framerate_num);
+  qtpad->trak_timescale = entry.timescale = adjust_rate (framerate_num);
   GST_DEBUG_OBJECT (qtmux, "Rate of video track selected: %" G_GUINT32_FORMAT,
-      rate);
+      entry.timescale);
 
   /* set common properties */
   entry.width = width;
   entry.height = height;
+  entry.par_n = par_num;
+  entry.par_d = par_den;
   /* should be OK according to qt and iso spec, override if really needed */
   entry.color_table_id = -1;
   entry.frame_count = 1;
@@ -1507,8 +1454,11 @@
         break;
     }
   } else if (strcmp (mimetype, "video/x-h263") == 0) {
-    entry.fourcc = FOURCC_h263;
-    ext_atom = build_h263_extension ();
+    if (format == GST_QT_MUX_FORMAT_QT)
+      entry.fourcc = FOURCC_h263;
+    else
+      entry.fourcc = FOURCC_s263;
+    entry.visual_ext = ATOM_CTX_VISUAL_EXT_H263;
   } else if (strcmp (mimetype, "video/x-divx") == 0 ||
       strcmp (mimetype, "video/mpeg") == 0) {
     gint version = 0;
@@ -1522,9 +1472,7 @@
     }
     if (version) {
       entry.fourcc = FOURCC_mp4v;
-      ext_atom =
-          build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P2,
-          ESDS_STREAM_TYPE_VISUAL, codec_data);
+      entry.visual_ext = ATOM_CTX_VISUAL_EXT_MP4_P2;
       if (!codec_data)
         GST_WARNING_OBJECT (qtmux, "no codec_data for MPEG4 video; "
             "output might not play in Apple QuickTime (try global-headers?)");
@@ -1534,7 +1482,7 @@
     qtpad->is_out_of_order = TRUE;
     if (!codec_data)
       GST_WARNING_OBJECT (qtmux, "no codec_data in h264 caps");
-    ext_atom = build_codec_data_extension (FOURCC_avcC, codec_data);
+    entry.visual_ext = ATOM_CTX_VISUAL_EXT_AVCC;
   } else if (strcmp (mimetype, "video/x-dv") == 0) {
     gint version = 0;
     gboolean pal = TRUE;
@@ -1567,13 +1515,13 @@
     entry.fourcc = FOURCC_jpeg;
     sync = FALSE;
   } else if (strcmp (mimetype, "image/x-j2c") == 0) {
-    guint32 fourcc;
-
     entry.fourcc = FOURCC_mjp2;
     sync = FALSE;
-    if (!gst_structure_get_fourcc (structure, "fourcc", &fourcc) ||
-        !(ext_atom =
-            build_jp2h_extension (qtpad->trak, width, height, fourcc))) {
+    if (gst_structure_get_fourcc (structure, "fourcc", &entry.sub_fourcc)) {
+      /* TODO: Evaluate whether 'fourcc' is invalid .. */
+      entry.visual_ext = ATOM_CTX_VISUAL_EXT_JP2H;
+	}
+	else {
       GST_DEBUG_OBJECT (qtmux, "missing or invalid fourcc in jp2 caps");
       goto refuse_caps;
     }
@@ -1599,11 +1547,18 @@
   /* ok, set the pad info accordingly */
   qtpad->fourcc = entry.fourcc;
   qtpad->sync = sync;
-  atom_trak_set_video_type (qtpad->trak, qtmux->context, &entry, rate,
-      ext_atom);
 
+  /* Track this.. */
+  if(!qtmux->has_h264)
+	  qtmux->has_h264 = (entry.fourcc == FOURCC_avc1);
+  qtmux->video_trak_count += 1;
+
+  /* Configure the moov trak atom */
+  atom_ctx_track_video_set (qtmux->context, qtpad->trak_id, &entry);
+
   gst_object_unref (qtmux);
-  return TRUE;
+  ret = TRUE;
+  goto end;
 
   /* ERRORS */
 refuse_caps:
@@ -1611,7 +1566,7 @@
     GST_WARNING_OBJECT (qtmux, "pad %s refused caps %" GST_PTR_FORMAT,
         GST_PAD_NAME (pad), caps);
     gst_object_unref (qtmux);
-    return FALSE;
+    goto end;
   }
 refuse_renegotiation:
   {
@@ -1619,8 +1574,11 @@
         "pad %s refused renegotiation to %" GST_PTR_FORMAT " from %"
         GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, GST_PAD_CAPS (pad));
     gst_object_unref (qtmux);
-    return FALSE;
+    goto end;
   }
+ end:
+  g_free(entry.codec_data);
+  return ret;
 }
 
 static gboolean
@@ -1633,12 +1591,10 @@
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_TAG:{
       GstTagList *list;
-      GstTagSetter *setter = GST_TAG_SETTER (qtmux);
-      const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
 
       GST_DEBUG_OBJECT (qtmux, "received tag event");
       gst_event_parse_tag (event, &list);
-      gst_tag_setter_merge_tags (setter, list, mode);
+	  gst_qt_mux_add_metadata_tags (qtmux, list);
       break;
     }
     default:
@@ -1670,23 +1626,56 @@
   GstQTPad *collect_pad;
   GstPad *newpad;
   gboolean audio;
+  guint trak_id = 0;
+  gint pad_num = -1;
 
-  GST_DEBUG_OBJECT (qtmux, "Requested pad: %s", GST_STR_NULL (name));
-
+  GST_INFO_OBJECT (qtmux, "Requested pad: %s", GST_STR_NULL (name));
+#if 0
   if (qtmux->state != GST_QT_MUX_STATE_NONE) {
     GST_WARNING_OBJECT (qtmux, "Not providing request pad after stream start.");
     return NULL;
   }
-
+#endif
   if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
     audio = TRUE;
+	if(name)
+		sscanf(name, "audio_%d", &pad_num);
   } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
     audio = FALSE;
+	if(name)
+		sscanf(name, "video_%d", &pad_num);
   } else {
     GST_WARNING_OBJECT (qtmux, "This is not our template!");
     return NULL;
   }
 
+  /* Assign atom context trak id */
+  if(pad_num > -1 && pad_num < MAX_TRAK) {
+	  /* Check if we've used this pad num before in this session..
+	   * If so, we should use the trak id we used previously
+	   */
+	  if(audio)
+		  trak_id = qtmux->audio_trak_ids[pad_num];
+	  else
+		  trak_id = qtmux->video_trak_ids[pad_num];
+  }
+
+  /* Havn't seen this pad num.. assign new id */
+  if(trak_id < 1) {
+	  trak_id = atom_ctx_track_add(qtmux->context);
+	  /* Track pad_num/trak_id */
+	  if(pad_num > -1 && pad_num < MAX_TRAK) {
+		  if(audio)
+			  qtmux->audio_trak_ids[pad_num] = trak_id;
+		  else
+			  qtmux->video_trak_ids[pad_num] = trak_id;
+	  }
+	  GST_INFO_OBJECT (qtmux, "Assigning Trak ID: %u (new trak id)", trak_id);
+  }
+  else {
+	  GST_INFO_OBJECT (qtmux, "Assigning Trak ID: %u (previously used)", trak_id);
+  }
+
   /* add pad to collections */
   newpad = gst_pad_new_from_template (templ, name);
   collect_pad = (GstQTPad *)
@@ -1694,8 +1683,7 @@
       (GstCollectDataDestroyNotify) (gst_qt_mux_pad_reset));
   /* set up pad */
   gst_qt_mux_pad_reset (collect_pad);
-  collect_pad->trak = atom_trak_new (qtmux->context);
-  atom_moov_add_trak (qtmux->moov, collect_pad->trak);
+  collect_pad->trak_id = trak_id;
 
   /* set up pad functions */
   if (audio)
@@ -1727,9 +1715,6 @@
 
   GST_OBJECT_LOCK (qtmux);
   switch (prop_id) {
-    case PROP_LARGE_FILE:
-      g_value_set_boolean (value, qtmux->large_file);
-      break;
     case PROP_MOVIE_TIMESCALE:
       g_value_set_uint (value, qtmux->timescale);
       break;
@@ -1737,11 +1722,21 @@
       g_value_set_boolean (value, qtmux->guess_pts);
       break;
     case PROP_FAST_START:
-      g_value_set_boolean (value, qtmux->fast_start);
+      //g_value_set_boolean (value, qtmux->fast_start);
       break;
     case PROP_FAST_START_TEMP_FILE:
-      g_value_set_string (value, qtmux->fast_start_file_path);
+      //g_value_set_string (value, qtmux->fast_start_file_path);
       break;
+    case PROP_MOOV_TEMP_FILE:
+      g_value_set_string (value, qtmux->moov_file_path);
+      break;
+    case PROP_MUX_BY_TIMESTAMP:
+      g_value_set_boolean (value, qtmux->mux_by_timestamp);
+      break;
+    case PROP_MOOV_TEMP_FILE_KEEP:
+      g_value_set_boolean (value, qtmux->moov_file_keep);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1750,21 +1745,6 @@
 }
 
 static void
-gst_qt_mux_generate_fast_start_file_path (GstQTMux * qtmux)
-{
-  gchar *tmp;
-
-  if (qtmux->fast_start_file_path) {
-    g_free (qtmux->fast_start_file_path);
-    qtmux->fast_start_file_path = NULL;
-  }
-
-  tmp = g_strdup_printf ("%s%d", "qtmux", g_random_int ());
-  qtmux->fast_start_file_path = g_build_filename (g_get_tmp_dir (), tmp, NULL);
-  g_free (tmp);
-}
-
-static void
 gst_qt_mux_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec)
 {
@@ -1772,28 +1752,32 @@
 
   GST_OBJECT_LOCK (qtmux);
   switch (prop_id) {
-    case PROP_LARGE_FILE:
-      qtmux->large_file = g_value_get_boolean (value);
-      break;
     case PROP_MOVIE_TIMESCALE:
       qtmux->timescale = g_value_get_uint (value);
+	  atom_ctx_timescale_set(qtmux->context, qtmux->timescale);
       break;
     case PROP_DO_CTTS:
       qtmux->guess_pts = g_value_get_boolean (value);
       break;
     case PROP_FAST_START:
-      qtmux->fast_start = g_value_get_boolean (value);
+      //qtmux->fast_start = g_value_get_boolean (value);
       break;
     case PROP_FAST_START_TEMP_FILE:
-      if (qtmux->fast_start_file_path) {
-        g_free (qtmux->fast_start_file_path);
+      break;
+    case PROP_MOOV_TEMP_FILE:
+      if (qtmux->moov_file_path) {
+        g_free (qtmux->moov_file_path);
       }
-      qtmux->fast_start_file_path = g_value_dup_string (value);
-      /* NULL means to generate a random one */
-      if (!qtmux->fast_start_file_path) {
-        gst_qt_mux_generate_fast_start_file_path (qtmux);
-      }
+      qtmux->moov_file_path = g_value_dup_string (value);
+	  atom_ctx_filename_set(qtmux->context, qtmux->moov_file_path);
       break;
+    case PROP_MUX_BY_TIMESTAMP:
+      qtmux->mux_by_timestamp = g_value_get_boolean (value);
+      break;
+    case PROP_MOOV_TEMP_FILE_KEEP:
+      qtmux->moov_file_keep = g_value_get_boolean (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1812,6 +1796,7 @@
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       gst_collect_pads_start (qtmux->collect);
+	  atom_ctx_start(qtmux->context);
       qtmux->state = GST_QT_MUX_STATE_STARTED;
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
@@ -1829,7 +1814,7 @@
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      gst_qt_mux_reset (qtmux, TRUE);
+      gst_qt_mux_reset (qtmux);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       break;
@@ -1855,9 +1840,6 @@
     0,
     (GInstanceInitFunc) gst_qt_mux_init,
   };
-  static const GInterfaceInfo tag_setter_info = {
-    NULL, NULL, NULL
-  };
   GType type;
   GstQTMuxFormat format;
   GstQTMuxClassParams *params;
@@ -1884,7 +1866,6 @@
     type = g_type_register_static (GST_TYPE_ELEMENT, prop->type_name, &typeinfo,
         0);
     g_type_set_qdata (type, GST_QT_MUX_PARAMS_QDATA, (gpointer) params);
-    g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
 
     if (!gst_element_register (plugin, prop->name, GST_RANK_PRIMARY, type))
       return FALSE;
@@ -1901,6 +1882,7 @@
 gst_qt_mux_plugin_init (GstPlugin * plugin)
 {
   GST_DEBUG_CATEGORY_INIT (gst_qt_mux_debug, "qtmux", 0, "QT Muxer");
+  GST_DEBUG_CATEGORY_INIT (gst_qtmux_atom_ctx_debug, "qtatom", 0, "QT Muxer - atom context");
 
   return gst_qt_mux_register (plugin);
 }
Index: gst/qtmux/ftypcc.h
===================================================================
--- gst/qtmux/ftypcc.h	(revision 90)
+++ gst/qtmux/ftypcc.h	(working copy)
@@ -53,6 +53,9 @@
 #define FOURCC_mp41     GST_MAKE_FOURCC('m','p','4','1')
 #define FOURCC_mp42     GST_MAKE_FOURCC('m','p','4','2')
 #define FOURCC_mjp2     GST_MAKE_FOURCC('m','j','p','2')
+#define FOURCC_3gp4     GST_MAKE_FOURCC('3','g','p','4')
+#define FOURCC_3gp6     GST_MAKE_FOURCC('3','g','p','6')
+#define FOURCC_3gg6     GST_MAKE_FOURCC('3','g','g','6')
 #define FOURCC_3gg7     GST_MAKE_FOURCC('3','g','g','7')
 #define FOURCC_avc1     GST_MAKE_FOURCC('a','v','c','1')
 #define FOURCC_qt__     GST_MAKE_FOURCC('q','t',' ',' ')
Index: gst/Makefile.in
===================================================================
--- gst/Makefile.in	(revision 90)
+++ gst/Makefile.in	(working copy)
@@ -150,6 +150,7 @@
 EXEEXT = @EXEEXT@
 EXIF_CFLAGS = @EXIF_CFLAGS@
 EXIF_LIBS = @EXIF_LIBS@
+EXPAT_LIBS = @EXPAT_LIBS@
 F77 = @F77@
 FAAC_LIBS = @FAAC_LIBS@
 FAAD_IS_NEAAC = @FAAD_IS_NEAAC@
@@ -219,6 +220,7 @@
 HAVE_GSM = @HAVE_GSM@
 HAVE_JP2K = @HAVE_JP2K@
 HAVE_NAS = @HAVE_NAS@
+HAVE_QTMUX = @HAVE_QTMUX@
 HAVE_X = @HAVE_X@
 HAVE_X11 = @HAVE_X11@
 HAVE_X264 = @HAVE_X264@
@@ -425,7 +427,9 @@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = $(GST_PLUGINS_SELECTED)
+@USE_QTMUX_FALSE@QTMUX_DIR = 
+@USE_QTMUX_TRUE@QTMUX_DIR = qtmux
+SUBDIRS = $(GST_PLUGINS_SELECTED) $(QTMUX_DIR)
 DIST_SUBDIRS = $(GST_PLUGINS_ALL)
 all: all-recursive
 
Index: gst/Makefile.am
===================================================================
--- gst/Makefile.am	(revision 90)
+++ gst/Makefile.am	(working copy)
@@ -1,2 +1,8 @@
-SUBDIRS = $(GST_PLUGINS_SELECTED)
+if USE_QTMUX
+QTMUX_DIR=qtmux
+else
+QTMUX_DIR=
+endif
+
+SUBDIRS = $(GST_PLUGINS_SELECTED) $(QTMUX_DIR)
 DIST_SUBDIRS = $(GST_PLUGINS_ALL)
Index: configure
===================================================================
--- configure	(revision 90)
+++ configure	(working copy)
@@ -853,6 +853,10 @@
 USE_TIMIDITY_TRUE
 TIMIDITY_LIBS
 TIMIDITY_CFLAGS
+USE_QTMUX_FALSE
+USE_QTMUX_TRUE
+EXPAT_LIBS
+HAVE_QTMUX
 USE_OFA_FALSE
 USE_OFA_TRUE
 OFA_LIBS
@@ -1055,8 +1059,6 @@
 USE_PLUGIN_REAL_TRUE
 USE_PLUGIN_RAWPARSE_FALSE
 USE_PLUGIN_RAWPARSE_TRUE
-USE_PLUGIN_QTMUX_FALSE
-USE_PLUGIN_QTMUX_TRUE
 USE_PLUGIN_PCAPPARSE_FALSE
 USE_PLUGIN_PCAPPARSE_TRUE
 USE_PLUGIN_NUVDEMUX_FALSE
@@ -1439,7 +1441,6 @@
 enable_nsf
 enable_nuvdemux
 enable_pcapparse
-enable_qtmux
 enable_rawparse
 enable_real
 enable_rtpmanager
@@ -1497,6 +1498,7 @@
 with_x
 enable_neon
 enable_ofa
+enable_qtmux
 enable_timidity
 enable_wildmidi
 enable_sdl
@@ -2294,7 +2296,6 @@
   --disable-nsf           disable dependency-less nsf plugin
   --disable-nuvdemux      disable dependency-less nuvdemux plugin
   --disable-pcapparse     disable dependency-less pcapparse plugin
-  --disable-qtmux         disable dependency-less qtmux plugin
   --disable-rawparse      disable dependency-less rawparse plugin
   --disable-real          disable dependency-less real plugin
   --disable-rtpmanager    disable dependency-less rtpmanager plugin
@@ -2348,6 +2349,7 @@
   --disable-nas                disable nas plug-in: nassink
   --disable-neon               disable neon http client plugins: neonhttpsrc
   --disable-ofa                disable ofa plugins: ofa
+  --disable-qtmux              disable qtmux plug-in: qtmux
   --disable-timidity           disable timidity midi soft synth plugin: timidity
   --disable-wildmidi           disable wildmidi midi soft synth plugin: wildmidi
   --disable-sdl                disable SDL plug-in: sdlvideosink sdlaudiosink
@@ -5657,13 +5659,13 @@
 else
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:5660: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:5662: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:5663: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:5665: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:5666: output\"" >&5)
+  (eval echo "\"\$as_me:5668: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -6866,7 +6868,7 @@
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6869 "configure"' > conftest.$ac_ext
+  echo '#line 6871 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -8721,11 +8723,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8724: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8726: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8728: \$? = $ac_status" >&5
+   echo "$as_me:8730: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -9060,11 +9062,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9063: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9065: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9067: \$? = $ac_status" >&5
+   echo "$as_me:9069: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -9165,11 +9167,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9168: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9170: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9172: \$? = $ac_status" >&5
+   echo "$as_me:9174: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -9220,11 +9222,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9223: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9225: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9227: \$? = $ac_status" >&5
+   echo "$as_me:9229: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -12033,7 +12035,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12036 "configure"
+#line 12038 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12129,7 +12131,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12132 "configure"
+#line 12134 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -20243,11 +20245,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20246: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20248: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:20250: \$? = $ac_status" >&5
+   echo "$as_me:20252: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -20342,11 +20344,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20345: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20347: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:20349: \$? = $ac_status" >&5
+   echo "$as_me:20351: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -20394,11 +20396,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20397: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20399: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:20401: \$? = $ac_status" >&5
+   echo "$as_me:20403: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -30713,48 +30715,6 @@
 
 
 
-  GST_PLUGINS_ALL="$GST_PLUGINS_ALL qtmux"
-
-
-
-  # Check whether --enable-qtmux was given.
-if test "${enable_qtmux+set}" = set; then
-  enableval=$enable_qtmux;
-      case "${enableval}" in
-        yes) gst_use_qtmux=yes ;;
-        no) gst_use_qtmux=no ;;
-        *) { { $as_echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-qtmux" >&5
-$as_echo "$as_me: error: bad value ${enableval} for --enable-qtmux" >&2;}
-   { (exit 1); exit 1; }; } ;;
-       esac
-
-else
-  gst_use_qtmux=yes
-fi
-
-  if test x$gst_use_qtmux = xno; then
-    { $as_echo "$as_me:$LINENO: disabling dependency-less plugin qtmux" >&5
-$as_echo "$as_me: disabling dependency-less plugin qtmux" >&6;}
-    WITHOUT_PLUGINS="$WITHOUT_PLUGINS qtmux"
-  fi
-
-
-  if [ -z "$WITH_PLUGINS" ] || echo " $WITH_PLUGINS " | tr , ' ' | grep -i " qtmux " > /dev/null; then
-    GST_PLUGINS_SELECTED="$GST_PLUGINS_SELECTED qtmux"
-  fi
-  if echo " $WITHOUT_PLUGINS " | tr , ' ' | grep -i " qtmux " > /dev/null; then
-    GST_PLUGINS_SELECTED=`echo " $GST_PLUGINS_SELECTED " | $SED -e 's/ qtmux / /'`
-  fi
-   if echo " $GST_PLUGINS_SELECTED " | grep -i " qtmux " > /dev/null; then
-  USE_PLUGIN_QTMUX_TRUE=
-  USE_PLUGIN_QTMUX_FALSE='#'
-else
-  USE_PLUGIN_QTMUX_TRUE='#'
-  USE_PLUGIN_QTMUX_FALSE=
-fi
-
-
-
   GST_PLUGINS_ALL="$GST_PLUGINS_ALL rawparse"
 
 
@@ -44666,6 +44626,326 @@
 
 
 echo
+{ $as_echo "$as_me:$LINENO: *** checking feature: qtmux plug-in ***" >&5
+$as_echo "$as_me: *** checking feature: qtmux plug-in ***" >&6;}
+if test "xqtmux" != "x"
+then
+  { $as_echo "$as_me:$LINENO: *** for plug-ins: qtmux ***" >&5
+$as_echo "$as_me: *** for plug-ins: qtmux ***" >&6;}
+fi
+NOUSE=
+if test "x$USE_QTMUX" = "xno"; then
+  NOUSE="yes"
+fi
+# Check whether --enable-qtmux was given.
+if test "${enable_qtmux+set}" = set; then
+  enableval=$enable_qtmux;  case "${enableval}" in
+      yes) USE_QTMUX=yes;;
+      no) USE_QTMUX=no;;
+      *) { { $as_echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-qtmux" >&5
+$as_echo "$as_me: error: bad value ${enableval} for --enable-qtmux" >&2;}
+   { (exit 1); exit 1; }; } ;;
+    esac
+else
+   USE_QTMUX=yes
+fi
+
+if test "x$NOUSE" = "xyes"; then
+  USE_QTMUX="no"
+  { $as_echo "$as_me:$LINENO: WARNING: *** qtmux pre-configured not to be built" >&5
+$as_echo "$as_me: WARNING: *** qtmux pre-configured not to be built" >&2;}
+fi
+NOUSE=
+
+
+if test x$USE_QTMUX = xyes; then
+
+  gst_check_save_LIBS=$LIBS
+  gst_check_save_LDFLAGS=$LDFLAGS
+  gst_check_save_CFLAGS=$CFLAGS
+  gst_check_save_CPPFLAGS=$CPPFLAGS
+  gst_check_save_CXXFLAGS=$CXXFLAGS
+
+  HAVE_QTMUX=no
+
+
+  { $as_echo "$as_me:$LINENO: checking for XML_ParserCreate in -lexpat" >&5
+$as_echo_n "checking for XML_ParserCreate in -lexpat... " >&6; }
+if test "${ac_cv_lib_expat_XML_ParserCreate+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lexpat  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XML_ParserCreate ();
+int
+main ()
+{
+return XML_ParserCreate ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_expat_XML_ParserCreate=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_expat_XML_ParserCreate=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_expat_XML_ParserCreate" >&5
+$as_echo "$ac_cv_lib_expat_XML_ParserCreate" >&6; }
+if test "x$ac_cv_lib_expat_XML_ParserCreate" = x""yes; then
+  HAVE_QTMUX=yes
+else
+  HAVE_QTMUX=no
+fi
+
+  if test "x$HAVE_QTMUX" = "xyes"; then
+    if test "${ac_cv_header_expat_h+set}" = set; then
+  { $as_echo "$as_me:$LINENO: checking for expat.h" >&5
+$as_echo_n "checking for expat.h... " >&6; }
+if test "${ac_cv_header_expat_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_expat_h" >&5
+$as_echo "$ac_cv_header_expat_h" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking expat.h usability" >&5
+$as_echo_n "checking expat.h usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <expat.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking expat.h presence" >&5
+$as_echo_n "checking expat.h presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <expat.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: expat.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: expat.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: expat.h: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: expat.h:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: expat.h: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: expat.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: expat.h: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: expat.h: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: expat.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------------------------------------ ##
+## Report this to http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer ##
+## ------------------------------------------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for expat.h" >&5
+$as_echo_n "checking for expat.h... " >&6; }
+if test "${ac_cv_header_expat_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_header_expat_h=$ac_header_preproc
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_expat_h" >&5
+$as_echo "$ac_cv_header_expat_h" >&6; }
+
+fi
+if test "x$ac_cv_header_expat_h" = x""yes; then
+  :
+else
+  HAVE_QTMUX=no
+fi
+
+
+    if test "x$HAVE_QTMUX" = "xyes"; then
+            EXPAT_LIBS="-lexpat"
+    else
+      :
+    fi
+  else
+    :
+  fi
+
+
+
+
+  GIVEN_CFLAGS=$EXPAT_CFLAGS
+  INCLUDE_DIRS=`echo | cpp -v 2>&1`
+
+      INCLUDE_DIRS=`echo $INCLUDE_DIRS | sed -e 's/.*<...> search starts here://' | sed -e 's/End of search list.*//'`
+  for dir in $INCLUDE_DIRS; do
+        GIVEN_CFLAGS=`echo $GIVEN_CFLAGS | sed -e "s#-I$dir ##"`
+  done
+  EXPAT_CFLAGS=$GIVEN_CFLAGS
+
+
+
+
+  LIBS=$gst_check_save_LIBS
+  LDFLAGS=$gst_check_save_LDFLAGS
+  CFLAGS=$gst_check_save_CFLAGS
+  CPPFLAGS=$gst_check_save_CPPFLAGS
+  CXXFLAGS=$gst_check_save_CXXFLAGS
+
+    if test x$HAVE_QTMUX = xno; then
+    USE_QTMUX=no
+  else
+    { $as_echo "$as_me:$LINENO: *** These plugins will be built: qtmux" >&5
+$as_echo "$as_me: *** These plugins will be built: qtmux" >&6;}
+  fi
+fi
+if test x$USE_QTMUX = xyes; then
+  :
+  if test "xqtmux" != "x"; then
+    GST_PLUGINS_YES="\tqtmux\n$GST_PLUGINS_YES"
+  fi
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_QTMUX /**/
+_ACEOF
+
+else
+  { $as_echo "$as_me:$LINENO: *** These plugins will not be built: qtmux" >&5
+$as_echo "$as_me: *** These plugins will not be built: qtmux" >&6;}
+  if test "xqtmux" != "x"; then
+    GST_PLUGINS_NO="\tqtmux\n$GST_PLUGINS_NO"
+  fi
+  :
+fi
+ if test x$USE_QTMUX = xyes; then
+  USE_QTMUX_TRUE=
+  USE_QTMUX_FALSE='#'
+else
+  USE_QTMUX_TRUE='#'
+  USE_QTMUX_FALSE=
+fi
+
+
+
+echo
 { $as_echo "$as_me:$LINENO: *** checking feature: timidity midi soft synth plugin ***" >&5
 $as_echo "$as_me: *** checking feature: timidity midi soft synth plugin ***" >&6;}
 if test "xtimidity" != "x"
@@ -49007,6 +49287,14 @@
 fi
 
  if false; then
+  USE_QTMUX_TRUE=
+  USE_QTMUX_FALSE='#'
+else
+  USE_QTMUX_TRUE='#'
+  USE_QTMUX_FALSE=
+fi
+
+ if false; then
   USE_SDL_TRUE=
   USE_SDL_FALSE='#'
 else
@@ -49226,7 +49514,7 @@
 
 
 
-ac_config_files="$ac_config_files Makefile common/shave common/shave-libtool gst-plugins-bad.spec gst/Makefile gst/aacparse/Makefile gst/aiffparse/Makefile gst/amrparse/Makefile gst/autoconvert/Makefile gst/legacyresample/Makefile gst/liveadder/Makefile gst/bayer/Makefile gst/camerabin/Makefile gst/cdxaparse/Makefile gst/dccp/Makefile gst/debugutils/Makefile gst/dtmf/Makefile gst/dvdspu/Makefile gst/festival/Makefile gst/freeze/Makefile gst/h264parse/Makefile gst/librfb/Makefile gst/mpegdemux/Makefile gst/mpegtsmux/Makefile gst/mpegtsmux/tsmux/Makefile gst/mpeg4videoparse/Makefile gst/mpegvideoparse/Makefile gst/mve/Makefile gst/mxf/Makefile gst/nsf/Makefile gst/nuvdemux/Makefile gst/pcapparse/Makefile gst/qtmux/Makefile gst/rawparse/Makefile gst/rtpmanager/Makefile gst/rtpmux/Makefile gst/scaletempo/Makefile gst/sdp/Makefile gst/selector/Makefile gst/siren/Makefile gst/speed/Makefile gst/subenc/Makefile gst/stereo/Makefile gst/tta/Makefile gst/valve/Makefile gst/videosignal/Makefile gst/vmnc/Makefile gst/real/Makefile gst/xdgmime/Makefile gst-libs/Makefile gst-libs/gst/Makefile gst-libs/gst/dshow/Makefile gst-libs/gst/interfaces/Makefile sys/Makefile sys/dshowdecwrapper/Makefile sys/acmenc/Makefile sys/acmmp3dec/Makefile sys/directdraw/Makefile sys/dshowsrcwrapper/Makefile sys/dshowvideosink/Makefile sys/dvb/Makefile sys/fbdev/Makefile sys/oss4/Makefile sys/osxvideo/Makefile sys/qtwrapper/Makefile sys/vcd/Makefile sys/wasapi/Makefile sys/wininet/Makefile sys/winks/Makefile sys/winscreencap/Makefile tests/examples/Makefile tests/examples/directfb/Makefile tests/examples/mxf/Makefile tests/examples/scaletempo/Makefile tests/examples/switch/Makefile ext/amrwb/Makefile ext/alsaspdif/Makefile ext/assrender/Makefile ext/apexsink/Makefile ext/bz2/Makefile ext/cdaudio/Makefile ext/celt/Makefile ext/dc1394/Makefile ext/dirac/Makefile ext/directfb/Makefile ext/divx/Makefile ext/dts/Makefile ext/metadata/Makefile ext/faac/Makefile ext/faad/Makefile ext/gsm/Makefile ext/ivorbis/Makefile ext/jack/Makefile ext/jp2k/Makefile ext/ladspa/Makefile ext/libmms/Makefile ext/Makefile ext/nas/Makefile ext/modplug/Makefile ext/mpeg2enc/Makefile ext/mimic/Makefile ext/mplex/Makefile ext/musepack/Makefile ext/musicbrainz/Makefile ext/mythtv/Makefile ext/neon/Makefile ext/ofa/Makefile ext/resindvd/Makefile ext/sdl/Makefile ext/sndfile/Makefile ext/soundtouch/Makefile ext/spc/Makefile ext/swfdec/Makefile ext/theora/Makefile ext/timidity/Makefile ext/x264/Makefile ext/xvid/Makefile po/Makefile.in docs/Makefile docs/plugins/Makefile docs/plugins/figures/Makefile docs/version.entities common/Makefile common/m4/Makefile m4/Makefile tests/Makefile tests/check/Makefile tests/icles/Makefile win32/common/config.h"
+ac_config_files="$ac_config_files Makefile common/shave common/shave-libtool gst-plugins-bad.spec gst/Makefile gst/aacparse/Makefile gst/aiffparse/Makefile gst/amrparse/Makefile gst/autoconvert/Makefile gst/legacyresample/Makefile gst/liveadder/Makefile gst/bayer/Makefile gst/camerabin/Makefile gst/cdxaparse/Makefile gst/dccp/Makefile gst/debugutils/Makefile gst/dtmf/Makefile gst/dvdspu/Makefile gst/festival/Makefile gst/freeze/Makefile gst/h264parse/Makefile gst/librfb/Makefile gst/mpegdemux/Makefile gst/mpegtsmux/Makefile gst/mpegtsmux/tsmux/Makefile gst/mpeg4videoparse/Makefile gst/mpegvideoparse/Makefile gst/mve/Makefile gst/mxf/Makefile gst/nsf/Makefile gst/nuvdemux/Makefile gst/pcapparse/Makefile gst/qtmux/Makefile gst/rawparse/Makefile gst/rtpmanager/Makefile gst/rtpmux/Makefile gst/scaletempo/Makefile gst/sdp/Makefile gst/selector/Makefile gst/siren/Makefile gst/speed/Makefile gst/subenc/Makefile gst/stereo/Makefile gst/tta/Makefile gst/valve/Makefile gst/videosignal/Makefile gst/vmnc/Makefile gst/real/Makefile gst/xdgmime/Makefile gst-libs/Makefile gst-libs/gst/Makefile gst-libs/gst/dshow/Makefile gst-libs/gst/interfaces/Makefile sys/Makefile sys/dshowdecwrapper/Makefile sys/acmenc/Makefile sys/acmmp3dec/Makefile sys/directdraw/Makefile sys/dshowsrcwrapper/Makefile sys/dshowvideosink/Makefile sys/dvb/Makefile sys/fbdev/Makefile sys/oss4/Makefile sys/osxvideo/Makefile sys/qtwrapper/Makefile sys/vcd/Makefile sys/wasapi/Makefile sys/wininet/Makefile sys/winks/Makefile sys/winscreencap/Makefile tests/examples/Makefile tests/examples/directfb/Makefile tests/examples/mxf/Makefile tests/examples/scaletempo/Makefile tests/examples/switch/Makefile tests/examples/qtmux/Makefile ext/amrwb/Makefile ext/alsaspdif/Makefile ext/assrender/Makefile ext/apexsink/Makefile ext/bz2/Makefile ext/cdaudio/Makefile ext/celt/Makefile ext/dc1394/Makefile ext/dirac/Makefile ext/directfb/Makefile ext/divx/Makefile ext/dts/Makefile ext/metadata/Makefile ext/faac/Makefile ext/faad/Makefile ext/gsm/Makefile ext/ivorbis/Makefile ext/jack/Makefile ext/jp2k/Makefile ext/ladspa/Makefile ext/libmms/Makefile ext/Makefile ext/nas/Makefile ext/modplug/Makefile ext/mpeg2enc/Makefile ext/mimic/Makefile ext/mplex/Makefile ext/musepack/Makefile ext/musicbrainz/Makefile ext/mythtv/Makefile ext/neon/Makefile ext/ofa/Makefile ext/resindvd/Makefile ext/sdl/Makefile ext/sndfile/Makefile ext/soundtouch/Makefile ext/spc/Makefile ext/swfdec/Makefile ext/theora/Makefile ext/timidity/Makefile ext/x264/Makefile ext/xvid/Makefile po/Makefile.in docs/Makefile docs/plugins/Makefile docs/plugins/figures/Makefile docs/version.entities common/Makefile common/m4/Makefile m4/Makefile tests/Makefile tests/check/Makefile tests/icles/Makefile win32/common/config.h"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -49775,13 +50063,6 @@
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
-if test -z "${USE_PLUGIN_QTMUX_TRUE}" && test -z "${USE_PLUGIN_QTMUX_FALSE}"; then
-  { { $as_echo "$as_me:$LINENO: error: conditional \"USE_PLUGIN_QTMUX\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-$as_echo "$as_me: error: conditional \"USE_PLUGIN_QTMUX\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
-fi
 if test -z "${USE_PLUGIN_RAWPARSE_TRUE}" && test -z "${USE_PLUGIN_RAWPARSE_FALSE}"; then
   { { $as_echo "$as_me:$LINENO: error: conditional \"USE_PLUGIN_RAWPARSE\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -50188,6 +50469,13 @@
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${USE_QTMUX_TRUE}" && test -z "${USE_QTMUX_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"USE_QTMUX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"USE_QTMUX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${USE_TIMIDITY_TRUE}" && test -z "${USE_TIMIDITY_FALSE}"; then
   { { $as_echo "$as_me:$LINENO: error: conditional \"USE_TIMIDITY\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -50552,6 +50840,13 @@
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${USE_QTMUX_TRUE}" && test -z "${USE_QTMUX_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"USE_QTMUX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"USE_QTMUX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${USE_SDL_TRUE}" && test -z "${USE_SDL_FALSE}"; then
   { { $as_echo "$as_me:$LINENO: error: conditional \"USE_SDL\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -51601,6 +51896,7 @@
     "tests/examples/mxf/Makefile") CONFIG_FILES="$CONFIG_FILES tests/examples/mxf/Makefile" ;;
     "tests/examples/scaletempo/Makefile") CONFIG_FILES="$CONFIG_FILES tests/examples/scaletempo/Makefile" ;;
     "tests/examples/switch/Makefile") CONFIG_FILES="$CONFIG_FILES tests/examples/switch/Makefile" ;;
+    "tests/examples/qtmux/Makefile") CONFIG_FILES="$CONFIG_FILES tests/examples/qtmux/Makefile" ;;
     "ext/amrwb/Makefile") CONFIG_FILES="$CONFIG_FILES ext/amrwb/Makefile" ;;
     "ext/alsaspdif/Makefile") CONFIG_FILES="$CONFIG_FILES ext/alsaspdif/Makefile" ;;
     "ext/assrender/Makefile") CONFIG_FILES="$CONFIG_FILES ext/assrender/Makefile" ;;
Index: ext/faac/Makefile.in
===================================================================
--- ext/faac/Makefile.in	(revision 90)
+++ ext/faac/Makefile.in	(working copy)
@@ -174,6 +174,7 @@
 EXEEXT = @EXEEXT@
 EXIF_CFLAGS = @EXIF_CFLAGS@
 EXIF_LIBS = @EXIF_LIBS@
+EXPAT_LIBS = @EXPAT_LIBS@
 F77 = @F77@
 FAAC_LIBS = @FAAC_LIBS@
 FAAD_IS_NEAAC = @FAAD_IS_NEAAC@
@@ -243,6 +244,7 @@
 HAVE_GSM = @HAVE_GSM@
 HAVE_JP2K = @HAVE_JP2K@
 HAVE_NAS = @HAVE_NAS@
+HAVE_QTMUX = @HAVE_QTMUX@
 HAVE_X = @HAVE_X@
 HAVE_X11 = @HAVE_X11@
 HAVE_X264 = @HAVE_X264@
Index: ext/faac/gstfaac.c
===================================================================
--- ext/faac/gstfaac.c	(revision 90)
+++ ext/faac/gstfaac.c	(working copy)
@@ -256,9 +256,8 @@
   faac->samplerate = -1;
   faac->channels = -1;
   faac->cache = NULL;
-  faac->cache_time = GST_CLOCK_TIME_NONE;
-  faac->cache_duration = 0;
   faac->next_ts = GST_CLOCK_TIME_NONE;
+  faac->stream_start_ts = GST_CLOCK_TIME_NONE;
 
   faac->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
   gst_pad_set_chain_function (faac->sinkpad,
@@ -291,6 +290,7 @@
   gint channels, samplerate, width;
   gulong samples, bytes, fmt = 0, bps = 0;
   gboolean result = FALSE;
+  guint enc_channel_samples, enc_channel_framesize;
 
   if (!gst_caps_is_fixed (caps))
     goto done;
@@ -314,6 +314,9 @@
   if (!(handle = faacEncOpen (samplerate, channels, &samples, &bytes)))
     goto done;
 
+  GST_DEBUG("faacEncOpen - samplerate:%d channels:%d samples:%lu, maxoutput:%lu",
+			samplerate, channels, samples, bytes);
+
   if (gst_structure_has_name (structure, "audio/x-raw-int")) {
     gst_structure_get_int (structure, "width", &width);
     switch (width) {
@@ -344,9 +347,13 @@
   faac->bps = bps;
   faac->handle = handle;
   faac->bytes = bytes;
-  faac->samples = samples;
   faac->channels = channels;
   faac->samplerate = samplerate;
+  enc_channel_samples = samples / channels;
+  enc_channel_framesize = enc_channel_samples * bps;
+  faac->enc_total_samples = samples;
+  faac->enc_input_size = enc_channel_framesize * channels;
+  faac->enc_input_duration = enc_channel_samples * (GST_SECOND / samplerate);
   GST_OBJECT_UNLOCK (faac);
 
   result = TRUE;
@@ -467,228 +474,240 @@
 static gboolean
 gst_faac_sink_event (GstPad * pad, GstEvent * event)
 {
-  GstFaac *faac;
-  gboolean ret;
+	GstFaac * faac;
+	gboolean ret;
 
-  faac = GST_FAAC (gst_pad_get_parent (pad));
+	faac = GST_FAAC(gst_pad_get_parent(pad));
 
-  switch (GST_EVENT_TYPE (event)) {
+	switch(GST_EVENT_TYPE(event)) {
     case GST_EVENT_EOS:
-    {
-      GstBuffer *outbuf;
+	{
+		GstBuffer * outbuf;
 
-      if (!faac->handle)
-        ret = FALSE;
-      else
-        ret = TRUE;
+		ret = (faac->handle != NULL);
 
-      /* flush first */
-      GST_DEBUG ("Pushing out remaining buffers because of EOS");
-      while (ret) {
-        if (gst_pad_alloc_buffer_and_set_caps (faac->srcpad,
-                GST_BUFFER_OFFSET_NONE, faac->bytes,
-                GST_PAD_CAPS (faac->srcpad), &outbuf) == GST_FLOW_OK) {
-          gint ret_size;
+		/*
+		 * Flush remaining buffers from the encoder
+		 */
+		GST_DEBUG ("Pushing out remaining buffers because of EOS");
 
-          GST_DEBUG ("next_ts %" GST_TIME_FORMAT,
-              GST_TIME_ARGS (faac->next_ts));
+		while(ret) {
+			GstFlowReturn result;
 
-          if ((ret_size = faacEncEncode (faac->handle, NULL, 0,
-                      GST_BUFFER_DATA (outbuf), faac->bytes)) > 0) {
-            GST_BUFFER_SIZE (outbuf) = ret_size;
-            GST_BUFFER_TIMESTAMP (outbuf) = faac->next_ts;
-            /* faac seems to always consume a fixed number of input samples,
-             * therefore extrapolate the duration from that value and the incoming
-             * bitrate */
-            GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (faac->samples,
-                GST_SECOND, faac->channels * faac->samplerate);
-            if (GST_CLOCK_TIME_IS_VALID (faac->next_ts))
-              faac->next_ts += GST_BUFFER_DURATION (outbuf);
-            gst_pad_push (faac->srcpad, outbuf);
-          } else {
-            gst_buffer_unref (outbuf);
-            ret = FALSE;
-          }
-        } else
-          ret = FALSE;
-      }
-      ret = gst_pad_event_default (pad, event);
-      break;
+			result = gst_pad_alloc_buffer_and_set_caps(faac->srcpad,
+													   GST_BUFFER_OFFSET_NONE,
+													   faac->bytes,
+													   GST_PAD_CAPS(faac->srcpad),
+													   &outbuf);
+			if(result == GST_FLOW_OK) {
+				gint ret_size;
+
+				ret_size = faacEncEncode(faac->handle,
+										 NULL,
+										 0,
+										 GST_BUFFER_DATA(outbuf),
+										 faac->bytes);
+
+				if(ret_size > 0) {
+					GST_BUFFER_SIZE(outbuf) = ret_size;
+					GST_BUFFER_TIMESTAMP(outbuf) = faac->next_ts;
+					GST_BUFFER_DURATION (outbuf) = faac->enc_input_duration;
+
+					if(GST_CLOCK_TIME_IS_VALID(faac->next_ts)) {
+						faac->next_ts += faac->enc_input_duration;
+					}
+
+					GST_INFO ("Pushing out buffer time:%" GST_TIME_FORMAT " duration:%"
+							  GST_TIME_FORMAT " size:%d (POST EOS)",
+							  GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(outbuf)),
+							  GST_TIME_ARGS(GST_BUFFER_DURATION(outbuf)),
+							  GST_BUFFER_SIZE(outbuf));
+
+					gst_pad_push(faac->srcpad, outbuf);
+				}
+				else {
+					gst_buffer_unref(outbuf);
+					ret = FALSE;
+				}
+			}
+			else
+				ret = FALSE;
+		}
+
+		ret = gst_pad_event_default(pad, event);
+		break;
     }
     case GST_EVENT_NEWSEGMENT:
-      ret = gst_pad_push_event (faac->srcpad, event);
-      break;
+		ret = gst_pad_push_event (faac->srcpad, event);
+		break;
     case GST_EVENT_TAG:
-      ret = gst_pad_event_default (pad, event);
-      break;
+		ret = gst_pad_event_default (pad, event);
+		break;
     default:
-      ret = gst_pad_event_default (pad, event);
-      break;
-
-  }
-  gst_object_unref (faac);
-  return ret;
+		ret = gst_pad_event_default (pad, event);
+		break;
+	}
+	gst_object_unref (faac);
+	return ret;
 }
 
 static GstFlowReturn
 gst_faac_chain (GstPad * pad, GstBuffer * inbuf)
 {
-  GstFlowReturn result = GST_FLOW_OK;
-  GstBuffer *outbuf, *subbuf;
-  GstFaac *faac;
-  guint size, ret_size, in_size, frame_size;
+	GstFlowReturn result = GST_FLOW_OK;
+	GstBuffer *outbuf, *subbuf;
+	GstFaac *faac;
+	guint size, ret_size;
+	guint cum_total_insize;
 
-  faac = GST_FAAC (gst_pad_get_parent (pad));
+	faac = GST_FAAC (gst_pad_get_parent (pad));
 
-  if (!faac->handle)
-    goto no_handle;
+	if (!faac->handle)
+		goto no_handle;
 
-  if (!GST_PAD_CAPS (faac->srcpad)) {
-    if (!gst_faac_configure_source_pad (faac))
-      goto nego_failed;
-  }
+	if (!GST_PAD_CAPS (faac->srcpad)) {
+		if (!gst_faac_configure_source_pad (faac))
+			goto nego_failed;
+	}
+	
+	/* We need to track the timestamps of encoded buffers because the
+	 * encoder will queue up a few buffers before returning the first
+	 * encoded buffer for output.
+	 */
+	if(faac->stream_start_ts == GST_CLOCK_TIME_NONE) {
+		faac->stream_start_ts = GST_BUFFER_TIMESTAMP(inbuf);
+		faac->next_ts = faac->stream_start_ts;
+	}
 
-  GST_DEBUG ("Got buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT,
-      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
-      GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)));
+	size = GST_BUFFER_SIZE (inbuf);
+	cum_total_insize = size;
+	if(faac->cache)
+		cum_total_insize += GST_BUFFER_SIZE(faac->cache);
 
-  size = GST_BUFFER_SIZE (inbuf);
-  in_size = size;
-  if (faac->cache)
-    in_size += GST_BUFFER_SIZE (faac->cache);
-  frame_size = faac->samples * faac->bps;
+	GST_DEBUG("Caching buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT " size:%d samples:%d",
+			  GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
+			  GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
+			  GST_BUFFER_SIZE (inbuf),
+			  GST_BUFFER_SIZE (inbuf) / (faac->bps * faac->channels));
 
-  while (1) {
-    /* do we have enough data for one frame? */
-    if (in_size / faac->bps < faac->samples) {
-      if (in_size > size) {
-        GstBuffer *merge;
+	/* 
+	 * Merge incomming buffer with the previous buffer
+	 */
+	if(faac->cache == NULL) {
+		faac->cache = inbuf;
+	}
+	else {
+		GstBuffer * merge;
+		merge = gst_buffer_merge(faac->cache, inbuf);
+		gst_buffer_unref(faac->cache);
+		gst_buffer_unref(inbuf);
+		faac->cache = merge;
+	}
 
-        /* this is panic! we got a buffer, but still don't have enough
-         * data. Merge them and retry in the next cycle... */
-        merge = gst_buffer_merge (faac->cache, inbuf);
-        gst_buffer_unref (faac->cache);
-        gst_buffer_unref (inbuf);
-        faac->cache = merge;
-      } else if (in_size == size) {
-        /* this shouldn't happen, but still... */
-        faac->cache = inbuf;
-      } else if (in_size > 0) {
-        faac->cache = gst_buffer_create_sub (inbuf, size - in_size, in_size);
-        GST_BUFFER_DURATION (faac->cache) =
-            GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (faac->cache) / size;
-        GST_BUFFER_TIMESTAMP (faac->cache) =
-            GST_BUFFER_TIMESTAMP (inbuf) + (GST_BUFFER_DURATION (inbuf) *
-            (size - in_size) / size);
-        gst_buffer_unref (inbuf);
-      } else {
-        gst_buffer_unref (inbuf);
-      }
+	/* If not enough data.. return */
+	if(cum_total_insize < faac->enc_input_size)
+		goto done;
 
-      goto done;
-    }
+	/* We now have enough data in the cache.. */
+	if(cum_total_insize > faac->enc_input_size) {
+		guint new_cache_size;
 
-    /* create the frame */
-    if (in_size > size) {
-      GstBuffer *merge;
+		new_cache_size = GST_BUFFER_SIZE(faac->cache) - faac->enc_input_size;
 
-      /* merge */
-      subbuf = gst_buffer_create_sub (inbuf, 0, frame_size - (in_size - size));
-      GST_BUFFER_DURATION (subbuf) =
-          GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (subbuf) / size;
-      merge = gst_buffer_merge (faac->cache, subbuf);
-      gst_buffer_unref (faac->cache);
-      gst_buffer_unref (subbuf);
-      subbuf = merge;
-      faac->cache = NULL;
-    } else {
-      subbuf = gst_buffer_create_sub (inbuf, size - in_size, frame_size);
-      GST_BUFFER_DURATION (subbuf) =
-          GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (subbuf) / size;
-      GST_BUFFER_TIMESTAMP (subbuf) =
-          GST_BUFFER_TIMESTAMP (inbuf) + (GST_BUFFER_DURATION (inbuf) *
-          (size - in_size) / size);
-    }
+		/* We have more audio data than the encoder will accept, so split
+		 * into 2 buffers, caching the remainder for the next encode job.
+		 */
+		subbuf = faac->cache;
+		faac->cache = gst_buffer_create_sub(subbuf, faac->enc_input_size, new_cache_size);
+		GST_BUFFER_TIMESTAMP(faac->cache) = GST_BUFFER_TIMESTAMP(subbuf) + faac->enc_input_duration;
+		GST_BUFFER_DURATION(faac->cache) = GST_BUFFER_DURATION(subbuf) - faac->enc_input_duration;
 
-    result =
-        gst_pad_alloc_buffer_and_set_caps (faac->srcpad, GST_BUFFER_OFFSET_NONE,
-        faac->bytes, GST_PAD_CAPS (faac->srcpad), &outbuf);
-    if (result != GST_FLOW_OK)
-      goto done;
+		GST_BUFFER_DURATION(subbuf) = faac->enc_input_duration;
+		GST_BUFFER_SIZE(subbuf) = faac->enc_input_size;
 
-    if ((ret_size = faacEncEncode (faac->handle,
-                (gint32 *) GST_BUFFER_DATA (subbuf),
-                GST_BUFFER_SIZE (subbuf) / faac->bps,
-                GST_BUFFER_DATA (outbuf), faac->bytes)) < 0) {
-      GST_ELEMENT_ERROR (faac, LIBRARY, ENCODE, (NULL), (NULL));
-      gst_buffer_unref (inbuf);
-      gst_buffer_unref (subbuf);
-      result = GST_FLOW_ERROR;
-      goto done;
-    }
+		GST_DEBUG("Split #1 buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT " size:%d",
+				  GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (subbuf)),
+				  GST_TIME_ARGS (GST_BUFFER_DURATION (subbuf)),
+				  GST_BUFFER_SIZE (subbuf));
+		GST_DEBUG("Split #2 buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT " size:%d",
+				  GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (faac->cache)),
+				  GST_TIME_ARGS (GST_BUFFER_DURATION (faac->cache)),
+				  GST_BUFFER_SIZE (faac->cache));
+	}
+	else {
+		/* We have eaxactly the right amount of data for encoding */
+		subbuf = faac->cache;
+		faac->cache = NULL;
+	}
 
-    if (ret_size > 0) {
-      GST_BUFFER_SIZE (outbuf) = ret_size;
-      if (faac->cache_time != GST_CLOCK_TIME_NONE) {
-        GST_BUFFER_TIMESTAMP (outbuf) = faac->cache_time;
-        faac->cache_time = GST_CLOCK_TIME_NONE;
-      } else
-        GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (subbuf);
-      GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (subbuf);
-      if (faac->cache_duration) {
-        GST_BUFFER_DURATION (outbuf) += faac->cache_duration;
-        faac->cache_duration = 0;
-      }
-      /* Store the value of the next expected timestamp to output
-       * This is required in order to output the trailing encoded packets
-       * at EOS with proper timestamps and duration. */
-      faac->next_ts =
-          GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf);
-      GST_DEBUG ("Pushing out buffer time:%" GST_TIME_FORMAT " duration:%"
-          GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
-          GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
-      result = gst_pad_push (faac->srcpad, outbuf);
-    } else {
-      /* FIXME: what I'm doing here isn't fully correct, but there
-       * really isn't a better way yet.
-       * Problem is that libfaac caches buffers (for encoding
-       * purposes), so the timestamp of the outgoing buffer isn't
-       * the same as the timestamp of the data that I pushed in.
-       * However, I don't know the delay between those two so I
-       * cannot really say aything about it. This is a bad guess. */
+	/* Encode the frame */
+	result = gst_pad_alloc_buffer_and_set_caps(faac->srcpad,
+											   GST_BUFFER_OFFSET_NONE,
+											   faac->bytes,
+											   GST_PAD_CAPS(faac->srcpad),
+											   &outbuf);
+	if(result != GST_FLOW_OK)
+		goto done;
 
-      gst_buffer_unref (outbuf);
-      if (faac->cache_time != GST_CLOCK_TIME_NONE)
-        faac->cache_time = GST_BUFFER_TIMESTAMP (subbuf);
-      faac->cache_duration += GST_BUFFER_DURATION (subbuf);
-    }
+	ret_size = faacEncEncode(faac->handle,
+							 (gint32*)GST_BUFFER_DATA(subbuf),
+							 faac->enc_total_samples,
+							 GST_BUFFER_DATA(outbuf),
+							 faac->bytes);
 
-    in_size -= frame_size;
-    gst_buffer_unref (subbuf);
-  }
+	if(ret_size < 0) {
+		GST_ELEMENT_ERROR(faac, LIBRARY, ENCODE, (NULL), (NULL));
+		gst_buffer_unref (subbuf);
+		result = GST_FLOW_ERROR;
+		goto done;
+	}
 
-done:
-  gst_object_unref (faac);
+	if(ret_size > 0) {
+		GST_BUFFER_SIZE(outbuf) = ret_size;
 
-  return result;
+		GST_BUFFER_TIMESTAMP(outbuf) = faac->next_ts;
+		GST_BUFFER_DURATION(outbuf) = faac->enc_input_duration;
+		faac->next_ts += GST_BUFFER_DURATION(outbuf);
 
-  /* ERRORS */
-no_handle:
-  {
-    GST_ELEMENT_ERROR (faac, CORE, NEGOTIATION, (NULL),
-        ("format wasn't negotiated before chain function"));
-    gst_buffer_unref (inbuf);
-    result = GST_FLOW_ERROR;
-    goto done;
-  }
-nego_failed:
-  {
-    GST_ELEMENT_ERROR (faac, CORE, NEGOTIATION, (NULL),
-        ("failed to negotiate MPEG/AAC format with next element"));
-    gst_buffer_unref (inbuf);
-    result = GST_FLOW_ERROR;
-    goto done;
-  }
+		GST_INFO ("Pushing out buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT " size:%d",
+				   GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(outbuf)),
+				   GST_TIME_ARGS(GST_BUFFER_DURATION(outbuf)),
+				   GST_BUFFER_SIZE(outbuf));
+
+		result = gst_pad_push(faac->srcpad, outbuf);
+	}
+	else {
+		/*
+		 * Encoder is queueing buffers before outputing the first encoded
+		 * buffer, so free the output buffer.
+		 */
+		gst_buffer_unref(outbuf);
+	}
+
+	gst_buffer_unref(subbuf);
+
+ done:
+	gst_object_unref(faac);
+
+	return result;
+
+	/* ERRORS */
+ no_handle:
+	{
+		GST_ELEMENT_ERROR(faac, CORE, NEGOTIATION, (NULL),
+						  ("format wasn't negotiated before chain function"));
+		gst_buffer_unref(inbuf);
+		result = GST_FLOW_ERROR;
+		goto done;
+	}
+ nego_failed:
+	{
+		GST_ELEMENT_ERROR(faac, CORE, NEGOTIATION, (NULL),
+						  ("failed to negotiate MPEG/AAC format with next element"));
+		gst_buffer_unref(inbuf);
+		result = GST_FLOW_ERROR;
+		goto done;
+	}
 }
 
 static void
@@ -788,11 +807,10 @@
         gst_buffer_unref (faac->cache);
         faac->cache = NULL;
       }
-      faac->cache_time = GST_CLOCK_TIME_NONE;
-      faac->cache_duration = 0;
       faac->samplerate = -1;
       faac->channels = -1;
       faac->next_ts = GST_CLOCK_TIME_NONE;
+	  faac->stream_start_ts = GST_CLOCK_TIME_NONE;
       GST_OBJECT_UNLOCK (faac);
       break;
     }
Index: ext/faac/gstfaac.h
===================================================================
--- ext/faac/gstfaac.h	(revision 90)
+++ ext/faac/gstfaac.h	(working copy)
@@ -53,18 +53,20 @@
        outputformat;
   gboolean tns,
            midside;
-  gulong bytes,
-         samples;
+  gulong bytes;
 
+  guint enc_total_samples;
+  guint enc_input_size;
+  GstClockTime enc_input_duration;
+
   /* FAAC object */
   faacEncHandle handle;
 
   /* cache of the input */
   GstBuffer *cache;
-  guint64 cache_time, cache_duration;
-
   /* Expected timestamp of the next buffer to output */
   GstClockTime next_ts;
+  GstClockTime stream_start_ts;
 } GstFaac;
 
 typedef struct _GstFaacClass {
Index: configure.ac
===================================================================
--- configure.ac	(revision 90)
+++ configure.ac	(working copy)
@@ -276,7 +276,6 @@
 AG_GST_CHECK_PLUGIN(nsf)
 AG_GST_CHECK_PLUGIN(nuvdemux)
 AG_GST_CHECK_PLUGIN(pcapparse)
-AG_GST_CHECK_PLUGIN(qtmux)
 AG_GST_CHECK_PLUGIN(rawparse)
 AG_GST_CHECK_PLUGIN(real)
 AG_GST_CHECK_PLUGIN(rtpmanager)
@@ -1224,6 +1223,15 @@
   AC_SUBST(OFA_LIBS)
 ])
 
+dnl **** qtmux (QT Muxer) ****
+translit(dnm, m, l) AM_CONDITIONAL(USE_QTMUX, true)
+AG_GST_CHECK_FEATURE(QTMUX, [qtmux plug-in], qtmux, [
+  AG_GST_CHECK_LIBHEADER(QTMUX, expat, XML_ParserCreate, , expat.h,
+    EXPAT_LIBS="-lexpat")
+  AS_SCRUB_INCLUDE(EXPAT_CFLAGS)
+  AC_SUBST(EXPAT_LIBS)
+])
+
 dnl *** timidity ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_TIMIDITY, true)
 AG_GST_CHECK_FEATURE(TIMIDITY, [timidity midi soft synth plugin], timidity, [
@@ -1480,6 +1488,7 @@
 AM_CONDITIONAL(USE_NEON, false)
 AM_CONDITIONAL(USE_OFA, false)
 AM_CONDITIONAL(USE_OSS4, false)
+AM_CONDITIONAL(USE_QTMUX, false)
 AM_CONDITIONAL(USE_SDL, false)
 AM_CONDITIONAL(USE_SNDFILE, false)
 AM_CONDITIONAL(USE_SOUNDTOUCH, false)
@@ -1628,6 +1637,7 @@
 tests/examples/mxf/Makefile
 tests/examples/scaletempo/Makefile
 tests/examples/switch/Makefile
+tests/examples/qtmux/Makefile
 ext/amrwb/Makefile
 ext/alsaspdif/Makefile
 ext/assrender/Makefile
