summaryrefslogtreecommitdiff
path: root/libgupnp-dlna
diff options
context:
space:
mode:
Diffstat (limited to 'libgupnp-dlna')
-rw-r--r--libgupnp-dlna/Makefile.am86
-rw-r--r--libgupnp-dlna/Makefile.in764
-rw-r--r--libgupnp-dlna/gupnp-dlna-discoverer.c443
-rw-r--r--libgupnp-dlna/gupnp-dlna-discoverer.h116
-rw-r--r--libgupnp-dlna/gupnp-dlna-information.c265
-rw-r--r--libgupnp-dlna/gupnp-dlna-information.h80
-rw-r--r--libgupnp-dlna/gupnp-dlna-marshal.c153
-rw-r--r--libgupnp-dlna/gupnp-dlna-marshal.h28
-rw-r--r--libgupnp-dlna/gupnp-dlna-marshal.list2
-rw-r--r--libgupnp-dlna/gupnp-dlna-profile-private.h44
-rw-r--r--libgupnp-dlna/gupnp-dlna-profile.c386
-rw-r--r--libgupnp-dlna/gupnp-dlna-profile.h77
-rw-r--r--libgupnp-dlna/gupnp-dlna-profiles.c545
-rw-r--r--libgupnp-dlna/profile-loading.c921
-rw-r--r--libgupnp-dlna/profile-loading.h56
15 files changed, 3966 insertions, 0 deletions
diff --git a/libgupnp-dlna/Makefile.am b/libgupnp-dlna/Makefile.am
new file mode 100644
index 0000000..55f4ed2
--- /dev/null
+++ b/libgupnp-dlna/Makefile.am
@@ -0,0 +1,86 @@
+# Version format current:revision:age
+# If the library source code has changed at all since the last update, then
+# increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
+# If any interfaces have been added, removed, or changed since the last update,
+# increment current, and set revision to 0.
+# If any interfaces have been added since the last public release, then
+# increment age.
+# If any interfaces have been removed since the last public release, then set
+# age to 0.
+LTVERSION = $(GUPNP_DLNA_VERSION_INFO)
+
+shareddir = $(datadir)/gupnp-dlna
+
+AM_CFLAGS = -I$(top_srcdir) \
+ $(LIBXML_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(GST_PBU_CFLAGS) \
+ -DDATA_DIR='"$(shareddir)"' \
+ -DG_LOG_DOMAIN='"gupnp-dlna"'
+
+lib_LTLIBRARIES = libgupnp-dlna-1.0.la
+
+gupnp-dlna-marshal.c: gupnp-dlna-marshal.list
+ $(AM_V_GEN) \
+ $(GLIB_GENMARSHAL) --prefix=gupnp_dlna_marshal $(srcdir)/gupnp-dlna-marshal.list --header --body > gupnp-dlna-marshal.c
+
+gupnp-dlna-marshal.h: gupnp-dlna-marshal.list
+ $(AM_V_GEN) \
+ $(GLIB_GENMARSHAL) --prefix=gupnp_dlna_marshal $(srcdir)/gupnp-dlna-marshal.list --header > gupnp-dlna-marshal.h
+
+BUILT_SOURCES = gupnp-dlna-marshal.c gupnp-dlna-marshal.h
+
+libgupnp_dlna_incdir = $(includedir)/gupnp-dlna-1.0/libgupnp-dlna
+
+libgupnp_dlna_1_0_la_LDFLAGS = -version-info $(LTVERSION) -no-undefined
+
+libgupnp_dlna_inc_HEADERS = gupnp-dlna-profile.h \
+ gupnp-dlna-information.h \
+ gupnp-dlna-discoverer.h
+
+noinst_HEADERS = profile-loading.h \
+ gupnp-dlna-profile-private.h
+
+introspection_sources = $(libgupnp_dlna_inc_HEADERS) \
+ gupnp-dlna-information.c \
+ gupnp-dlna-discoverer.c \
+ gupnp-dlna-profile.c \
+ gupnp-dlna-profiles.c \
+ profile-loading.c
+
+libgupnp_dlna_1_0_la_SOURCES = $(introspection_sources) \
+ $(BUILT_SOURCES)
+
+libgupnp_dlna_1_0_la_LIBADD = $(LIBXML_LIBS) \
+ $(GST_PBU_LIBS)
+
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS =
+INTROSPECTION_SCANNER_ARGS = --warn-all \
+ --symbol-prefix=gupnp_dlna \
+ --identifier-prefix=GUPnPDLNA \
+ --add-include-path=$(top_srcdir) \
+ --add-init-section="gst_init(NULL, NULL);"
+INTROSPECTION_COMPILER_ARGS = --includedir=$(top_srcdir)
+
+if HAVE_INTROSPECTION
+GUPnPDLNA-1.0.gir: libgupnp-dlna-1.0.la
+GUPnPDLNA_1_0_gir_INCLUDES = libxml2-2.0 GObject-2.0 GstPbutils-0.10
+GUPnPDLNA_1_0_gir_CFLAGS = $(INCLUDES) $(AM_CFLAGS)
+GUPnPDLNA_1_0_gir_LIBS = libgupnp-dlna-1.0.la gstreamer-0.10
+GUPnPDLNA_1_0_gir_FILES = $(introspection_sources)
+GUPnPDLNA_1_0_gir_NAMESPACE = GUPnPDLNA
+GUPnPDLNA_1_0_gir_VERSION = 1.0
+
+INTROSPECTION_GIRS += GUPnPDLNA-1.0.gir
+
+girdir = $(datadir)/gir-1.0
+gir_DATA = GUPnPDLNA-1.0.gir
+
+typelibdir = $(libdir)/girepository-1.0/
+typelib_DATA = $(gir_DATA:.gir=.typelib)
+endif
+
+EXTRA_DIST = gupnp-dlna-marshal.list
+
+CLEANFILES = $(BUILT_SOURCES) $(gir_DATA) $(typelib_DATA)
diff --git a/libgupnp-dlna/Makefile.in b/libgupnp-dlna/Makefile.in
new file mode 100644
index 0000000..da6a808
--- /dev/null
+++ b/libgupnp-dlna/Makefile.in
@@ -0,0 +1,764 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_INTROSPECTION_TRUE@am__append_1 = GUPnPDLNA-1.0.gir
+subdir = libgupnp-dlna
+DIST_COMMON = $(libgupnp_dlna_inc_HEADERS) $(noinst_HEADERS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gtk-doc.m4 \
+ $(top_srcdir)/m4/introspection.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)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(girdir)" \
+ "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libgupnp_dlna_incdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgupnp_dlna_1_0_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__objects_1 =
+am__objects_2 = $(am__objects_1) gupnp-dlna-information.lo \
+ gupnp-dlna-discoverer.lo gupnp-dlna-profile.lo \
+ gupnp-dlna-profiles.lo profile-loading.lo
+am__objects_3 = gupnp-dlna-marshal.lo
+am_libgupnp_dlna_1_0_la_OBJECTS = $(am__objects_2) $(am__objects_3)
+libgupnp_dlna_1_0_la_OBJECTS = $(am_libgupnp_dlna_1_0_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgupnp_dlna_1_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgupnp_dlna_1_0_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgupnp_dlna_1_0_la_SOURCES)
+DIST_SOURCES = $(libgupnp_dlna_1_0_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(gir_DATA) $(typelib_DATA)
+HEADERS = $(libgupnp_dlna_inc_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GREP = @GREP@
+GST_CFLAGS = @GST_CFLAGS@
+GST_LIBS = @GST_LIBS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_PBU_CFLAGS = @GST_PBU_CFLAGS@
+GST_PBU_LIBS = @GST_PBU_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUPNP_DLNA_VERSION_INFO = @GUPNP_DLNA_VERSION_INFO@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBXML_CFLAGS = @LIBXML_CFLAGS@
+LIBXML_LIBS = @LIBXML_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Version format current:revision:age
+# If the library source code has changed at all since the last update, then
+# increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
+# If any interfaces have been added, removed, or changed since the last update,
+# increment current, and set revision to 0.
+# If any interfaces have been added since the last public release, then
+# increment age.
+# If any interfaces have been removed since the last public release, then set
+# age to 0.
+LTVERSION = $(GUPNP_DLNA_VERSION_INFO)
+shareddir = $(datadir)/gupnp-dlna
+AM_CFLAGS = -I$(top_srcdir) \
+ $(LIBXML_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(GST_PBU_CFLAGS) \
+ -DDATA_DIR='"$(shareddir)"' \
+ -DG_LOG_DOMAIN='"gupnp-dlna"'
+
+lib_LTLIBRARIES = libgupnp-dlna-1.0.la
+BUILT_SOURCES = gupnp-dlna-marshal.c gupnp-dlna-marshal.h
+libgupnp_dlna_incdir = $(includedir)/gupnp-dlna-1.0/libgupnp-dlna
+libgupnp_dlna_1_0_la_LDFLAGS = -version-info $(LTVERSION) -no-undefined
+libgupnp_dlna_inc_HEADERS = gupnp-dlna-profile.h \
+ gupnp-dlna-information.h \
+ gupnp-dlna-discoverer.h
+
+noinst_HEADERS = profile-loading.h \
+ gupnp-dlna-profile-private.h
+
+introspection_sources = $(libgupnp_dlna_inc_HEADERS) \
+ gupnp-dlna-information.c \
+ gupnp-dlna-discoverer.c \
+ gupnp-dlna-profile.c \
+ gupnp-dlna-profiles.c \
+ profile-loading.c
+
+libgupnp_dlna_1_0_la_SOURCES = $(introspection_sources) \
+ $(BUILT_SOURCES)
+
+libgupnp_dlna_1_0_la_LIBADD = $(LIBXML_LIBS) \
+ $(GST_PBU_LIBS)
+
+INTROSPECTION_GIRS = $(am__append_1)
+INTROSPECTION_SCANNER_ARGS = --warn-all \
+ --symbol-prefix=gupnp_dlna \
+ --identifier-prefix=GUPnPDLNA \
+ --add-include-path=$(top_srcdir) \
+ --add-init-section="gst_init(NULL, NULL);"
+
+INTROSPECTION_COMPILER_ARGS = --includedir=$(top_srcdir)
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA_1_0_gir_INCLUDES = libxml2-2.0 GObject-2.0 GstPbutils-0.10
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA_1_0_gir_CFLAGS = $(INCLUDES) $(AM_CFLAGS)
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA_1_0_gir_LIBS = libgupnp-dlna-1.0.la gstreamer-0.10
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA_1_0_gir_FILES = $(introspection_sources)
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA_1_0_gir_NAMESPACE = GUPnPDLNA
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA_1_0_gir_VERSION = 1.0
+@HAVE_INTROSPECTION_TRUE@girdir = $(datadir)/gir-1.0
+@HAVE_INTROSPECTION_TRUE@gir_DATA = GUPnPDLNA-1.0.gir
+@HAVE_INTROSPECTION_TRUE@typelibdir = $(libdir)/girepository-1.0/
+@HAVE_INTROSPECTION_TRUE@typelib_DATA = $(gir_DATA:.gir=.typelib)
+EXTRA_DIST = gupnp-dlna-marshal.list
+CLEANFILES = $(BUILT_SOURCES) $(gir_DATA) $(typelib_DATA)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(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 libgupnp-dlna/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libgupnp-dlna/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: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgupnp-dlna-1.0.la: $(libgupnp_dlna_1_0_la_OBJECTS) $(libgupnp_dlna_1_0_la_DEPENDENCIES) $(EXTRA_libgupnp_dlna_1_0_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgupnp_dlna_1_0_la_LINK) -rpath $(libdir) $(libgupnp_dlna_1_0_la_OBJECTS) $(libgupnp_dlna_1_0_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gupnp-dlna-discoverer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gupnp-dlna-information.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gupnp-dlna-marshal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gupnp-dlna-profile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gupnp-dlna-profiles.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile-loading.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-girDATA: $(gir_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(gir_DATA)'; test -n "$(girdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(girdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(girdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(girdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(girdir)" || exit $$?; \
+ done
+
+uninstall-girDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(gir_DATA)'; test -n "$(girdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(girdir)'; $(am__uninstall_files_from_dir)
+install-typelibDATA: $(typelib_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(typelib_DATA)'; test -n "$(typelibdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(typelibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(typelibdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(typelibdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(typelibdir)" || exit $$?; \
+ done
+
+uninstall-typelibDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(typelib_DATA)'; test -n "$(typelibdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(typelibdir)'; $(am__uninstall_files_from_dir)
+install-libgupnp_dlna_incHEADERS: $(libgupnp_dlna_inc_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(libgupnp_dlna_inc_HEADERS)'; test -n "$(libgupnp_dlna_incdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libgupnp_dlna_incdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libgupnp_dlna_incdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libgupnp_dlna_incdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libgupnp_dlna_incdir)" || exit $$?; \
+ done
+
+uninstall-libgupnp_dlna_incHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libgupnp_dlna_inc_HEADERS)'; test -n "$(libgupnp_dlna_incdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libgupnp_dlna_incdir)'; $(am__uninstall_files_from_dir)
+
+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)
+ set x; \
+ 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; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ 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)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__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 "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libgupnp_dlna_incdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-girDATA install-libgupnp_dlna_incHEADERS \
+ install-typelibDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-girDATA uninstall-libLTLIBRARIES \
+ uninstall-libgupnp_dlna_incHEADERS uninstall-typelibDATA
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool 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-girDATA \
+ install-html install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-libgupnp_dlna_incHEADERS \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip install-typelibDATA 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-girDATA \
+ uninstall-libLTLIBRARIES uninstall-libgupnp_dlna_incHEADERS \
+ uninstall-typelibDATA
+
+
+gupnp-dlna-marshal.c: gupnp-dlna-marshal.list
+ $(AM_V_GEN) \
+ $(GLIB_GENMARSHAL) --prefix=gupnp_dlna_marshal $(srcdir)/gupnp-dlna-marshal.list --header --body > gupnp-dlna-marshal.c
+
+gupnp-dlna-marshal.h: gupnp-dlna-marshal.list
+ $(AM_V_GEN) \
+ $(GLIB_GENMARSHAL) --prefix=gupnp_dlna_marshal $(srcdir)/gupnp-dlna-marshal.list --header > gupnp-dlna-marshal.h
+
+-include $(INTROSPECTION_MAKEFILE)
+
+@HAVE_INTROSPECTION_TRUE@GUPnPDLNA-1.0.gir: libgupnp-dlna-1.0.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libgupnp-dlna/gupnp-dlna-discoverer.c b/libgupnp-dlna/gupnp-dlna-discoverer.c
new file mode 100644
index 0000000..faf21ff
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-discoverer.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "gupnp-dlna-discoverer.h"
+#include "gupnp-dlna-marshal.h"
+#include "profile-loading.h"
+
+/**
+ * SECTION:gupnp-dlna-discoverer
+ * @short_description: Utility API for discovering DLNA profile/mime type and
+ * other metadata for given media.
+ *
+ * The GUPnPDLNADiscoverer object provides a light-weight wrapper over the
+ * #GstDiscoverer API. The latter provides a simple interface to discover
+ * media metadata given a URI. GUPnPDLNADiscoverer extends this API to also
+ * provide a DLNA profile name and mime type for the media.
+ *
+ * The API provided corresponds very closely to the API provided by
+ * #GstDiscoverer - both synchronous and asynchronous discovery of metadata
+ * are possible.
+ *
+ * The asynchronous mode requires a running #GMainLoop in the default
+ * #GMainContext, where one connects to the various signals, appends the
+ * URIs to be processed and then asks for the discovery to begin.
+ */
+enum {
+ DONE,
+ SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST];
+
+
+G_DEFINE_TYPE (GUPnPDLNADiscoverer, gupnp_dlna_discoverer, GST_TYPE_DISCOVERER)
+
+#define GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ GUPNP_TYPE_DLNA_DISCOVERER, \
+ GUPnPDLNADiscovererPrivate))
+
+typedef struct _GUPnPDLNADiscovererPrivate GUPnPDLNADiscovererPrivate;
+
+struct _GUPnPDLNADiscovererPrivate {
+ gboolean relaxed_mode;
+ gboolean extended_mode;
+};
+
+enum {
+ PROP_0,
+ PROP_DLNA_RELAXED_MODE,
+ PROP_DLNA_EXTENDED_MODE,
+};
+
+static void
+gupnp_dlna_discoverer_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GUPnPDLNADiscoverer *self = GUPNP_DLNA_DISCOVERER (object);
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DLNA_RELAXED_MODE:
+ priv->relaxed_mode = g_value_get_boolean (value);
+ break;
+
+ case PROP_DLNA_EXTENDED_MODE:
+ priv->extended_mode = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+ break;
+ }
+}
+
+static void
+gupnp_dlna_discoverer_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GUPnPDLNADiscoverer *self = GUPNP_DLNA_DISCOVERER (object);
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DLNA_RELAXED_MODE:
+ g_value_set_boolean (value, priv->relaxed_mode);
+ break;
+
+ case PROP_DLNA_EXTENDED_MODE:
+ g_value_set_boolean (value, priv->extended_mode);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+ break;
+ }
+}
+
+static void
+gupnp_dlna_discoverer_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (gupnp_dlna_discoverer_parent_class)->dispose (object);
+}
+
+static void
+gupnp_dlna_discoverer_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gupnp_dlna_discoverer_parent_class)->finalize (object);
+}
+
+static void
+gupnp_dlna_discovered_cb (GstDiscoverer *discoverer,
+ GstDiscovererInfo *info,
+ GError *err)
+{
+ GUPnPDLNAInformation *dlna = NULL;
+ GUPnPDLNADiscovererClass *klass =
+ GUPNP_DLNA_DISCOVERER_GET_CLASS (discoverer);
+ GUPnPDLNADiscovererPrivate *priv =
+ GET_PRIVATE (GUPNP_DLNA_DISCOVERER (discoverer));
+ gboolean relaxed = priv->relaxed_mode;
+ gboolean extended = priv->extended_mode;
+
+ if (info)
+ dlna = gupnp_dlna_information_new_from_discoverer_info
+ (info,
+ klass->profiles_list
+ [relaxed][extended]);
+
+ g_signal_emit (GUPNP_DLNA_DISCOVERER (discoverer),
+ signals[DONE], 0, dlna, err);
+
+ if (dlna)
+ g_object_unref (dlna);
+}
+
+static void
+gupnp_dlna_discoverer_class_init (GUPnPDLNADiscovererClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (GUPnPDLNADiscovererPrivate));
+
+ object_class->get_property = gupnp_dlna_discoverer_get_property;
+ object_class->set_property = gupnp_dlna_discoverer_set_property;
+ object_class->dispose = gupnp_dlna_discoverer_dispose;
+ object_class->finalize = gupnp_dlna_discoverer_finalize;
+
+ /**
+ * GUPnPDLNADiscoverer::relaxed-mode:
+ * @relaxed_mode: setting to true will enable relaxed mode
+ *
+ * The current release does not support relaxed mode yet
+ */
+ pspec = g_param_spec_boolean ("relaxed-mode",
+ "Relaxed mode property",
+ "Indicates that profile matching should"
+ "be strictly compliant with the DLNA "
+ "specification",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class,
+ PROP_DLNA_RELAXED_MODE,
+ pspec);
+
+ /**
+ * GUPnPDLNADiscoverer::extended-mode:
+ * @extended: setting true will enable extended profile support
+ *
+ * The current release does not support extended mode yet
+ */
+ pspec = g_param_spec_boolean ("extended-mode",
+ "Extended mode property",
+ "Indicates support for profiles that are "
+ "not part of the DLNA specification",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class,
+ PROP_DLNA_EXTENDED_MODE,
+ pspec);
+
+ /**
+ * GUPnPDLNADiscoverer::done:
+ * @discoverer: the #GUPnPDLNADiscoverer
+ * @dlna: the results as #GUPnPDLNAInformation
+ * @err: contains details of the error if discovery fails, else is NULL
+ *
+ * Will be emitted when all information on a URI could be discovered.
+ *
+ * The reciever must unref @dlna with when done using it.
+ */
+ signals[DONE] =
+ g_signal_new ("done", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GUPnPDLNADiscovererClass, done),
+ NULL, NULL,
+ gupnp_dlna_marshal_VOID__OBJECT_BOXED,
+ G_TYPE_NONE, 2, GUPNP_TYPE_DLNA_INFORMATION,
+ GST_TYPE_G_ERROR);
+
+ /* Load DLNA profiles from disk */
+ if (g_type_from_name ("GstElement")) {
+ klass->profiles_list [0][0]
+ = gupnp_dlna_load_profiles_from_disk (FALSE,
+ FALSE);
+ klass->profiles_list [0][1]
+ = gupnp_dlna_load_profiles_from_disk (FALSE,
+ TRUE);
+ klass->profiles_list [1][0]
+ = gupnp_dlna_load_profiles_from_disk (TRUE,
+ FALSE);
+ klass->profiles_list [1][1]
+ = gupnp_dlna_load_profiles_from_disk (TRUE,
+ TRUE);
+ } else {
+ klass->profiles_list [0][0] = NULL;
+ klass->profiles_list [0][1] = NULL;
+ klass->profiles_list [1][0] = NULL;
+ klass->profiles_list [1][1] = NULL;
+ g_warning ("GStreamer has not yet been initialised. You need "
+ "to call gst_init()/gst_init_check() for discovery "
+ "to work.");
+ }
+}
+
+static void
+gupnp_dlna_discoverer_init (GUPnPDLNADiscoverer *self)
+{
+ g_signal_connect (&self->parent,
+ "discovered",
+ G_CALLBACK (gupnp_dlna_discovered_cb),
+ NULL);
+}
+
+/**
+ * gupnp_dlna_discoverer_new:
+ * @timeout: default discovery timeout, in nanoseconds
+ * @relaxed_mode: set to TRUE, to enable relaxed mode support. FALSE otherwise
+ * @extended_mode: set to TRUE, to enable extended mode support. FALSE otherwise
+ *
+ * Creates a new #GUPnPDLNADiscoverer object with the given default timeout
+ * value.
+ *
+ * Returns: A new #GUPnPDLNADiscoverer object.
+ */
+GUPnPDLNADiscoverer*
+gupnp_dlna_discoverer_new (GstClockTime timeout,
+ gboolean relaxed_mode,
+ gboolean extended_mode)
+{
+ return g_object_new (GUPNP_TYPE_DLNA_DISCOVERER,
+ "timeout", timeout,
+ "relaxed-mode", relaxed_mode,
+ "extended-mode", extended_mode,
+ NULL);
+}
+
+/* Asynchronous API */
+
+/**
+ * gupnp_dlna_discoverer_start:
+ * @discoverer: #GUPnPDLNADiscoverer object to start discovery on
+ *
+ * Allows asynchronous discovery of URIs to begin.
+ */
+
+/**
+ * gupnp_dlna_discoverer_stop:
+ * @discoverer: #GUPnPDLNADiscoverer object to stop discovery on
+ *
+ * Stops asynchronous discovery of URIs.
+ */
+
+/**
+ * gupnp_dlna_discoverer_discover_uri:
+ * @discoverer: #GUPnPDLNADiscoverer object to use for discovery
+ * @uri: URI to gather metadata for
+ *
+ * Queues @uri for metadata discovery. When discovery is completed, the
+ * "discovered" signal is emitted on @discoverer.
+ *
+ * Returns: TRUE if @uri was successfully queued, FALSE otherwise.
+ */
+gboolean
+gupnp_dlna_discoverer_discover_uri (GUPnPDLNADiscoverer *discoverer,
+ const gchar *uri)
+{
+ return gst_discoverer_discover_uri_async (GST_DISCOVERER (discoverer),
+ uri);
+}
+
+/* Synchronous API */
+
+/**
+ * gupnp_dlna_discoverer_discover_uri_sync:
+ * @discoverer: #GUPnPDLNADiscoverer object to use for discovery
+ * @uri: URI to gather metadata for
+ * @err: contains details of the error if discovery fails, else is NULL
+ *
+ * Synchronously gathers metadata for @uri.
+ *
+ * Returns: (transfer full): a #GUPnPDLNAInformation with the metadata for @uri
+ * on success, NULL otherwise
+ */
+GUPnPDLNAInformation *
+gupnp_dlna_discoverer_discover_uri_sync (GUPnPDLNADiscoverer *discoverer,
+ const gchar *uri,
+ GError **err)
+{
+ GstDiscovererInfo *info;
+ GUPnPDLNADiscovererClass *klass =
+ GUPNP_DLNA_DISCOVERER_GET_CLASS (discoverer);
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (discoverer);
+ gboolean relaxed = priv->relaxed_mode;
+ gboolean extended = priv->extended_mode;
+
+ info = gst_discoverer_discover_uri (GST_DISCOVERER (discoverer),
+ uri,
+ err);
+
+ if (info)
+ return gupnp_dlna_information_new_from_discoverer_info
+ (info, klass->profiles_list [relaxed][extended]);
+
+ return NULL;
+}
+
+/**
+ * gupnp_dlna_discoverer_get_profile:
+ * @self: The #GUPnPDLNADiscoverer object
+ * @name: The name of the DLNA profile to be retrieved
+ *
+ * Given @name, this finds the corresponding DLNA profile information (stored
+ * as a #GUPnPDLNAProfile).
+ *
+ * Returns: (transfer full): a #GUPnPDLNAProfile on success, NULL otherwise.
+ **/
+GUPnPDLNAProfile *
+gupnp_dlna_discoverer_get_profile (GUPnPDLNADiscoverer *self,
+ const gchar *name)
+{
+ GList *i;
+ GUPnPDLNADiscovererClass *klass;
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (self);
+ gboolean relaxed = priv->relaxed_mode;
+ gboolean extended = priv->extended_mode;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ klass = GUPNP_DLNA_DISCOVERER_GET_CLASS (self);
+
+ for (i = klass->profiles_list [relaxed][extended];
+ i != NULL;
+ i = i->next) {
+ GUPnPDLNAProfile *profile = (GUPnPDLNAProfile *) i->data;
+
+ if (g_str_equal (gupnp_dlna_profile_get_name (profile), name)) {
+ g_object_ref (profile);
+ return profile;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * gupnp_dlna_discoverer_list_profiles:
+ * @self: The #GUPnPDLNADiscoverer whose profile list is required
+ *
+ * Retuns a list of the all the DLNA profiles supported by @self.
+ *
+ * Returns: (transfer none) (element-type GUPnPDLNAProfile*): a #GList of
+ * #GUPnPDLNAProfile on success, NULL otherwise.
+ **/
+const GList *
+gupnp_dlna_discoverer_list_profiles (GUPnPDLNADiscoverer *self)
+{
+ GUPnPDLNADiscovererClass *klass;
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (self);
+ gboolean relaxed = priv->relaxed_mode;
+ gboolean extended = priv->extended_mode;
+
+ g_return_val_if_fail (self != NULL, NULL);
+
+ klass = GUPNP_DLNA_DISCOVERER_GET_CLASS (self);
+
+ return klass->profiles_list [relaxed][extended];
+}
+
+/**
+ * gupnp_dlna_discoverer_get_relaxed_mode:
+ * @self: The #GUPnPDLNADiscoverer object
+ *
+ * Returns: true if relaxed mode is set and false otherwise
+ */
+gboolean
+gupnp_dlna_discoverer_get_relaxed_mode (GUPnPDLNADiscoverer *self)
+{
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (self);
+
+ return priv->relaxed_mode;
+}
+
+/**
+ * gupnp_dlna_discoverer_get_extended_mode:
+ * @self: The #GUPnPDLNADiscoverer object
+ *
+ * Returns: true if application is using extended mode and false otherwise
+ */
+gboolean
+gupnp_dlna_discoverer_get_extended_mode (GUPnPDLNADiscoverer *self)
+{
+ GUPnPDLNADiscovererPrivate *priv = GET_PRIVATE (self);
+
+ return priv->extended_mode;
+}
diff --git a/libgupnp-dlna/gupnp-dlna-discoverer.h b/libgupnp-dlna/gupnp-dlna-discoverer.h
new file mode 100644
index 0000000..bdf9e45
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-discoverer.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef _GUPNP_DLNA_DISCOVERER
+#define _GUPNP_DLNA_DISCOVERER
+
+#include <glib-object.h>
+#include <gst/pbutils/pbutils.h>
+#include "gupnp-dlna-information.h"
+#include "gupnp-dlna-profile.h"
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_DLNA_DISCOVERER gupnp_dlna_discoverer_get_type()
+
+#define GUPNP_DLNA_DISCOVERER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GUPNP_TYPE_DLNA_DISCOVERER, \
+ GUPnPDLNADiscoverer))
+
+#define GUPNP_DLNA_DISCOVERER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ GUPNP_TYPE_DLNA_DISCOVERER, \
+ GUPnPDLNADiscovererClass))
+
+#define GUPNP_IS_DLNA_DISCOVERER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ GUPNP_TYPE_DLNA_DISCOVERER))
+
+#define GUPNP_IS_DLNA_DISCOVERER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ GUPNP_TYPE_DLNA_DISCOVERER))
+
+#define GUPNP_DLNA_DISCOVERER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GUPNP_TYPE_DLNA_DISCOVERER, \
+ GUPnPDLNADiscovererClass))
+
+/**
+ * GUPnPDLNADiscoverer:
+ *
+ * The top-level object used to for metadata extraction.
+ */
+typedef struct {
+ GstDiscoverer parent;
+} GUPnPDLNADiscoverer;
+
+typedef struct {
+ GstDiscovererClass parent_class;
+
+ /*< signals >*/
+ void (*done) (GUPnPDLNADiscoverer *discoverer,
+ GUPnPDLNAInformation *dlna,
+ GError *err);
+
+ /*< private >*/
+ GList *profiles_list[2][2];
+
+} GUPnPDLNADiscovererClass;
+
+GType gupnp_dlna_discoverer_get_type (void);
+
+GUPnPDLNADiscoverer *
+gupnp_dlna_discoverer_new (GstClockTime timeout,
+ gboolean relaxed_mode,
+ gboolean extended_mode);
+
+/* Asynchronous API */
+#define gupnp_dlna_discoverer_start(discoverer) \
+ gst_discoverer_start(GST_DISCOVERER((discoverer)))
+#define gupnp_dlna_discoverer_stop(discoverer) \
+ gst_discoverer_stop(GST_DISCOVERER((discoverer)))
+gboolean
+gupnp_dlna_discoverer_discover_uri (GUPnPDLNADiscoverer *discoverer,
+ const gchar *uri);
+
+/* Synchronous API */
+GUPnPDLNAInformation *
+gupnp_dlna_discoverer_discover_uri_sync (GUPnPDLNADiscoverer *discoverer,
+ const gchar *uri,
+ GError **err);
+
+/* Get a GUPnPDLNAProfile by name */
+GUPnPDLNAProfile *
+gupnp_dlna_discoverer_get_profile (GUPnPDLNADiscoverer *self,
+ const gchar *name);
+
+/* API to list all available profiles */
+const GList *
+gupnp_dlna_discoverer_list_profiles (GUPnPDLNADiscoverer *self);
+gboolean
+gupnp_dlna_discoverer_get_relaxed_mode (GUPnPDLNADiscoverer *self);
+gboolean
+gupnp_dlna_discoverer_get_extended_mode (GUPnPDLNADiscoverer *self);
+
+G_END_DECLS
+
+#endif /* _GUPNP_DLNA_DISCOVERER */
diff --git a/libgupnp-dlna/gupnp-dlna-information.c b/libgupnp-dlna/gupnp-dlna-information.c
new file mode 100644
index 0000000..5585893
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-information.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "gupnp-dlna-information.h"
+#include <gst/gstminiobject.h>
+
+/**
+ * SECTION:gupnp-dlna-information
+ * @short_description: Object containing metadata information returned by the
+ * #GUPnPDLNADiscoverer API
+ *
+ * The GUPnPDLNAInformation object holds metadata information discovered by the
+ * GUPnPDiscoverer API. The DLNA profile name and MIME type have their own
+ * fields, and other metadata is held in a GstDiscovererInfo structure.
+ * All fields are read-only.
+ */
+
+G_DEFINE_TYPE (GUPnPDLNAInformation, gupnp_dlna_information, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ GUPNP_TYPE_DLNA_INFORMATION, \
+ GUPnPDLNAInformationPrivate))
+
+typedef struct _GUPnPDLNAInformationPrivate GUPnPDLNAInformationPrivate;
+
+struct _GUPnPDLNAInformationPrivate {
+ GstDiscovererInfo *info;
+ gchar *name;
+ gchar *mime;
+};
+
+enum {
+ PROP_0,
+ PROP_DLNA_NAME,
+ PROP_DLNA_MIME,
+ PROP_DISCOVERER_INFO,
+};
+
+static void
+gupnp_dlna_information_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GUPnPDLNAInformation *self = GUPNP_DLNA_INFORMATION (object);
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DLNA_NAME:
+ g_value_set_string (value, priv->name);
+
+ break;
+
+ case PROP_DLNA_MIME:
+ g_value_set_string (value, priv->mime);
+
+ break;
+
+ case PROP_DISCOVERER_INFO:
+ gst_value_set_mini_object (value,
+ GST_MINI_OBJECT(priv->info));
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+
+ break;
+ }
+}
+
+static void
+gupnp_dlna_information_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GUPnPDLNAInformation *self = GUPNP_DLNA_INFORMATION (object);
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DLNA_NAME:
+ g_free (priv->name);
+ priv->name = g_value_dup_string (value);
+
+ break;
+
+ case PROP_DLNA_MIME:
+ g_free (priv->mime);
+ priv->mime = g_value_dup_string (value);
+
+ break;
+
+ case PROP_DISCOVERER_INFO:
+ if (priv->info)
+ gst_discoverer_info_unref (priv->info);
+ priv->info = GST_DISCOVERER_INFO
+ (gst_value_dup_mini_object (value));
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+
+ break;
+ }
+}
+
+
+static void
+gupnp_dlna_information_finalize (GObject *object)
+{
+ GUPnPDLNAInformation *self = GUPNP_DLNA_INFORMATION (object);
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ g_free (priv->name);
+ g_free (priv->mime);
+ if (priv->info)
+ gst_discoverer_info_unref (priv->info);
+
+ G_OBJECT_CLASS (gupnp_dlna_information_parent_class)->finalize (object);
+}
+
+static void
+gupnp_dlna_information_class_init (GUPnPDLNAInformationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (GUPnPDLNAInformationPrivate));
+
+ object_class->get_property = gupnp_dlna_information_get_property;
+ object_class->set_property = gupnp_dlna_information_set_property;
+ object_class->finalize = gupnp_dlna_information_finalize;
+
+ pspec = g_param_spec_string ("name",
+ "DLNA profile name",
+ "The name of the DLNA profile "
+ "corresponding to the strream",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_DLNA_NAME, pspec);
+
+ pspec = g_param_spec_string ("mime",
+ "DLNA profile MIME type corresponding "
+ "to the stream",
+ "The DLNA MIME type of the stream",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_DLNA_MIME, pspec);
+
+ pspec = gst_param_spec_mini_object ("info",
+ "Stream metadata",
+ "Metadata of the stream in a "
+ "GstDiscovererInfo structure",
+ GST_TYPE_DISCOVERER_INFO,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class,
+ PROP_DISCOVERER_INFO,
+ pspec);
+}
+
+static void
+gupnp_dlna_information_init (GUPnPDLNAInformation *self)
+{
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ priv->name = NULL;
+ priv->mime = NULL;
+ priv->info = NULL;
+}
+
+/**
+ * gupnp_dlna_information_new:
+ * @name: DLNA media profile name corresponding to the media
+ * @mime: DLNA MIME type for the media
+ * @info: #GstDiscovererInfo type with additional metadata about the
+ * stream
+ *
+ * Creates a new #GUPnPDLNAInformation object with the given properties.
+ *
+ * Returns: A newly created #GUPnPDLNAInformation object.
+ */
+GUPnPDLNAInformation*
+gupnp_dlna_information_new (gchar *name,
+ gchar *mime,
+ GstDiscovererInfo *info)
+{
+ return g_object_new (GUPNP_TYPE_DLNA_INFORMATION,
+ "name", name,
+ "mime", mime,
+ "info", info,
+ NULL);
+}
+
+/**
+ * gupnp_dlna_information_get_name:
+ * @self: The #GUPnPDLNAInformation object
+ *
+ * Returns: the DLNA profile name of the stream represented by @self. Do not
+ * free this string.
+ */
+const gchar *
+gupnp_dlna_information_get_name (GUPnPDLNAInformation *self)
+{
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ return priv->name;
+}
+
+/**
+ * gupnp_dlna_information_get_mime:
+ * @self: The #GUPnPDLNAInformation object
+ *
+ * Returns: the DLNA MIME type of the stream represented by @self. Do not
+ * free this string.
+ */
+const gchar *
+gupnp_dlna_information_get_mime (GUPnPDLNAInformation *self)
+{
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ return priv->mime;
+}
+
+/**finalize
+ * gupnp_dlna_information_get_info:
+ * @self: The #GUPnPDLNAInformation object
+ *
+ * Returns: additional stream metadata for @self in the form of a
+ * #GstDiscovererInfo structure. Do not free this structure.
+ */
+const GstDiscovererInfo *
+gupnp_dlna_information_get_info (GUPnPDLNAInformation *self)
+{
+ GUPnPDLNAInformationPrivate *priv = GET_PRIVATE (self);
+
+ return priv->info;
+}
diff --git a/libgupnp-dlna/gupnp-dlna-information.h b/libgupnp-dlna/gupnp-dlna-information.h
new file mode 100644
index 0000000..5293fc1
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-information.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GUPNP_DLNA_INFORMATION_H__
+#define __GUPNP_DLNA_INFORMATION_H__
+
+#include <gst/pbutils/pbutils.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_DLNA_INFORMATION gupnp_dlna_information_get_type()
+
+#define GUPNP_DLNA_INFORMATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GUPNP_TYPE_DLNA_INFORMATION, \
+ GUPnPDLNAInformation))
+
+#define GUPNP_DLNA_INFORMATION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ GUPNP_TYPE_DLNA_INFORMATION, \
+ GUPnPDLNAInformationClass))
+
+#define GUPNP_IS_DLNA_INFORMATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GUPNP_TYPE_DLNA_INFORMATION))
+
+#define GUPNP_IS_DLNA_INFORMATION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GUPNP_TYPE_DLNA_INFORMATION))
+
+#define GUPNP_DLNA_INFORMATION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GUPNP_TYPE_DLNA_INFORMATION, \
+ GUPnPDLNAInformationClass))
+
+typedef struct {
+ GObject parent;
+} GUPnPDLNAInformation;
+
+typedef struct {
+ GObjectClass parent_class;
+} GUPnPDLNAInformationClass;
+
+GType gupnp_dlna_information_get_type (void);
+
+GUPnPDLNAInformation*
+gupnp_dlna_information_new (gchar *name,
+ gchar *mime,
+ GstDiscovererInfo *info);
+
+const gchar * gupnp_dlna_information_get_name (GUPnPDLNAInformation *self);
+const gchar * gupnp_dlna_information_get_mime (GUPnPDLNAInformation *self);
+const GstDiscovererInfo *
+gupnp_dlna_information_get_info (GUPnPDLNAInformation *self);
+
+G_GNUC_INTERNAL GUPnPDLNAInformation *
+gupnp_dlna_information_new_from_discoverer_info (GstDiscovererInfo *info,
+ GList *profiles);
+
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_INFORMATION_H__ */
diff --git a/libgupnp-dlna/gupnp-dlna-marshal.c b/libgupnp-dlna/gupnp-dlna-marshal.c
new file mode 100644
index 0000000..7b5a28e
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-marshal.c
@@ -0,0 +1,153 @@
+
+#ifndef __gupnp_dlna_marshal_MARSHAL_H__
+#define __gupnp_dlna_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_schar (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* BOOLEAN:STRING,UINT,STRING,POINTER (./gupnp-dlna-marshal.list:1) */
+extern void gupnp_dlna_marshal_BOOLEAN__STRING_UINT_STRING_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+gupnp_dlna_marshal_BOOLEAN__STRING_UINT_STRING_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_UINT_STRING_POINTER) (gpointer data1,
+ gpointer arg_1,
+ guint arg_2,
+ gpointer arg_3,
+ gpointer arg_4,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__STRING_UINT_STRING_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 5);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__STRING_UINT_STRING_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ g_marshal_value_peek_string (param_values + 3),
+ g_marshal_value_peek_pointer (param_values + 4),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* VOID:OBJECT,BOXED (./gupnp-dlna-marshal.list:2) */
+extern void gupnp_dlna_marshal_VOID__OBJECT_BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+void
+gupnp_dlna_marshal_VOID__OBJECT_BOXED (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__OBJECT_BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__OBJECT_BOXED callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__OBJECT_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_object (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ data2);
+}
+
+G_END_DECLS
+
+#endif /* __gupnp_dlna_marshal_MARSHAL_H__ */
+
diff --git a/libgupnp-dlna/gupnp-dlna-marshal.h b/libgupnp-dlna/gupnp-dlna-marshal.h
new file mode 100644
index 0000000..437e4df
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-marshal.h
@@ -0,0 +1,28 @@
+
+#ifndef __gupnp_dlna_marshal_MARSHAL_H__
+#define __gupnp_dlna_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* BOOLEAN:STRING,UINT,STRING,POINTER (./gupnp-dlna-marshal.list:1) */
+extern void gupnp_dlna_marshal_BOOLEAN__STRING_UINT_STRING_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:OBJECT,BOXED (./gupnp-dlna-marshal.list:2) */
+extern void gupnp_dlna_marshal_VOID__OBJECT_BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+G_END_DECLS
+
+#endif /* __gupnp_dlna_marshal_MARSHAL_H__ */
+
diff --git a/libgupnp-dlna/gupnp-dlna-marshal.list b/libgupnp-dlna/gupnp-dlna-marshal.list
new file mode 100644
index 0000000..c03532c
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-marshal.list
@@ -0,0 +1,2 @@
+BOOLEAN:STRING,UINT,STRING,POINTER
+VOID:OBJECT,BOXED
diff --git a/libgupnp-dlna/gupnp-dlna-profile-private.h b/libgupnp-dlna/gupnp-dlna-profile-private.h
new file mode 100644
index 0000000..0e1f4ed
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-profile-private.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation.
+ *
+ * Authors: Parthasarathi Susarla <partha.susarla@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+#ifndef __GUPNP_DLNA_PROFILE_PRIVATE_H__
+#define __GUPNP_DLNA_PROFILE_PRIVATE_H__
+
+G_BEGIN_DECLS
+
+GUPnPDLNAProfile * gupnp_dlna_profile_new (gchar *name,
+ gchar *mime,
+ GstCaps *container_caps,
+ GstCaps *video_caps,
+ GstCaps *audio_caps,
+ gboolean extended);
+
+
+const GstCaps * gupnp_dlna_profile_get_container_caps (GUPnPDLNAProfile *self);
+const GstCaps * gupnp_dlna_profile_get_video_caps (GUPnPDLNAProfile *self);
+const GstCaps * gupnp_dlna_profile_get_audio_caps (GUPnPDLNAProfile *self);
+
+void gupnp_dlna_profile_set_container_caps (GUPnPDLNAProfile *self, GstCaps *caps);
+void gupnp_dlna_profile_set_video_caps (GUPnPDLNAProfile *self, GstCaps *caps);
+void gupnp_dlna_profile_set_audio_caps (GUPnPDLNAProfile *self, GstCaps *caps);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_PROFILE_PRIVATE_H__ */
diff --git a/libgupnp-dlna/gupnp-dlna-profile.c b/libgupnp-dlna/gupnp-dlna-profile.c
new file mode 100644
index 0000000..b88fed6
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-profile.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include "gupnp-dlna-profile.h"
+#include "gupnp-dlna-profile-private.h"
+#include <gst/gstminiobject.h>
+
+/**
+ * SECTION:gupnp-dlna-profile
+ * @short_description: Object representing a DLNA profile
+ *
+ * The #GUPnPDLNADiscoverer object provides a few APIs that return
+ * #GUPnPDLNAProfile objects. These represent a single DLNA profile. Each
+ * #GUPnPDLNAProfile has a name (the name of the DLNA profile), the
+ * corresponding MIME type, and a #GstEncodingProfile which represents the
+ * various audio/video/container restrictions specified for that DLNA profile.
+ */
+G_DEFINE_TYPE (GUPnPDLNAProfile, gupnp_dlna_profile, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ GUPNP_TYPE_DLNA_PROFILE, \
+ GUPnPDLNAProfilePrivate))
+
+typedef struct _GUPnPDLNAProfilePrivate GUPnPDLNAProfilePrivate;
+
+struct _GUPnPDLNAProfilePrivate {
+ gchar *name;
+ gchar *mime;
+ GstCaps *container_caps;
+ GstCaps *video_caps;
+ GstCaps *audio_caps;
+ gboolean extended;
+ GstEncodingProfile *enc_profile;
+};
+
+enum {
+ PROP_0,
+ PROP_DLNA_NAME,
+ PROP_DLNA_MIME,
+ PROP_ENCODING_PROFILE,
+ PROP_DLNA_EXTENDED,
+};
+
+static void
+gupnp_dlna_profile_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GUPnPDLNAProfile *self = GUPNP_DLNA_PROFILE (object);
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DLNA_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+
+ case PROP_DLNA_MIME:
+ g_value_set_string (value, priv->mime);
+ break;
+
+ case PROP_ENCODING_PROFILE:
+ gst_value_set_mini_object (value,
+ GST_MINI_OBJECT (priv->enc_profile));
+ break;
+
+ case PROP_DLNA_EXTENDED:
+ g_value_set_boolean (value, priv->extended);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+ break;
+ }
+}
+
+static void
+gupnp_dlna_profile_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GUPnPDLNAProfile *self = GUPNP_DLNA_PROFILE (object);
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ switch (property_id) {
+ case PROP_DLNA_NAME:
+ g_free (priv->name);
+ priv->name = g_value_dup_string (value);
+ break;
+
+ case PROP_DLNA_MIME:
+ g_free (priv->mime);
+ priv->mime = g_value_dup_string (value);
+ break;
+
+ case PROP_DLNA_EXTENDED:
+ priv->extended = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID
+ (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gupnp_dlna_profile_finalize (GObject *object)
+{
+ GUPnPDLNAProfile *self = GUPNP_DLNA_PROFILE (object);
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ g_free (priv->name);
+ g_free (priv->mime);
+
+ if (priv->container_caps)
+ gst_caps_unref (priv->container_caps);
+ if (priv->audio_caps)
+ gst_caps_unref (priv->audio_caps);
+ if (priv->video_caps)
+ gst_caps_unref (priv->video_caps);
+
+ if (priv->enc_profile)
+ gst_encoding_profile_unref (priv->enc_profile);
+
+ G_OBJECT_CLASS (gupnp_dlna_profile_parent_class)->finalize (object);
+}
+
+static void
+gupnp_dlna_profile_class_init (GUPnPDLNAProfileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (GUPnPDLNAProfilePrivate));
+
+ object_class->get_property = gupnp_dlna_profile_get_property;
+ object_class->set_property = gupnp_dlna_profile_set_property;
+ object_class->finalize = gupnp_dlna_profile_finalize;
+
+ pspec = g_param_spec_string ("name",
+ "DLNA profile name",
+ "The name of the DLNA profile ",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_DLNA_NAME, pspec);
+
+ pspec = g_param_spec_string ("mime",
+ "DLNA profile MIME type",
+ "The MIME type of the DLNA profile",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_DLNA_MIME, pspec);
+
+ pspec = gst_param_spec_mini_object ("encoding-profile",
+ "Encoding Profile for the "
+ "DLNA Profile",
+ "GstEncodingProfile object"
+ "corresponding to the DLNA profile",
+ GST_TYPE_ENCODING_PROFILE,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_ENCODING_PROFILE,
+ pspec);
+
+ pspec = g_param_spec_boolean ("extended",
+ "Extended mode property",
+ "Indicates that this profile is not "
+ "part of the DLNA specification",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class,
+ PROP_DLNA_EXTENDED,
+ pspec);
+
+}
+
+static void
+gupnp_dlna_profile_init (GUPnPDLNAProfile *self)
+{
+}
+
+const GstCaps *
+gupnp_dlna_profile_get_container_caps (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+ return priv->container_caps;
+}
+
+const GstCaps *
+gupnp_dlna_profile_get_video_caps (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+ return priv->video_caps;
+}
+
+const GstCaps *
+gupnp_dlna_profile_get_audio_caps (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+ return priv->audio_caps;
+}
+
+void
+gupnp_dlna_profile_set_container_caps (GUPnPDLNAProfile *self, GstCaps *caps)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ if (priv->container_caps)
+ gst_caps_unref (priv->container_caps);
+ priv->container_caps = gst_caps_copy (caps);
+}
+
+void
+gupnp_dlna_profile_set_video_caps (GUPnPDLNAProfile *self, GstCaps *caps)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ if (priv->video_caps)
+ gst_caps_unref (priv->video_caps);
+ priv->video_caps = gst_caps_copy (caps);
+}
+
+void
+gupnp_dlna_profile_set_audio_caps (GUPnPDLNAProfile *self, GstCaps *caps)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ if (priv->audio_caps)
+ gst_caps_unref (priv->audio_caps);
+ priv->audio_caps = gst_caps_copy (caps);
+}
+
+GUPnPDLNAProfile *
+gupnp_dlna_profile_new (gchar *name,
+ gchar *mime,
+ GstCaps *container_caps,
+ GstCaps *video_caps,
+ GstCaps *audio_caps,
+ gboolean extended)
+{
+ GUPnPDLNAProfile *prof;
+
+ prof = g_object_new (GUPNP_TYPE_DLNA_PROFILE,
+ "name", name,
+ "mime", mime,
+ "extended", extended,
+ NULL);
+
+ gupnp_dlna_profile_set_container_caps (prof, container_caps);
+ gupnp_dlna_profile_set_video_caps (prof, video_caps);
+ gupnp_dlna_profile_set_audio_caps (prof, audio_caps);
+
+ return prof;
+}
+
+/**
+ * gupnp_dlna_profile_get_name:
+ * @self: The #GUPnPDLNAProfile object
+ *
+ * Returns: the name of the DLNA profile represented by @self
+ */
+const gchar *
+gupnp_dlna_profile_get_name (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+ return priv->name;
+}
+
+/**
+ * gupnp_dlna_profile_get_mime:
+ * @self: The #GUPnPDLNAProfile object
+ *
+ * Returns: the DLNA MIME type of the DLNA profile represented by @self
+ */
+const gchar *
+gupnp_dlna_profile_get_mime (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+ return priv->mime;
+}
+
+/**
+ * gupnp_dlna_profile_get_encoding_profile:
+ * @self: The #GUPnPDLNAProfile object
+ *
+ * Returns: (transfer full): a #GstEncodingProfile object that, in a future
+ * version, can be used to transcode a given stream to match the DLNA
+ * profile represented by @self.
+ * The receiver must unref the returned #GstEncodingProfile when done
+ * using it.
+ */
+GstEncodingProfile *
+gupnp_dlna_profile_get_encoding_profile (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+
+ /* create an encoding-profile if we don't have one */
+ if (!priv->enc_profile) {
+ GstEncodingContainerProfile *container = NULL;
+ GstEncodingAudioProfile *audio_profile = NULL;
+ GstEncodingVideoProfile *video_profile = NULL;
+
+ if (GST_IS_CAPS (priv->video_caps) &&
+ !gst_caps_is_empty (priv->video_caps))
+ video_profile = gst_encoding_video_profile_new
+ (priv->video_caps,NULL, NULL, 0);
+
+ if (GST_IS_CAPS (priv->audio_caps) &&
+ !gst_caps_is_empty (priv->audio_caps))
+ audio_profile = gst_encoding_audio_profile_new
+ (priv->audio_caps,NULL, NULL, 0);
+
+ if (GST_IS_CAPS (priv->container_caps)) {
+ container = gst_encoding_container_profile_new
+ (priv->name,
+ priv->mime,
+ priv->container_caps,
+ NULL);
+
+ if (video_profile)
+ gst_encoding_container_profile_add_profile
+ (container,
+ (GstEncodingProfile *)video_profile);
+
+ if (audio_profile)
+ gst_encoding_container_profile_add_profile
+ (container,
+ (GstEncodingProfile *) audio_profile);
+
+ priv->enc_profile = (GstEncodingProfile *)container;
+ } else {
+ if(audio_profile)
+ /* Container-less audio */
+ priv->enc_profile =
+ (GstEncodingProfile *)audio_profile;
+
+ if (video_profile)
+ /* Container-less video isn't a possibility
+ yet */
+ g_assert_not_reached ();
+ }
+ }
+
+ gst_encoding_profile_ref (priv->enc_profile);
+
+ return priv->enc_profile;
+}
+
+/**
+ * gupnp_dlna_profile_get_extended:
+ * @self: The #GUPnPDLNAProfile object
+ *
+ * Returns: true if application is using extended mode and false otherwise
+ */
+gboolean
+gupnp_dlna_profile_get_extended (GUPnPDLNAProfile *self)
+{
+ GUPnPDLNAProfilePrivate *priv = GET_PRIVATE (self);
+ return priv->extended;
+}
diff --git a/libgupnp-dlna/gupnp-dlna-profile.h b/libgupnp-dlna/gupnp-dlna-profile.h
new file mode 100644
index 0000000..4708a39
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-profile.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GUPNP_DLNA_PROFILE_H__
+#define __GUPNP_DLNA_PROFILE_H__
+
+#include <gst/pbutils/pbutils.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_DLNA_PROFILE gupnp_dlna_profile_get_type()
+
+#define GUPNP_DLNA_PROFILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GUPNP_TYPE_DLNA_PROFILE, \
+ GUPnPDLNAProfile))
+
+#define GUPNP_DLNA_PROFILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ GUPNP_TYPE_DLNA_PROFILE, \
+ GUPnPDLNAProfileClass))
+
+#define GUPNP_IS_DLNA_PROFILE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GUPNP_TYPE_DLNA_PROFILE))
+
+#define GUPNP_IS_DLNA_PROFILE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GUPNP_TYPE_DLNA_PROFILE))
+
+#define GUPNP_DLNA_PROFILE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GUPNP_TYPE_DLNA_PROFILE, \
+ GUPnPDLNAProfileClass))
+
+/**
+ * GUPnPDLNAProfile:
+ *
+ * The top-level object used for the in-memory representation of the DLNA
+ * Profiles.
+ */
+typedef struct {
+ GObject parent;
+} GUPnPDLNAProfile;
+
+typedef struct {
+ GObjectClass parent_class;
+} GUPnPDLNAProfileClass;
+
+GType gupnp_dlna_profile_get_type (void);
+
+const gchar * gupnp_dlna_profile_get_name (GUPnPDLNAProfile *self);
+const gchar * gupnp_dlna_profile_get_mime (GUPnPDLNAProfile *self);
+GstEncodingProfile *
+gupnp_dlna_profile_get_encoding_profile (GUPnPDLNAProfile *self);
+gboolean gupnp_dlna_profile_get_extended (GUPnPDLNAProfile *self);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_PROFILE_H__ */
diff --git a/libgupnp-dlna/gupnp-dlna-profiles.c b/libgupnp-dlna/gupnp-dlna-profiles.c
new file mode 100644
index 0000000..4207b58
--- /dev/null
+++ b/libgupnp-dlna/gupnp-dlna-profiles.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include <glib.h>
+#include <gst/pbutils/pbutils.h>
+#include "gupnp-dlna-discoverer.h"
+#include "gupnp-dlna-profile.h"
+
+/*
+ * This file provides the infrastructure to load DLNA profiles and the
+ * corresponding restrictions from an on-disk representation, and use them to
+ * map a given stream to its DLNA profile, if possible.
+ *
+ * Each DLNA profile is represented as a GstEncodingProfile (there might be
+ * exceptions where a single DLNA profile is represented by multiple
+ * GstEncodingProfiles - right now that's only LPCM).
+ *
+ * For a GstEncodingProfile "profile", the following fields will be populated:
+ *
+ * profile.name = "<DLNA Profile Name>"
+ * profile.format = Muxing format caps (with restrictions) if specified,
+ * else GST_CAPS_NONE
+ * profile.encodingprofiles = GList of GstStreamEncodingProfiles
+ *
+ * For each stream of the given profile, "profile.encodingprofiles" will have
+ * a GstEncodingProfile representing the restrictions for that stream (for a
+ * video format there will be one audio and one video stream, for example).
+ *
+ * enc_profile.type = GST_ENCODING_PROFILE_{AUDIO,VIDEO,...} (UNKNOWN for
+ * container restrictions)
+ * enc_profile.format = GstCaps with all the restrictions for this format
+ * enc_profile.restriction = GST_CAPS_ANY
+ *
+ * We assume that all DLNA profiles have exactly one audio stream, or one audio
+ * stream and one video stream.
+ *
+ * Things yet to account for:
+ *
+ * 1. Multiple audio/video streams (we need to pick the "main" one - how?
+ * Possibly get information from the demuxer.)
+ *
+ * 2. How do we handle discovered metadata which is in tags, but not in caps?
+ * Could potentially move it to caps in a post-discovery, pre-guessing
+ * phase
+ */
+
+/* New profile guessing API */
+
+#define GUPNP_DLNA_DEBUG_ENV "GUPNP_DLNA_DEBUG"
+
+#define gupnp_dlna_debug(args...) \
+do { \
+ const gchar *_e = g_getenv (GUPNP_DLNA_DEBUG_ENV); \
+ if (_e && !g_str_equal (_e, "0")) \
+ g_debug (args); \
+} while (0)
+
+static gboolean
+is_video_profile (const GstEncodingProfile *profile)
+{
+ const GList *i, *profiles_list;
+
+ if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
+ profiles_list = gst_encoding_container_profile_get_profiles
+ (GST_ENCODING_CONTAINER_PROFILE (profile));
+
+ for (i = profiles_list ; i; i = i->next)
+ if (GST_IS_ENCODING_VIDEO_PROFILE (i->data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+structure_can_intersect (const GstStructure *st1, const GstStructure *st2)
+{
+ /* Since there is no API to intersect GstStructures, we cheat (thanks
+ * for the idea, tpm!) and make caps from the structuresa */
+
+ GstCaps *caps1, *caps2;
+ gboolean ret;
+
+ caps1 = gst_caps_new_full (gst_structure_copy (st1), NULL);
+ caps2 = gst_caps_new_full (gst_structure_copy (st2), NULL);
+
+ ret = gst_caps_can_intersect (caps1, caps2);
+
+ gst_caps_unref (caps1);
+ gst_caps_unref (caps2);
+
+ return ret;
+}
+
+static gboolean
+structure_is_subset (const GstStructure *st1, const GstStructure *st2)
+{
+ int i;
+
+ for (i = 0; i < gst_structure_n_fields (st2); i++) {
+ const gchar *name = gst_structure_nth_field_name (st2, i);
+
+ if (!gst_structure_has_field(st1, name)) {
+ gupnp_dlna_debug (" missing field %s", name);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Returns TRUE if stream_caps and profile_caps can intersect, and the
+ * intersecting structure from profile_caps is a subset of stream_caps. Put
+ * simply, the condition being met is that stream_caps intersects with
+ * profile_caps, and that intersection includes *all* fields specified by
+ * profile_caps (viz. all the fields specified by the DLNA profile's
+ * restrictions)
+ */
+static gboolean
+caps_can_intersect_and_is_subset (GstCaps *stream_caps,
+ const GstCaps *profile_caps)
+{
+ int i;
+ GstStructure *stream_st, *profile_st;
+
+ stream_st = gst_caps_get_structure (stream_caps, 0);
+
+ for (i = 0; i < gst_caps_get_size (profile_caps); i++) {
+ profile_st = gst_caps_get_structure (profile_caps, i);
+
+ if (structure_can_intersect (stream_st, profile_st) &&
+ structure_is_subset (stream_st, profile_st))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+match_profile (GstEncodingProfile *profile,
+ GstCaps *caps,
+ GType type)
+{
+ const GList *i, *profiles_list;
+ const gchar *name;
+
+ /* Profiles with an empty name are used only for inheritance and should
+ * not be matched against. */
+ name = gst_encoding_profile_get_name (profile);
+ if (name[0] == '\0')
+ return FALSE;
+
+ profiles_list = gst_encoding_container_profile_get_profiles
+ (GST_ENCODING_CONTAINER_PROFILE (profile));
+
+ for (i = profiles_list; i; i = i->next){
+ GstEncodingProfile *enc_profile = GST_ENCODING_PROFILE
+ (i->data);
+ const GstCaps *format = gst_encoding_profile_get_format
+ (enc_profile);
+
+ if (type == G_TYPE_FROM_INSTANCE (enc_profile) &&
+ caps_can_intersect_and_is_subset (caps, format))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+check_container (GstDiscovererInfo *info,
+ GstEncodingProfile *profile)
+{
+ GstDiscovererStreamInfo *stream_info;
+ GType stream_type;
+ GstCaps *stream_caps;
+ gboolean ret = FALSE;
+
+ const GstCaps *profile_caps = gst_encoding_profile_get_format (profile);
+
+ /* Top-level GstStreamInformation in the topology will be
+ * the container */
+ stream_info = gst_discoverer_info_get_stream_info (info);
+ stream_caps = gst_discoverer_stream_info_get_caps (stream_info);
+ stream_type = G_TYPE_FROM_INSTANCE (stream_info);
+
+ if (stream_type == GST_TYPE_DISCOVERER_CONTAINER_INFO &&
+ gst_caps_can_intersect (stream_caps, profile_caps))
+ ret = TRUE;
+ else if (stream_type != GST_TYPE_DISCOVERER_CONTAINER_INFO &&
+ gst_caps_is_empty (profile_caps))
+ ret = TRUE;
+
+ gst_discoverer_stream_info_unref (stream_info);
+ gst_caps_unref (stream_caps);
+
+ return ret;
+}
+
+static GstCaps *
+caps_from_audio_stream_info (GstDiscovererStreamInfo *info)
+{
+ GstCaps *temp = gst_discoverer_stream_info_get_caps (info);
+ GstCaps *caps = gst_caps_copy (temp);
+ const GstDiscovererAudioInfo *audio_info =
+ GST_DISCOVERER_AUDIO_INFO(info);
+ guint data;
+
+ gst_caps_unref (temp);
+
+ data = gst_discoverer_audio_info_get_sample_rate (audio_info);
+ if (data)
+ gst_caps_set_simple (caps, "rate", G_TYPE_INT, data, NULL);
+
+ data = gst_discoverer_audio_info_get_channels (audio_info);
+ if (data)
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT, data, NULL);
+
+ data = gst_discoverer_audio_info_get_bitrate (audio_info);
+ if (data)
+ gst_caps_set_simple (caps, "bitrate", G_TYPE_INT, data, NULL);
+
+ data = gst_discoverer_audio_info_get_max_bitrate (audio_info);
+ if (data)
+ gst_caps_set_simple
+ (caps, "maximum-bitrate", G_TYPE_INT, data, NULL);
+
+ data = gst_discoverer_audio_info_get_depth (audio_info);
+ if (data)
+ gst_caps_set_simple (caps, "depth", G_TYPE_INT, data, NULL);
+
+ return caps;
+}
+
+static gboolean
+check_audio_profile (GstDiscovererInfo *info,
+ GstEncodingProfile *profile)
+{
+ GstCaps *caps;
+ GList *i, *stream_list;
+ gboolean found = FALSE;
+
+ /* Optimisation TODO: this can be pre-computed */
+ if (is_video_profile (profile))
+ return FALSE;
+
+ stream_list = gst_discoverer_info_get_stream_list (info);
+
+ for (i = stream_list; !found && i; i = i->next) {
+ GstDiscovererStreamInfo *stream =
+ GST_DISCOVERER_STREAM_INFO(i->data);
+ GType stream_type = G_TYPE_FROM_INSTANCE (stream);
+
+ if (stream_type != GST_TYPE_DISCOVERER_AUDIO_INFO)
+ continue;
+
+ caps = caps_from_audio_stream_info (stream);
+
+ if (match_profile (profile,
+ caps,
+ GST_TYPE_ENCODING_AUDIO_PROFILE)) {
+ found = TRUE;
+ break;
+ }
+
+ gst_caps_unref (caps);
+ }
+
+ gst_discoverer_stream_info_list_free (stream_list);
+
+ return found;
+}
+
+static void
+guess_audio_profile (GstDiscovererInfo *info,
+ gchar **name,
+ gchar **mime,
+ GList *profiles)
+{
+ GList *i;
+ GUPnPDLNAProfile *profile;
+ GstEncodingProfile *enc_profile;
+
+ for (i = profiles; i; i = i->next) {
+ profile = (GUPnPDLNAProfile *)(i->data);
+ enc_profile = gupnp_dlna_profile_get_encoding_profile (profile);
+
+ gupnp_dlna_debug ("Checking DLNA profile %s",
+ gupnp_dlna_profile_get_name (profile));
+
+ if (!check_audio_profile (info, enc_profile))
+ gupnp_dlna_debug (" Audio did not match");
+ else if (!check_container (info, enc_profile))
+ gupnp_dlna_debug (" Container did not match");
+ else {
+ *name = g_strdup
+ (gupnp_dlna_profile_get_name (profile));
+ *mime = g_strdup
+ (gupnp_dlna_profile_get_mime (profile));
+ break;
+ }
+ }
+}
+
+static GstCaps *
+caps_from_video_stream_info (GstDiscovererStreamInfo *info)
+{
+ GstCaps *temp = gst_discoverer_stream_info_get_caps (info);
+ GstCaps *caps = gst_caps_copy (temp);
+ const GstDiscovererVideoInfo *video_info =
+ GST_DISCOVERER_VIDEO_INFO (info);
+ const GstTagList *stream_tag_list;
+ guint n, d, data;
+ gboolean value;
+
+ gst_caps_unref (temp);
+
+ data = gst_discoverer_video_info_get_height (video_info);
+ if (data)
+ gst_caps_set_simple (caps, "height", G_TYPE_INT, data, NULL);
+
+ data = gst_discoverer_video_info_get_width (video_info);
+ if (data)
+ gst_caps_set_simple (caps, "width", G_TYPE_INT, data, NULL);
+
+ data = gst_discoverer_video_info_get_depth (video_info);
+ if (data)
+ gst_caps_set_simple (caps, "depth", G_TYPE_INT, data, NULL);
+
+ n = gst_discoverer_video_info_get_framerate_num (video_info);
+ d = gst_discoverer_video_info_get_framerate_denom (video_info);
+ if (n && d)
+ gst_caps_set_simple (caps,
+ "framerate",
+ GST_TYPE_FRACTION, n, d,
+ NULL);
+
+ n = gst_discoverer_video_info_get_par_num (video_info);
+ d = gst_discoverer_video_info_get_par_denom (video_info);
+ if (n && d)
+ gst_caps_set_simple (caps,
+ "pixel-aspect-ratio",
+ GST_TYPE_FRACTION, n, d,
+ NULL);
+
+ value = gst_discoverer_video_info_is_interlaced (video_info);
+ if (value)
+ gst_caps_set_simple
+ (caps, "interlaced", G_TYPE_BOOLEAN, value, NULL);
+
+ stream_tag_list = gst_discoverer_stream_info_get_tags (info);
+ if (stream_tag_list) {
+ guint bitrate;
+ if (gst_tag_list_get_uint (stream_tag_list, "bitrate", &bitrate))
+ gst_caps_set_simple
+ (caps, "bitrate", G_TYPE_INT, (int) bitrate, NULL);
+
+ if (gst_tag_list_get_uint (stream_tag_list,
+ "maximum-bitrate",
+ &bitrate))
+ gst_caps_set_simple (caps,
+ "maximum-bitrate",
+ G_TYPE_INT,
+ (int) bitrate,
+ NULL);
+ }
+
+ return caps;
+}
+
+static gboolean
+check_video_profile (GstDiscovererInfo *info,
+ GstEncodingProfile *profile)
+{
+ GList *i, *stream_list;
+ gboolean found_video = FALSE, found_audio = FALSE;;
+
+ stream_list = gst_discoverer_info_get_stream_list (info);
+
+ /* Check video and audio restrictions */
+ for (i = stream_list;
+ i && !(found_video && found_audio);
+ i = i->next) {
+ GstDiscovererStreamInfo *stream;
+ GType stream_type;
+ GstCaps *caps = NULL;
+
+ stream = GST_DISCOVERER_STREAM_INFO(i->data);
+ stream_type = G_TYPE_FROM_INSTANCE (stream);
+
+ if (!found_video &&
+ stream_type == GST_TYPE_DISCOVERER_VIDEO_INFO) {
+ caps = caps_from_video_stream_info (stream);
+ if (match_profile (profile,
+ caps,
+ GST_TYPE_ENCODING_VIDEO_PROFILE))
+ found_video = TRUE;
+ else
+ gupnp_dlna_debug (" Video did not match");
+ } else if (!found_audio &&
+ stream_type == GST_TYPE_DISCOVERER_AUDIO_INFO) {
+ caps = caps_from_audio_stream_info (stream);
+ if (match_profile (profile,
+ caps,
+ GST_TYPE_ENCODING_AUDIO_PROFILE))
+ found_audio = TRUE;
+ else
+ gupnp_dlna_debug (" Audio did not match");
+ }
+
+ if (caps)
+ gst_caps_unref (caps);
+ }
+
+ gst_discoverer_stream_info_list_free (stream_list);
+
+ if (!found_video || !found_audio)
+ return FALSE;
+
+ /* Check container restrictions */
+ if (!check_container (info, profile)) {
+ gupnp_dlna_debug (" Container did not match");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+guess_video_profile (GstDiscovererInfo *info,
+ gchar **name,
+ gchar **mime,
+ GList *profiles)
+{
+ GUPnPDLNAProfile *profile = NULL;
+ GstEncodingProfile *enc_profile;
+ GList *i;
+
+ for (i = profiles; i; i = i->next) {
+ profile = (GUPnPDLNAProfile *)(i->data);
+ enc_profile = gupnp_dlna_profile_get_encoding_profile (profile);
+
+ gupnp_dlna_debug ("Checking DLNA profile %s",
+ gupnp_dlna_profile_get_name (profile));
+ if (check_video_profile (info, enc_profile)) {
+ *name = g_strdup (gupnp_dlna_profile_get_name (profile));
+ *mime = g_strdup (gupnp_dlna_profile_get_mime (profile));
+ break;
+ }
+ }
+}
+
+static void
+guess_image_profile (GstDiscovererStreamInfo *info,
+ gchar **name,
+ gchar **mime,
+ GList *profiles)
+{
+ GstCaps *caps;
+ GList *i;
+ gboolean found = FALSE;
+ GUPnPDLNAProfile *profile;
+ GstEncodingProfile *enc_profile;
+ const GstDiscovererVideoInfo *video_info =
+ GST_DISCOVERER_VIDEO_INFO (info);
+
+ if (!info || !gst_discoverer_video_info_is_image (video_info))
+ return;
+
+ caps = caps_from_video_stream_info (info);
+
+ for (i = profiles; !found && i; i = i->next) {
+ profile = (GUPnPDLNAProfile *)(i->data);
+ enc_profile = gupnp_dlna_profile_get_encoding_profile (profile);
+
+ /* Optimisation TODO: this can be pre-computed */
+ if (!is_video_profile (enc_profile))
+ continue;
+
+ if (match_profile (enc_profile,
+ caps,
+ GST_TYPE_ENCODING_VIDEO_PROFILE)) {
+ /* Found a match */
+ *name = g_strdup (gupnp_dlna_profile_get_name (profile));
+ *mime = g_strdup (gupnp_dlna_profile_get_mime (profile));
+ break;
+ }
+ }
+
+ gst_caps_unref (caps);
+}
+
+GUPnPDLNAInformation *
+gupnp_dlna_information_new_from_discoverer_info (GstDiscovererInfo *info,
+ GList *profiles)
+{
+ GUPnPDLNAInformation *dlna;
+ GList *video_list, *audio_list;
+ gchar *name = NULL, *mime = NULL;
+
+ video_list = gst_discoverer_info_get_video_streams (info);
+ audio_list = gst_discoverer_info_get_audio_streams (info);
+ if (video_list) {
+ if ((g_list_length (video_list) ==1 ) &&
+ gst_discoverer_video_info_is_image
+ (GST_DISCOVERER_VIDEO_INFO
+ (video_list->data))) {
+ GstDiscovererStreamInfo *stream;
+ stream = (GstDiscovererStreamInfo *) video_list->data;
+ guess_image_profile (stream, &name, &mime, profiles);
+ } else
+ guess_video_profile (info, &name, &mime, profiles);
+ } else if (audio_list)
+ guess_audio_profile (info, &name, &mime, profiles);
+
+ gst_discoverer_stream_info_list_free (audio_list);
+ gst_discoverer_stream_info_list_free (video_list);
+
+ dlna = gupnp_dlna_information_new (name, mime, info);
+
+
+ g_free (name);
+ g_free (mime);
+
+ return dlna;
+}
diff --git a/libgupnp-dlna/profile-loading.c b/libgupnp-dlna/profile-loading.c
new file mode 100644
index 0000000..874fe44
--- /dev/null
+++ b/libgupnp-dlna/profile-loading.c
@@ -0,0 +1,921 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Authors: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <libxml/xmlreader.h>
+#include <libxml/relaxng.h>
+#include <gst/pbutils/pbutils.h>
+#include "profile-loading.h"
+#include "gupnp-dlna-profile.h"
+#include "gupnp-dlna-profile-private.h"
+
+#define GST_CAPS_NULL_NAME "NULL"
+#define DLNA_DATA_DIR DATA_DIR \
+ G_DIR_SEPARATOR_S "dlna-profiles" G_DIR_SEPARATOR_S
+
+static gboolean
+copy_func (GQuark field_id, const GValue *value, gpointer data)
+{
+ GstStructure *st2 = (GstStructure *)data;
+
+ if (!gst_structure_has_field (st2, g_quark_to_string (field_id)))
+ gst_structure_id_set_value (st2, field_id, value);
+
+ return TRUE;
+}
+
+/* Note: It is assumed that caps1 and caps2 have only 1 structure each */
+static GstCaps *
+merge_caps (GstCaps *caps1, GstCaps *caps2)
+{
+ GstStructure *st1, *st2;
+ GstCaps *ret;
+ gboolean any = FALSE;
+
+ /* If one of the caps GST_CAPS_ANY, gst_caps_merge will result in a
+ * GST_CAPS_ANY, which might not be correct for us */
+ if (!gst_caps_is_any (caps1) && !gst_caps_is_any (caps2)) {
+ any = TRUE;
+ gst_caps_merge (caps1, gst_caps_copy (caps2));
+ gst_caps_do_simplify (caps1);
+ }
+
+ ret = gst_caps_make_writable (caps1);
+ st1 = gst_caps_get_structure (ret, 0);
+ if (gst_caps_get_size (caps1) == 2)
+ /* Non-merged fields were copied to a second structure in caps
+ * at gst_merge_caps() time */
+ st2 = gst_caps_get_structure (ret, 1);
+ else
+ /* Either one of the caps was GST_CAPS_ANY, or there were no
+ * unmerged fields */
+ st2 = gst_caps_get_structure (caps2, 0);
+
+ /* If caps1 has a name, we retain it. If not, and caps2 does, caps1
+ * gets caps2's name. */
+ if ((g_strcmp0 (GST_CAPS_NULL_NAME,
+ gst_structure_get_name (st1)) == 0) &&
+ (g_strcmp0 (GST_CAPS_NULL_NAME,
+ gst_structure_get_name (st2)) != 0)) {
+ gst_structure_set_name (st1, gst_structure_get_name (st2));
+ }
+
+ /* We now walk over the structures and append any fields that are in
+ * caps2 but not in caps1. */
+ if (any || gst_caps_get_size (caps1) == 2)
+ gst_structure_foreach (st2, copy_func, st1);
+
+ if (gst_caps_get_size (caps1) == 2)
+ gst_caps_remove_structure (ret, 1);
+
+ return ret;
+}
+
+static xmlChar *
+get_value (xmlTextReaderPtr reader)
+{
+ xmlChar *value = NULL, *curr;
+ int ret = 1;
+
+ curr = xmlTextReaderName (reader);
+
+ /* This function may be called with reader pointing to a <field> or
+ * the element just below a <field>. In the former case, we move the
+ * cursor forward and then continue processing. */
+ if (xmlStrEqual (curr, BAD_CAST ("field")))
+ ret = xmlTextReaderRead (reader);
+ xmlFree (curr);
+
+ while (ret == 1) {
+ xmlChar *tag;
+
+ tag = xmlTextReaderName (reader);
+
+ if (xmlTextReaderNodeType (reader) == 1 &&
+ xmlStrEqual (tag, BAD_CAST ("value"))) {
+ /* <value> */
+
+ /* Note: This assumes you won't have a comment in the
+ * middle of your text */
+ do {
+ ret = xmlTextReaderRead (reader);
+ } while (ret == 1 &&
+ xmlTextReaderNodeType (reader) != 3 &&
+ xmlTextReaderNodeType (reader) != 15);
+
+ /* We're now at the real text between a <value> and a
+ * </value> */
+
+ if (xmlTextReaderNodeType (reader) == 3)
+ value = xmlTextReaderValue (reader);
+ }
+
+ if (xmlTextReaderNodeType (reader) == 15 &&
+ xmlStrEqual (tag, BAD_CAST ("value"))) {
+ /* </value> */
+ xmlFree (tag);
+
+ break;
+ }
+
+ xmlFree (tag);
+ ret = xmlTextReaderRead (reader);
+ }
+
+ if (!value)
+ g_warning ("Empty <value>s are illegal");
+
+ return value;
+}
+
+static void
+xml_str_free (xmlChar *str, gpointer unused)
+{
+ xmlFree (str);
+}
+
+static void
+free_restrictions_struct (gpointer data, gpointer user_data)
+{
+ GUPnPDLNARestrictions *restr = (GUPnPDLNARestrictions *)data;
+ if (restr) {
+ if (restr->caps)
+ gst_caps_unref (restr->caps);
+
+ g_free (restr);
+ }
+}
+
+static void
+process_range (xmlTextReaderPtr reader, GString *caps_str)
+{
+ xmlChar *min, *max;
+
+ min = xmlTextReaderGetAttribute (reader, BAD_CAST ("min"));
+ max = xmlTextReaderGetAttribute (reader, BAD_CAST ("max"));
+
+ g_string_append_printf (caps_str, "[ %s, %s ]", min, max);
+
+ xmlFree (min);
+ xmlFree (max);
+}
+
+static int
+process_field (xmlTextReaderPtr reader,
+ GString *caps_str,
+ gboolean relaxed_mode,
+ gboolean extended_mode)
+{
+ int ret;
+ xmlChar *name;
+ xmlChar *type;
+ xmlChar *used;
+ GList *values = NULL;
+ gboolean done = FALSE, skip = FALSE;
+
+ /*
+ * Parse the 'used' attribute and figure out the mode we
+ * need to follow.
+ */
+ used = xmlTextReaderGetAttribute (reader, BAD_CAST ("used"));
+ if (used) {
+ if ((relaxed_mode == FALSE) &&
+ xmlStrEqual (used, BAD_CAST ("in-relaxed"))) {
+ skip = TRUE;
+ } else if ((relaxed_mode == TRUE) &&
+ (xmlStrEqual (used, BAD_CAST ("in-strict")))) {
+ skip = TRUE;
+ }
+
+ xmlFree (used);
+ }
+
+ name = xmlTextReaderGetAttribute (reader, BAD_CAST ("name"));
+ type = xmlTextReaderGetAttribute (reader, BAD_CAST ("type"));
+
+ /*
+ * This function reads a <field> and appends it to caps_str in the
+ * GstCaps-as-a-string format:
+ *
+ * Single value: field = (type) value
+ * Multiple values: field = (type) { value1, value2, value3 }
+ * Range: field = (type) [ min, max ]
+ */
+
+ /* Fields are comma-separeted. The leading comma is okay for the first
+ * field - we will be prepending the restriction name to this string */
+ if (!skip)
+ g_string_append_printf (caps_str, ", %s = (%s) ", name, type);
+
+ xmlFree (name);
+ xmlFree (type);
+
+ ret = xmlTextReaderRead (reader);
+ while (ret == 1 && !done) {
+ xmlChar *tag;
+
+ tag = xmlTextReaderName (reader);
+
+ switch (xmlTextReaderNodeType (reader)) {
+ case 1:
+ if (skip)
+ break;
+
+ if (xmlStrEqual (tag, BAD_CAST ("range"))) {
+ /* <range> */
+ process_range (reader, caps_str);
+ } else if (xmlStrEqual (tag, BAD_CAST ("value"))) {
+ /* <value> */
+ xmlChar *value;
+
+ value = get_value (reader);
+
+ if (value)
+ values = g_list_append (values, value);
+ }
+
+ break;
+
+ case 15:
+ if (xmlStrEqual (tag, BAD_CAST ("field")))
+ /* </field> */
+ done = TRUE;
+
+ break;
+
+ default:
+ break;
+ }
+
+ xmlFree (tag);
+ ret = xmlTextReaderRead (reader);
+ }
+
+ if (skip)
+ return ret;
+
+ if (g_list_length (values) == 1)
+ /* Single value */
+ g_string_append_printf (caps_str,
+ "%s",
+ (xmlChar *) values->data);
+ else if (g_list_length (values) > 1) {
+ /* Multiple values */
+ GList *tmp = values->next;
+ g_string_append_printf (caps_str,
+ "{ %s",
+ (xmlChar *) values->data);
+
+ do {
+ g_string_append_printf (caps_str,
+ ", %s",
+ (xmlChar *) tmp->data);
+ } while ((tmp = tmp->next) != NULL);
+
+ g_string_append_printf (caps_str, " }");
+ }
+
+ if (values) {
+ g_list_foreach (values, (GFunc) xml_str_free, NULL);
+ g_list_free (values);
+ }
+
+ return ret;
+}
+
+static GUPnPDLNARestrictions *
+process_parent (xmlTextReaderPtr reader, GUPnPDLNALoadState *data)
+{
+ xmlChar *parent;
+ xmlChar *used;
+ GUPnPDLNARestrictions *restr = NULL;
+
+ /*
+ * Check to see if we need to follow any relaxed/strict mode
+ * restrictions.
+ */
+ used = xmlTextReaderGetAttribute (reader, BAD_CAST ("used"));
+ if (used) {
+ if ((data->relaxed_mode == FALSE) &&
+ xmlStrEqual (used, BAD_CAST ("in-relaxed"))) {
+ xmlFree (used);
+ return NULL;
+ } else if ((data->relaxed_mode == TRUE) &&
+ (xmlStrEqual (used, BAD_CAST ("in-strict")))) {
+ xmlFree (used);
+ return NULL;
+ }
+ }
+
+ parent = xmlTextReaderGetAttribute (reader, BAD_CAST ("name"));
+ restr = g_hash_table_lookup (data->restrictions, parent);
+
+ if (!restr) {
+ g_warning ("Could not find parent restriction: %s", parent);
+ return NULL;
+ }
+
+ xmlFree (parent);
+ xmlFree (used);
+
+ return restr;
+}
+
+static GUPnPDLNARestrictions *
+process_restriction (xmlTextReaderPtr reader, GUPnPDLNALoadState *data)
+{
+ GUPnPDLNARestrictions *restr = NULL;
+ GType type;
+ GstCaps *caps = NULL;
+ GString *caps_str = g_string_sized_new (100);
+ GList *parents = NULL, *tmp;
+ xmlChar *id, *name = NULL, *restr_type, *used;
+ int ret;
+ gboolean done = FALSE, skip = FALSE;
+
+ /*
+ * First we parse the 'used' attribute and figure out
+ * the mode we need to comply to.
+ */
+ used = xmlTextReaderGetAttribute (reader, BAD_CAST ("used"));
+ if (used) {
+ if ((data->relaxed_mode == FALSE) &&
+ xmlStrEqual (used, BAD_CAST ("in-relaxed"))) {
+ skip = TRUE;
+ } else if ((data->relaxed_mode == TRUE) &&
+ (xmlStrEqual (used, BAD_CAST ("in-strict")))) {
+ skip = TRUE;
+ }
+ }
+
+ /* We then walk through the fields in this restriction, and make a
+ * string that can be parsed by gst_caps_from_string (). We then make
+ * a GstCaps from this string */
+
+ id = xmlTextReaderGetAttribute (reader, BAD_CAST ("id"));
+ restr_type = xmlTextReaderGetAttribute (reader, BAD_CAST ("type"));
+
+ ret = xmlTextReaderRead (reader);
+ while (ret == 1 && !done) {
+ xmlChar *tag;
+
+ tag = xmlTextReaderName (reader);
+
+ switch (xmlTextReaderNodeType (reader)) {
+ case 1:
+ if (skip)
+ break;
+
+ if (xmlStrEqual (tag, BAD_CAST ("field"))) {
+ /* <field> */
+ xmlChar *field;
+
+ field = xmlTextReaderGetAttribute
+ (reader, BAD_CAST ("name"));
+
+ /* We handle the "name" field specially - if
+ * present, it is the caps name */
+ if (xmlStrEqual (field, BAD_CAST ("name")))
+ name = get_value (reader);
+ else
+ process_field (reader,
+ caps_str,
+ data->relaxed_mode,
+ data->extended_mode);
+
+ xmlFree (field);
+ } else if (xmlStrEqual (tag, BAD_CAST ("parent"))) {
+ /* <parent> */
+ GUPnPDLNARestrictions *restr =
+ process_parent (reader, data);
+
+ if (restr && restr->caps)
+ /* Collect parents in a list - we'll
+ * coalesce them later */
+ parents = g_list_append (parents,
+ gst_caps_copy
+ (restr->caps));
+ }
+
+ break;
+
+ case 15:
+ if (xmlStrEqual (tag, BAD_CAST ("restriction")))
+ /* </restriction> */
+ done = TRUE;
+
+ break;
+
+ default:
+ break;
+ }
+
+ xmlFree (tag);
+ ret = xmlTextReaderRead (reader);
+ }
+
+ if (skip)
+ goto out;
+
+ /* If the restriction doesn't have a name, we make it up */
+ if (!name)
+ name = BAD_CAST (g_strdup (GST_CAPS_NULL_NAME));
+ g_string_prepend (caps_str, (gchar *) name);
+ xmlFree (name);
+
+ if (xmlStrEqual (restr_type, BAD_CAST ("container")))
+ type = GST_TYPE_ENCODING_CONTAINER_PROFILE;
+ else if (xmlStrEqual (restr_type, BAD_CAST ("audio")))
+ type = GST_TYPE_ENCODING_AUDIO_PROFILE;
+ else if (xmlStrEqual (restr_type, BAD_CAST ("video")))
+ type = GST_TYPE_ENCODING_VIDEO_PROFILE;
+ else if (xmlStrEqual (restr_type, BAD_CAST ("image")))
+ type = GST_TYPE_ENCODING_VIDEO_PROFILE;
+ else {
+ g_warning ("Support for '%s' restrictions not yet implemented",
+ restr_type);
+ goto out;
+ }
+
+ caps = gst_caps_from_string (caps_str->str);
+ g_string_free (caps_str, TRUE);
+ g_return_val_if_fail (caps != NULL, NULL);
+
+ tmp = parents;
+ while (tmp) {
+ /* Merge all the parent caps. The child overrides parent
+ * attributes */
+ GstCaps *tmp_caps = (GstCaps *)tmp->data;
+ caps = merge_caps (caps, tmp_caps);
+ gst_caps_unref (tmp_caps);
+ tmp = tmp->next;
+ }
+
+ restr = g_new0 (GUPnPDLNARestrictions, 1);
+
+ restr->caps = gst_caps_copy (caps);
+ restr->type = type;
+
+ if (id)
+ g_hash_table_insert (data->restrictions, id, restr);
+
+out:
+ xmlFree (restr_type);
+ if (used)
+ xmlFree (used);
+ if (caps)
+ gst_caps_unref (caps);
+ if (parents)
+ g_list_free (parents);
+
+ return restr;
+}
+
+static void
+process_restrictions (xmlTextReaderPtr reader, GUPnPDLNALoadState *data)
+{
+ int ret = xmlTextReaderRead (reader);
+
+ while (ret == 1) {
+ xmlChar *tag;
+
+ tag = xmlTextReaderName (reader);
+
+ switch (xmlTextReaderNodeType (reader)) {
+ case 1:
+ if (xmlStrEqual (tag, BAD_CAST ("restriction"))) {
+ /* <restriction> */
+ process_restriction (reader, data);
+ }
+
+ break;
+
+ case 15:
+ if (xmlStrEqual (tag, BAD_CAST ("restrictions"))) {
+ /* </restrictions> */
+ xmlFree (tag);
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ xmlFree (tag);
+ ret = xmlTextReaderRead (reader);
+ }
+}
+
+static void
+process_dlna_profile (xmlTextReaderPtr reader,
+ GList **profiles,
+ GUPnPDLNALoadState *data)
+{
+ guint ret;
+ GUPnPDLNAProfile *profile = NULL;
+ GUPnPDLNAProfile *base = NULL;
+ GUPnPDLNARestrictions *restr = NULL;
+ GstCaps *temp_audio = NULL, *temp_video = NULL, *temp_container = NULL;
+ xmlChar *name, *mime, *id, *base_profile, *extended;
+ gboolean done = FALSE, is_extended = FALSE;
+
+ name = xmlTextReaderGetAttribute (reader, BAD_CAST ("name"));
+ mime = xmlTextReaderGetAttribute (reader, BAD_CAST ("mime"));
+ extended = xmlTextReaderGetAttribute (reader, BAD_CAST ("extended"));
+ id = xmlTextReaderGetAttribute (reader, BAD_CAST ("id"));
+ base_profile = xmlTextReaderGetAttribute (reader,
+ BAD_CAST ("base-profile"));
+
+ /* Create temporary place-holders for caps */
+ temp_container = gst_caps_new_empty ();
+ temp_video = gst_caps_new_empty ();
+ temp_audio = gst_caps_new_empty ();
+
+ if (!name) {
+ g_assert (mime == NULL);
+
+ /* We need a non-NULL string to not trigger asserts in the
+ * places these are used. Profiles without names are used
+ * only for inheritance, not for actual matching. */
+ name = xmlStrdup (BAD_CAST (""));
+ mime = xmlStrdup (BAD_CAST (""));
+ }
+
+ if (extended && xmlStrEqual (extended, BAD_CAST ("true"))) {
+ /* If we're not in extended mode, skip this profile */
+ if (!data->extended_mode)
+ goto out;
+
+ is_extended = TRUE;
+ }
+
+ ret = xmlTextReaderRead (reader);
+ while (ret == 1 && !done) {
+ xmlChar *tag;
+
+ tag = xmlTextReaderName (reader);
+
+ switch (xmlTextReaderNodeType (reader)) {
+ case 1:
+ if (xmlStrEqual (tag, BAD_CAST ("restriction")))
+ restr = process_restriction (reader, data);
+ else if (xmlStrEqual (tag, BAD_CAST ("parent")))
+ restr = process_parent (reader, data);
+
+ if (!restr)
+ break;
+
+ if (restr->type == GST_TYPE_ENCODING_CONTAINER_PROFILE)
+ gst_caps_merge (temp_container,
+ gst_caps_copy (restr->caps));
+ else if (restr->type == GST_TYPE_ENCODING_VIDEO_PROFILE)
+ gst_caps_merge (temp_video,
+ gst_caps_copy (restr->caps));
+ else if (restr->type == GST_TYPE_ENCODING_AUDIO_PROFILE)
+ gst_caps_merge (temp_audio,
+ gst_caps_copy (restr->caps));
+ else
+ g_assert_not_reached ();
+
+ break;
+
+ case 15:
+ if (xmlStrEqual (tag, BAD_CAST ("dlna-profile")))
+ done = TRUE;
+
+ default:
+ break;
+ }
+
+ xmlFree (tag);
+ ret = xmlTextReaderRead (reader);
+ }
+
+ if (base_profile) {
+ base = g_hash_table_lookup (data->profile_ids, base_profile);
+ if (!base)
+ g_warning ("Invalid base-profile reference");
+ }
+
+
+ /* create a new GUPnPDLNAProfile */
+ profile = gupnp_dlna_profile_new ((gchar *)name,
+ (gchar *)mime,
+ GST_CAPS_NONE,
+ GST_CAPS_NONE,
+ GST_CAPS_NONE,
+ is_extended);
+
+ /* Inherit from base profile, if it exists*/
+ if (base) {
+ const GstCaps *video_caps =
+ gupnp_dlna_profile_get_video_caps (base);
+ const GstCaps *audio_caps =
+ gupnp_dlna_profile_get_audio_caps (base);
+ const GstCaps *container_caps =
+ gupnp_dlna_profile_get_container_caps (base);
+
+ if (GST_IS_CAPS (video_caps))
+ gst_caps_merge (temp_video,
+ gst_caps_copy (video_caps));
+ if (GST_IS_CAPS (audio_caps))
+ gst_caps_merge (temp_audio,
+ gst_caps_copy (audio_caps));
+ if (GST_IS_CAPS (container_caps))
+ gst_caps_merge (temp_container,
+ gst_caps_copy (container_caps));
+
+ }
+
+
+ /* The merged caps will be our new GUPnPDLNAProfile */
+
+ if (GST_IS_CAPS (temp_container) && !gst_caps_is_empty (temp_container))
+ gupnp_dlna_profile_set_container_caps (profile, temp_container);
+ if (GST_IS_CAPS (temp_video) && !gst_caps_is_empty (temp_video))
+ gupnp_dlna_profile_set_video_caps (profile, temp_video);
+ if (GST_IS_CAPS (temp_audio) && !gst_caps_is_empty (temp_audio))
+ gupnp_dlna_profile_set_audio_caps (profile, temp_audio);
+
+ *profiles = g_list_append (*profiles, profile);
+
+ if (id) {
+ /* id is freed when the hash table is destroyed */
+ g_object_ref (profile);
+ g_hash_table_insert (data->profile_ids, id, profile);
+ }
+
+out:
+
+ if (temp_container)
+ gst_caps_unref (temp_container);
+ if (temp_audio)
+ gst_caps_unref (temp_audio);
+ if (temp_video)
+ gst_caps_unref (temp_video);
+
+ xmlFree (mime);
+ xmlFree (name);
+ if (extended)
+ xmlFree (extended);
+ if (base_profile)
+ xmlFree (base_profile);
+}
+
+static GList *
+process_include (xmlTextReaderPtr reader, GUPnPDLNALoadState *data)
+{
+ xmlChar *path;
+ GList *ret;
+
+ path = xmlTextReaderGetAttribute (reader, BAD_CAST ("ref"));
+
+ if (!g_path_is_absolute ((gchar *) path)) {
+ gchar *tmp = g_strconcat (DLNA_DATA_DIR,
+ G_DIR_SEPARATOR_S,
+ path,
+ NULL);
+ xmlFree (path);
+ path = BAD_CAST (tmp);
+ }
+
+ ret = gupnp_dlna_load_profiles_from_file ((gchar *) path,
+ data);
+ xmlFree (path);
+
+ return ret;
+}
+
+/* This can go away once we have a glib function to canonicalize paths (see
+ * https://bugzilla.gnome.org/show_bug.cgi?id=111848
+ *
+ * The implementationis not generic enough, but sufficient for our use. The
+ * idea is taken from Tristan Van Berkom's comment in the bug mentioned above:
+ *
+ * 1. cd dirname(path)
+ * 2. absdir = $CWD
+ * 3. cd $OLDPWD
+ * 4. abspath = absdir + basename(path)
+ */
+static gchar *
+canonicalize_path_name (const char *path)
+{
+ gchar *dir_name = NULL, *file_name = NULL, *abs_dir = NULL,
+ *old_dir = NULL, *ret = NULL;
+
+ if (g_path_is_absolute (path))
+ return g_strdup (path);
+
+ old_dir = g_get_current_dir ();
+ dir_name = g_path_get_dirname (path);
+
+ if (g_chdir (dir_name) < 0) {
+ ret = g_strdup (path);
+ goto out;
+ }
+
+ abs_dir = g_get_current_dir ();
+ g_chdir (old_dir);
+
+ file_name = g_path_get_basename (path);
+ ret = g_build_filename (abs_dir, file_name, NULL);
+
+out:
+ g_free (dir_name);
+ g_free (file_name);
+ g_free (abs_dir);
+ g_free (old_dir);
+
+ return ret;
+}
+
+GList *
+gupnp_dlna_load_profiles_from_file (const char *file_name,
+ GUPnPDLNALoadState *data)
+{
+ GList *profiles = NULL;
+ gchar *path = NULL;
+ xmlTextReaderPtr reader;
+ xmlRelaxNGParserCtxtPtr rngp;
+ xmlRelaxNGPtr rngs;
+ int ret;
+
+ path = canonicalize_path_name (file_name);
+ if (g_hash_table_lookup_extended (data->files_hash, path, NULL, NULL))
+ goto out;
+ else
+ g_hash_table_insert (data->files_hash, g_strdup (path), NULL);
+
+ reader = xmlNewTextReaderFilename (path);
+ if (!reader)
+ goto out;
+
+ /* Load the schema for validation */
+ rngp = xmlRelaxNGNewParserCtxt (DLNA_DATA_DIR "dlna-profiles.rng");
+ rngs = xmlRelaxNGParse (rngp);
+ xmlTextReaderRelaxNGSetSchema (reader, rngs);
+
+ ret = xmlTextReaderRead (reader);
+ while (ret == 1) {
+ xmlChar *tag;
+
+ tag = xmlTextReaderName (reader);
+
+ switch (xmlTextReaderNodeType (reader)) {
+ /* Start tag */
+ case 1:
+ if (xmlStrEqual (tag, BAD_CAST ("include"))) {
+ /* <include> */
+ GList *include =
+ process_include (reader,
+ data);
+ profiles = g_list_concat (profiles,
+ include);
+ } else if (xmlStrEqual (tag,
+ BAD_CAST ("restrictions"))) {
+ /* <restrictions> */
+ process_restrictions (reader,
+ data);
+ } else if (xmlStrEqual (tag,
+ BAD_CAST ("dlna-profile"))) {
+ /* <dlna-profile> */
+ process_dlna_profile (reader,
+ &profiles,
+ data);
+
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ xmlFree (tag);
+ ret = xmlTextReaderRead (reader);
+ }
+
+ xmlFreeTextReader (reader);
+ xmlRelaxNGFree (rngs);
+ xmlRelaxNGFreeParserCtxt (rngp);
+
+out:
+ g_free (path);
+
+ return profiles;
+}
+
+GList *
+gupnp_dlna_load_profiles_from_dir (gchar *profile_dir, GUPnPDLNALoadState *data)
+{
+ GDir *dir;
+
+ data->restrictions =
+ g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) xmlFree,
+ (GDestroyNotify)
+ free_restrictions_struct);
+ data->profile_ids =
+ g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) xmlFree,
+ (GDestroyNotify)
+ g_object_unref);
+
+ GList *profiles = NULL;
+
+ if ((dir = g_dir_open (profile_dir, 0, NULL))) {
+ const gchar *entry;
+
+ while ((entry = g_dir_read_name (dir))) {
+ gchar *path = g_strconcat (profile_dir,
+ G_DIR_SEPARATOR_S,
+ entry,
+ NULL);
+
+ if (g_str_has_suffix (entry, ".xml") &&
+ g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
+ profiles = g_list_concat (profiles,
+ gupnp_dlna_load_profiles_from_file (
+ path,
+ data));
+ }
+
+ g_free (path);
+ }
+
+ g_dir_close (dir);
+ }
+
+ g_hash_table_unref (data->restrictions);
+ g_hash_table_unref (data->profile_ids);
+
+ return profiles;
+}
+
+GList *
+gupnp_dlna_load_profiles_from_disk (gboolean relaxed_mode,
+ gboolean extended_mode)
+{
+ GUPnPDLNALoadState *load_data;
+ GList *ret, *i;
+
+ load_data = g_new0 (GUPnPDLNALoadState, 1);
+
+ load_data->files_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+ load_data->relaxed_mode = relaxed_mode;
+ load_data->extended_mode = extended_mode;
+
+ ret = gupnp_dlna_load_profiles_from_dir (DLNA_DATA_DIR,
+ load_data);
+
+ /* Now that we're done loading profiles, remove all profiles with no
+ * name which are only used for inheritance and not matching. */
+ i = ret;
+ while (i) {
+ const gchar *name;
+ GUPnPDLNAProfile *profile = i->data;
+ GstEncodingProfile *enc_profile =
+ gupnp_dlna_profile_get_encoding_profile
+ (profile);
+ GList *tmp = g_list_next (i);
+
+ name = gst_encoding_profile_get_name (enc_profile);
+ if (name[0] == '\0') {
+ ret = g_list_delete_link (ret, i);
+ g_object_unref (profile);
+ }
+
+ i = tmp;
+ }
+
+ g_hash_table_unref (load_data->files_hash);
+ g_free (load_data);
+ load_data = NULL;
+
+ return ret;
+}
diff --git a/libgupnp-dlna/profile-loading.h b/libgupnp-dlna/profile-loading.h
new file mode 100644
index 0000000..fa1f966
--- /dev/null
+++ b/libgupnp-dlna/profile-loading.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Authors: Zeeshan Ali <zeeshanak@gnome.org>
+ * <zeeshan.ali@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+#ifndef __GUPNP_DLNA_LOAD_H__
+#define __GUPNP_DLNA_LOAD_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+ GHashTable *restrictions;
+ GHashTable *profile_ids;
+ GHashTable *files_hash;
+ gboolean relaxed_mode;
+ gboolean extended_mode;
+} GUPnPDLNALoadState;
+
+typedef struct {
+ GstCaps *caps;
+ GType type;
+} GUPnPDLNARestrictions;
+
+GList *
+gupnp_dlna_load_profiles_from_file (const gchar *file_name,
+ GUPnPDLNALoadState *data);
+GList *
+gupnp_dlna_load_profiles_from_dir (gchar *profile_dir,
+ GUPnPDLNALoadState *data);
+
+GList *
+gupnp_dlna_load_profiles_from_disk (gboolean relaxed_mode,
+ gboolean extended_mode);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_LOAD_H__ */