Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 4 Feb 2011 11:50:34 +0100
From:      =?UTF-8?Q?Jan_=C5=A0olc?= <solc@thinline.cz>
To:        <mi@aldan.algebra.com>
Cc:        ports@FreeBSD.org
Subject:   FreeBSD Port: minidlna-2010.12.12
Message-ID:  <8BD2DD27A14C43D39338545577C89A74@HonzaSolcPC>

next in thread | raw e-mail | index | archive | help
Toto je zpráva ve formátu MIME s několika částmi.

------=_NextPart_000_0052_01CBC461.BB9AB060
Content-Type: text/plain;
	charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi,

With help from the maker of miniupnpd I have done patches for minidlna.

patch-ssdpd =E2=80=93 minidlna can use minissdpd when you need using =
more upnp services at once (in example miniupnpd and minidlna =
simultaneously).
patch-zsamsung =E2=80=93 it=E2=80=99s latest patch for better =
cooperation with samsung televisions

You can use it as you wish. I=E2=80=99d like to find it in official repo =
in future (samsung patch could be optional in configure window) ;-)


With best regards
Honza SOLC

------=_NextPart_000_0052_01CBC461.BB9AB060
Content-Type: application/octet-stream;
	name="patch-ssdpd"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="patch-ssdpd"

diff -u -r -N minidlna_1.0.18/codelength.h =
minidlna_minissdpd/codelength.h=0A=
--- codelength.h	1970-01-01 01:00:00.000000000 +0100=0A=
+++ codelength.h	2011-02-02 15:35:05.000000000 +0100=0A=
@@ -0,0 +1,24 @@=0A=
+/* $Id: codelength.h,v 1.1 2008/10/06 22:04:06 nanard Exp $ */=0A=
+/* Project : miniupnp=0A=
+ * Author : Thomas BERNARD=0A=
+ * copyright (c) 2005-2008 Thomas Bernard=0A=
+ * This software is subjet to the conditions detailed in the=0A=
+ * provided LICENCE file. */=0A=
+#ifndef __CODELENGTH_H__=0A=
+#define __CODELENGTH_H__=0A=
+=0A=
+/* Encode length by using 7bit per Byte :=0A=
+ * Most significant bit of each byte specifies that the=0A=
+ * following byte is part of the code */=0A=
+#define DECODELENGTH(n, p) n =3D 0; \=0A=
+                           do { n =3D (n << 7) | (*p & 0x7f); } \=0A=
+                           while(*(p++)&0x80);=0A=
+=0A=
+#define CODELENGTH(n, p) if(n>=3D268435456) *(p++) =3D (n >> 28) | =
0x80; \=0A=
+                         if(n>=3D2097152) *(p++) =3D (n >> 21) | 0x80; \=0A=
+                         if(n>=3D16384) *(p++) =3D (n >> 14) | 0x80; \=0A=
+                         if(n>=3D128) *(p++) =3D (n >> 7) | 0x80; \=0A=
+                         *(p++) =3D n & 0x7f;=0A=
+=0A=
+#endif=0A=
+=0A=
diff -u -r -N minidlna_1.0.18/minidlna.c minidlna_minissdpd/minidlna.c=0A=
--- minidlna.c	2010-07-21 01:26:36.000000000 +0200=0A=
+++ minidlna.c	2011-02-02 15:59:07.000000000 +0100=0A=
@@ -422,6 +422,9 @@=0A=
 				if( (strcmp(ary_options[i].value, "yes") =3D=3D 0) || =
atoi(ary_options[i].value) )=0A=
 					SETFLAG(DLNA_STRICT_MASK);=0A=
 				break;=0A=
+			case UPNPMINISSDPDSOCKET:=0A=
+				minissdpdsocketpath =3D ary_options[i].value;=0A=
+				break;=0A=
 			default:=0A=
 				fprintf(stderr, "Unknown option in file %s\n",=0A=
 				        optionsfile);=0A=
@@ -797,7 +800,11 @@=0A=
 	sudp =3D OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);=0A=
 	if(sudp < 0)=0A=
 	{=0A=
-		DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for receiving =
SSDP. EXITING\n");=0A=
+		DPRINTF(E_INFO, L_GENERAL, "Failed to open socket for receiving SSDP. =
Trying to use MiniSSDPd\n");=0A=
+		if(SubmitServicesToMiniSSDPD(lan_addr[0].str, runtime_vars.port) < 0) =
{=0A=
+			DPRINTF(E_FATAL, L_GENERAL, "Failed to connect to MiniSSDPd. =
EXITING");=0A=
+			return 1;=0A=
+		}=0A=
 	}=0A=
 	/* open socket for HTTP connections. Listen on the 1st LAN address */=0A=
 	shttpl =3D OpenAndConfHTTPSocket(runtime_vars.port);=0A=
diff -u -r -N minidlna_1.0.18/minissdp.c minidlna_minissdpd/minissdp.c=0A=
--- minissdp.c	2010-07-16 23:27:11.000000000 +0200=0A=
+++ minissdp.c	2011-02-02 15:57:12.000000000 +0100=0A=
@@ -10,6 +10,7 @@=0A=
 #include <string.h>=0A=
 #include <unistd.h>=0A=
 #include <sys/socket.h>=0A=
+#include <sys/un.h>=0A=
 #include <netinet/in.h>=0A=
 #include <arpa/inet.h>=0A=
 #include <errno.h>=0A=
@@ -20,14 +21,18 @@=0A=
 #include "upnphttp.h"=0A=
 #include "upnpglobalvars.h"=0A=
 #include "minissdp.h"=0A=
+#include "codelength.h"=0A=
 #include "log.h"=0A=
 =0A=
 /* SSDP ip/port */=0A=
 #define SSDP_PORT (1900)=0A=
 #define SSDP_MCAST_ADDR ("239.255.255.250")=0A=
 =0A=
+/* Prototypes */=0A=
+void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, =
int n, unsigned short port) ;=0A=
+=0A=
 static int=0A=
-AddMulticastMembership(int s, in_addr_t ifaddr/*const char * ifaddr*/)=0A=
+AddMulticastMembership(int s, in_addr_t ifaddr)=0A=
 {=0A=
 	struct ip_mreq imr;	/* Ip multicast membership */=0A=
 =0A=
@@ -45,6 +50,8 @@=0A=
 	return 0;=0A=
 }=0A=
 =0A=
+/* Open and configure the socket listening for =0A=
+ * SSDP udp packets sent on 239.255.255.250 port 1900 */=0A=
 int=0A=
 OpenAndConfSSDPReceiveSocket()=0A=
 {=0A=
@@ -207,9 +214,9 @@=0A=
 {=0A=
 	int l, n;=0A=
 	char buf[512];=0A=
-	/* TODO :=0A=
+	/*=0A=
 	 * follow guideline from document "UPnP Device Architecture 1.0"=0A=
-	 * put in uppercase.=0A=
+	 * uppercase is recommended.=0A=
 	 * DATE: is recommended=0A=
 	 * SERVER: OS/ver UPnP/1.0 minidlna/1.0=0A=
 	 * - check what to put in the 'Cache-Control' header =0A=
@@ -314,17 +321,12 @@=0A=
  * process SSDP M-SEARCH requests and responds to them */=0A=
 void=0A=
 ProcessSSDPRequest(int s, unsigned short port)=0A=
-/*ProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int =
n_lan_addr,=0A=
-                   unsigned short port)*/=0A=
 {=0A=
 	int n;=0A=
 	char bufr[1500];=0A=
 	socklen_t len_r;=0A=
 	struct sockaddr_in sendername;=0A=
-	int i, l;=0A=
-	int lan_addr_index =3D 0;=0A=
-	char * st =3D NULL, * mx =3D NULL, * man =3D NULL, * mx_end =3D NULL;=0A=
-	int st_len =3D 0, mx_len =3D 0, man_len =3D 0, mx_val =3D 0;=0A=
+=0A=
 	len_r =3D sizeof(struct sockaddr_in);=0A=
 =0A=
 	n =3D recvfrom(s, bufr, sizeof(bufr), 0,=0A=
@@ -334,6 +336,15 @@=0A=
 		DPRINTF(E_ERROR, L_SSDP, "recvfrom(udp): %s\n", strerror(errno));=0A=
 		return;=0A=
 	}=0A=
+	ProcessSSDPData(s, bufr, sendername, n, port);=0A=
+=0A=
+}=0A=
+=0A=
+void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, =
int n, unsigned short port) {=0A=
+	int i, l;=0A=
+	int lan_addr_index =3D 0;=0A=
+	char * st =3D NULL, * mx =3D NULL, * man =3D NULL, * mx_end =3D NULL;=0A=
+	int st_len =3D 0, mx_len =3D 0, man_len =3D 0, mx_val =3D 0;=0A=
 =0A=
 	if(memcmp(bufr, "NOTIFY", 6) =3D=3D 0)=0A=
 	{=0A=
@@ -433,6 +444,7 @@=0A=
 			/* strlen("ssdp:all") =3D=3D 8 */=0A=
 			if(st_len=3D=3D8 && (0 =3D=3D memcmp(st, "ssdp:all", 8)))=0A=
 			{=0A=
+				DPRINTF(E_INFO, L_SSDP, "ssdp:all found");=0A=
 				for(i=3D0; known_service_types[i]; i++)=0A=
 				{=0A=
 					l =3D (int)strlen(known_service_types[i]);=0A=
@@ -496,3 +508,62 @@=0A=
 	}=0A=
 	return 0;=0A=
 }=0A=
+=0A=
+/* SubmitServicesToMiniSSDPD() :=0A=
+ * register services offered by MiniUPnPd to a running instance of=0A=
+ * MiniSSDPd */=0A=
+int=0A=
+SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {=0A=
+	struct sockaddr_un addr;=0A=
+	int s;=0A=
+	unsigned char buffer[2048];=0A=
+	char strbuf[256];=0A=
+	unsigned char * p;=0A=
+	int i, l;=0A=
+=0A=
+	s =3D socket(AF_UNIX, SOCK_STREAM, 0);=0A=
+	if(s < 0) {=0A=
+		DPRINTF(E_ERROR, L_SSDP, "socket(unix): %s", strerror(errno));=0A=
+		return -1;=0A=
+	}=0A=
+	addr.sun_family =3D AF_UNIX;=0A=
+	strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));=0A=
+	if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < =
0) {=0A=
+		DPRINTF(E_ERROR, L_SSDP, "connect(\"%s\"): %s",=0A=
+		        minissdpdsocketpath, strerror(errno));=0A=
+		return -1;=0A=
+	}=0A=
+	for(i =3D 0; known_service_types[i]; i++) {=0A=
+		buffer[0] =3D 4;=0A=
+		p =3D buffer + 1;=0A=
+		l =3D (int)strlen(known_service_types[i]);=0A=
+		if(i > 0)=0A=
+			l++;=0A=
+		CODELENGTH(l, p);=0A=
+		memcpy(p, known_service_types[i], l);=0A=
+		if(i > 0)=0A=
+			p[l-1] =3D '1';=0A=
+		p +=3D l;=0A=
+		l =3D snprintf(strbuf, sizeof(strbuf), "%s::%s%s", =0A=
+		             uuidvalue, known_service_types[i], (i=3D=3D0)?"":"1");=0A=
+		CODELENGTH(l, p);=0A=
+		memcpy(p, strbuf, l);=0A=
+		p +=3D l;=0A=
+		l =3D (int)strlen(MINIDLNA_SERVER_STRING);=0A=
+		CODELENGTH(l, p);=0A=
+		memcpy(p, MINIDLNA_SERVER_STRING, l);=0A=
+		p +=3D l;=0A=
+		l =3D snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH,=0A=
+		             host, (unsigned int)port);=0A=
+		CODELENGTH(l, p);=0A=
+		memcpy(p, strbuf, l);=0A=
+		p +=3D l;=0A=
+		if(write(s, buffer, p - buffer) < 0) {=0A=
+			DPRINTF(E_ERROR, L_SSDP, "write(): %s", strerror(errno));=0A=
+			return -1;=0A=
+		}=0A=
+	}=0A=
+ 	close(s);=0A=
+	return 0;=0A=
+}=0A=
+=0A=
diff -u -r -N minidlna_1.0.18/minissdp.h minidlna_minissdpd/minissdp.h=0A=
--- minissdp.h	2010-07-16 23:25:55.000000000 +0200=0A=
+++ minissdp.h	2011-02-02 15:22:14.000000000 +0100=0A=
@@ -39,5 +39,8 @@=0A=
 int=0A=
 SendSSDPGoodbye(int * sockets, int n);=0A=
 =0A=
+int=0A=
+SubmitServicesToMiniSSDPD(const char * host, unsigned short port);=0A=
+=0A=
 #endif=0A=
 =0A=
diff -u -r -N minidlna_1.0.18/options.c minidlna_minissdpd/options.c=0A=
--- options.c	2010-07-16 23:25:55.000000000 +0200=0A=
+++ options.c	2011-02-02 15:59:52.000000000 +0100=0A=
@@ -35,7 +35,8 @@=0A=
 	{ UPNPINOTIFY, "inotify" },=0A=
 	{ UPNPDBDIR, "db_dir" },=0A=
 	{ ENABLE_TIVO, "enable_tivo" },=0A=
-	{ ENABLE_DLNA_STRICT, "strict_dlna" }=0A=
+	{ ENABLE_DLNA_STRICT, "strict_dlna" },=0A=
+	{ UPNPMINISSDPDSOCKET, "minissdpdsocket"}=0A=
 };=0A=
 =0A=
 int=0A=
diff -u -r -N minidlna_1.0.18/options.h minidlna_minissdpd/options.h=0A=
--- options.h	2010-07-16 23:25:55.000000000 +0200=0A=
+++ options.h	2011-02-02 16:09:06.000000000 +0100=0A=
@@ -28,7 +28,8 @@=0A=
 	UPNPINOTIFY,			/* enable inotify on the media directories */=0A=
 	UPNPDBDIR,			/* base directory to store the database, log files, and =
album art cache */=0A=
 	ENABLE_TIVO,			/* enable support for streaming images and music to =
TiVo */=0A=
-	ENABLE_DLNA_STRICT		/* strictly adhere to DLNA specs */=0A=
+	ENABLE_DLNA_STRICT,		/* strictly adhere to DLNA specs */=0A=
+	UPNPMINISSDPDSOCKET		/* minissdpdsocket */=0A=
 };=0A=
 =0A=
 /* readoptionsfile()=0A=
diff -u -r -N minidlna_1.0.18/upnpglobalvars.c =
minidlna_minissdpd/upnpglobalvars.c=0A=
--- upnpglobalvars.c	2010-07-16 23:25:56.000000000 +0200=0A=
+++ upnpglobalvars.c	2011-02-02 15:55:11.000000000 +0100=0A=
@@ -40,6 +40,9 @@=0A=
 int n_lan_addr =3D 0;=0A=
 struct lan_addr_s lan_addr[MAX_LAN_ADDR];=0A=
 =0A=
+/* Path of the Unix socket used to communicate with MiniSSDPd */=0A=
+const char * minissdpdsocketpath =3D "/var/run/minissdpd.sock";=0A=
+=0A=
 /* UPnP-A/V [DLNA] */=0A=
 sqlite3 * db;=0A=
 char dlna_no_conv[] =3D "DLNA.ORG_OP=3D01;DLNA.ORG_CI=3D0";=0A=
diff -u -r -N minidlna_1.0.18/upnpglobalvars.h =
minidlna_minissdpd/upnpglobalvars.h=0A=
--- upnpglobalvars.h	2010-07-21 01:26:36.000000000 +0200=0A=
+++ upnpglobalvars.h	2011-02-02 15:54:41.000000000 +0100=0A=
@@ -117,6 +117,8 @@=0A=
 extern int n_lan_addr;=0A=
 extern struct lan_addr_s lan_addr[];=0A=
 =0A=
+extern const char * minissdpdsocketpath;=0A=
+=0A=
 /* UPnP-A/V [DLNA] */=0A=
 extern sqlite3 *db;=0A=
 extern char dlna_no_conv[];=0A=

------=_NextPart_000_0052_01CBC461.BB9AB060
Content-Type: application/octet-stream;
	name="patch-zsamsung"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="patch-zsamsung"

diff -urNp minidlna-cvs/albumart.c albumart.c=0A=
--- albumart.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ albumart.c	2010-12-19 19:37:20.000000000 +0100=0A=
@@ -27,6 +27,10 @@=0A=
 =0A=
 #include <jpeglib.h>=0A=
 =0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+# include <libffmpegthumbnailer/videothumbnailerc.h>=0A=
+#endif=0A=
+=0A=
 #include "upnpglobalvars.h"=0A=
 #include "albumart.h"=0A=
 #include "sql.h"=0A=
@@ -280,7 +284,8 @@ check_for_album_file(char * dir, const c=0A=
 	char * art_file;=0A=
 =0A=
 	/* First look for file-specific cover art */=0A=
-	sprintf(file, "%s.cover.jpg", path);=0A=
+	//sprintf(file, "%s.cover.jpg", path);=0A=
+	sprintf(file, "%s.jpg", path);=0A=
 	if( access(file, R_OK) =3D=3D 0 )=0A=
 	{=0A=
 		if( art_cache_exists(file, &art_file) )=0A=
@@ -336,6 +341,36 @@ found_file:=0A=
 	return NULL;=0A=
 }=0A=
 =0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+=0A=
+/*=0A=
+ * generates jpegs for movies as thumbnail files. The new thumbs have =
the name of the movie, with an ".jpg" =0A=
+ * appended. The thumbs are created with the minidlna-user (e.g. root).=0A=
+ */=0A=
+char *=0A=
+generate_albumart(char * dir, const char * path)=0A=
+{=0A=
+    int rc;=0A=
+    char * thumbfile =3D malloc(PATH_MAX);=0A=
+    =0A=
+    /* DPRINTF(E_DEBUG, L_METADATA, "generate_albumart - dir: %s, path: =
%s\n", dir, path); */=0A=
+=0A=
+    if (ends_with(path, ".avi") || ends_with(path, ".mkv") || =
ends_with(path, ".mpg")) {=0A=
+        video_thumbnailer* vt =3D video_thumbnailer_create();=0A=
+        vt->thumbnail_image_type =3D Jpeg;=0A=
+        /* DPRINTF(E_DEBUG, L_METADATA, "generate_albumart - movie\n"); =
*/=0A=
+        sprintf(thumbfile, "%s.jpg", path);=0A=
+=0A=
+        rc =3D video_thumbnailer_generate_thumbnail_to_file(vt, path, =
thumbfile);=0A=
+        DPRINTF(E_DEBUG, L_METADATA, "rc: %d\n", rc);=0A=
+        video_thumbnailer_destroy(vt);=0A=
+        return thumbfile;=0A=
+    }=0A=
+    return 0;=0A=
+}=0A=
+=0A=
+#endif=0A=
+=0A=
 sqlite_int64=0A=
 find_album_art(const char * path, const char * image_data, int =
image_size)=0A=
 {=0A=
@@ -346,8 +381,14 @@ find_album_art(const char * path, const =0A=
 	sqlite_int64 ret =3D 0;=0A=
 	char * mypath =3D strdup(path);=0A=
 =0A=
-	if( (image_size && (album_art =3D check_embedded_art(path, image_data, =
image_size))) ||=0A=
-	    (album_art =3D check_for_album_file(dirname(mypath), path)) )=0A=
+=0A=
+    album_art =3D check_embedded_art(path, image_data, image_size);=0A=
+    if (!album_art) album_art =3D check_for_album_file(dirname(mypath), =
path);=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+    if (!album_art) album_art =3D generate_albumart(dirname(mypath), =
path);=0A=
+#endif=0A=
+=0A=
+    if (album_art) =0A=
 	{=0A=
 		sql =3D sqlite3_mprintf("SELECT ID from ALBUM_ART where PATH =3D =
'%q'", album_art ? album_art : path);=0A=
 		if( (sql_get_table(db, sql, &result, &rows, &cols) =3D=3D SQLITE_OK) =
&& rows )=0A=
diff -urNp icons.c icons.c=0A=
--- icons.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ icons.c	2010-12-19 20:30:47.000000000 +0100=0A=
@@ -1301,3 +1301,145 @@ jpeg_lrg[] =3D "\xff\xd8\xff\xe0\x00\x10\x=0A=
              =
"\x1e\x88\x20\xa8\xd8\xba\xe2\x7e\xdc\x26\x9a\x69\x08\xf7\x22\x22\x02\x82=
\x28\x82\x29\xe8\x88\x9e"=0A=
              "\xda\x69\xa6\x90\x8f\xff\xd9";=0A=
 #endif=0A=
+=0A=
+/* Chapter JPEG image */=0A=
+unsigned char=0A=
+jpeg_chapter[] =3D=0A=
+    "\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01\x01\x01\x00\x48"=0A=
+    "\x00\x48\x00\x00\xFF\xFE\x00\x13\x43\x72\x65\x61\x74\x65\x64\x20"=0A=
+    "\x77\x69\x74\x68\x20\x47\x49\x4D\x50\xFF\xDB\x00\x43\x00\x05\x03"=0A=
+    "\x04\x04\x04\x03\x05\x04\x04\x04\x05\x05\x05\x06\x07\x0C\x08\x07"=0A=
+    "\x07\x07\x07\x0F\x0B\x0B\x09\x0C\x11\x0F\x12\x12\x11\x0F\x11\x11"=0A=
+    "\x13\x16\x1C\x17\x13\x14\x1A\x15\x11\x11\x18\x21\x18\x1A\x1D\x1D"=0A=
+    "\x1F\x1F\x1F\x13\x17\x22\x24\x22\x1E\x24\x1C\x1E\x1F\x1E\xFF\xDB"=0A=
+    "\x00\x43\x01\x05\x05\x05\x07\x06\x07\x0E\x08\x08\x0E\x1E\x14\x11"=0A=
+    "\x14\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E"=0A=
+    "\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E"=0A=
+    "\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E"=0A=
+    "\x1E\x1E\x1E\xFF\xC0\x00\x11\x08\x00\x50\x00\x80\x03\x01\x22\x00"=0A=
+    "\x02\x11\x01\x03\x11\x01\xFF\xC4\x00\x1C\x00\x00\x01\x04\x03\x01"=0A=
+    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x07\x08\x09"=0A=
+    "\x02\x05\x06\x03\xFF\xC4\x00\x3D\x10\x00\x01\x03\x03\x02\x04\x02"=0A=
+    "\x06\x08\x02\x0B\x00\x00\x00\x00\x00\x01\x02\x03\x06\x00\x04\x05"=0A=
+    "\x07\x11\x12\x21\x31\xD2\x84\x85\x13\x22\xA4\xB2\xB4\xD1\x08\x14"=0A=
+    "\x41\x64\x65\x66\x83\xD3\x15\x74\x26\x27\x42\x46\x51\x61\x71\x76"=0A=
+    "\x94\xA5\xB3\xFF\xC4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00"=0A=
+    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xC4\x00\x14\x11\x01\x00"=0A=
+    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"=0A=
+    "\xDA\x00\x0C\x03\x01\x00\x02\x11\x03\x11\x00\x3F\x00\x92\xB9\x99"=0A=
+    "\x06\x4D\x9C\x8D\xC3\x4C\xDC\x06\xD0\xDB\x8A\x42\x52\x1B\x49\xE4"=0A=
+    "\x0E\xDF\x68\x35\xAB\x7A\x53\x9B\x4F\x4B\xDD\xBF\x49\x1F\x2A\xF0"=0A=
+    "\x90\x2F\x6C\xBD\xE8\xFB\xC3\x9E\xF1\xA7\x10\xE2\x71\x47\xAE\x32"=0A=
+    "\xC8\xFE\x82\x7E\x54\x0D\xB3\xB2\xF9\x02\x7A\x64\x36\xFD\x16\xFB"=0A=
+    "\x69\x23\xB3\x69\x22\x7A\x64\xB6\xFD\x06\xFB\x69\xD2\x38\x5C\x39"=0A=
+    "\xEB\x89\xB0\x3E\x1D\x1F\x2A\xC4\xE0\xB0\x87\xAE\x1B\x1C\x7C\x32"=0A=
+    "\x3E\x54\x0D\x1B\xD3\xC9\x4A\x7A\x65\x3D\x9D\xAE\xDA\x48\xEE\xA1"=0A=
+    "\x4B\x53\xD3\x2D\xEC\xCD\x76\xD3\xCC\x63\xF8\x03\xD7\x07\x8C\x3E"=0A=
+    "\x11\x1F\x2A\xC4\xC6\xE3\xA7\xAE\x07\x14\x7C\x1B\x7F\x2A\x06\x3D"=0A=
+    "\xDD\x48\x99\x27\xA6\x63\xD9\x99\xED\xA4\x6E\xEA\x74\xD9\x3D\x33"=0A=
+    "\x5B\x78\x56\x7B\x29\xFA\x31\x88\xD1\xEB\x1E\xC4\x1F\x04\xDF\xCA"=0A=
+    "\xB1\x31\x58\xB9\xEB\x1B\xC3\x9F\x02\xDF\x6D\x04\x7C\x77\x55\x67"=0A=
+    "\x49\xE9\x9D\xDB\xC2\x31\xD9\x48\xDE\xD5\xB9\xFA\x7A\x67\xF6\xF0"=0A=
+    "\x6C\x76\x54\x8D\x31\x18\xA1\xEB\x18\xC2\x9F\x00\xD7\x6D\x62\x61"=0A=
+    "\xD1\x13\xD6\x2B\x83\x3E\x5E\xD7\x6D\x04\x69\x7B\x58\x75\x0D\x3D"=0A=
+    "\x24\x3E\xC4\xC7\x65\x23\x7B\x59\xF5\x21\x3D\x24\x7E\xC5\x6F\xFB"=0A=
+    "\x75\x28\x0C\x2A\x1A\x7A\xC4\xB0\x27\xCB\x9A\xED\xAC\x4C\x1E\x14"=0A=
+    "\x7A\xC4\x23\xE7\xCB\x59\xED\xA0\x8A\xCF\x6B\x6E\xA6\x27\xA4\x97"=0A=
+    "\xD8\x6D\xFF\x00\x6E\x91\xBB\xAE\x7A\xA2\x9E\x92\x8F\x60\xB6\xFD"=0A=
+    "\xBA\x96\x66\x09\x07\x3D\x61\xB1\xD3\xE5\x8C\xF6\xD6\x26\x01\x04"=0A=
+    "\x3D\x61\x51\xB3\xE5\x6C\x76\xD0\x44\x27\xB5\xEB\x55\x53\xD2\x55"=0A=
+    "\xFF\x00\x5F\x6D\xFB\x75\xB8\xD3\x5D\x74\xD4\xBB\xFD\x46\x8E\xE3"=0A=
+    "\x32\x79\xE6\xAF\xAC\xAF\xB2\x4C\x5A\x3E\xC3\x96\x2C\x24\x29\x0E"=0A=
+    "\xAC\x20\x9D\xD0\x84\xA8\x11\xC5\xB8\xE7\xD4\x0D\xF7\x1B\x83\x28"=0A=
+    "\xCE\x9E\xC0\x4F\x58\x3C\x64\xF9\x53\x1D\xB5\x02\xF4\x9D\x7B\xEA"=0A=
+    "\xD4\x3C\x7E\x3D\x65\xFF\x00\xBA\x28\x26\x0C\x8D\x7B\x66\xAF\xBF"=0A=
+    "\x98\x73\xDE\x34\xEC\xD3\x3B\x25\x5E\xD9\xCC\x80\xFB\xCB\x9E\xF1"=0A=
+    "\xA7\x8A\x80\xA2\x8A\x28\x0A\x28\xA4\x57\x79\x6C\x55\x9E\x52\xC7"=0A=
+    "\x17\x77\x93\xB2\xB7\xBF\xC8\x7A\x4F\xA9\x5A\xBA\xFA\x52\xED\xCF"=0A=
+    "\xA3\x4F\x13\x9E\x8D\x04\xEE\xBE\x14\x90\x4E\xC0\xEC\x39\x9A\x05"=0A=
+    "\xB4\x51\x45\x01\x45\x14\x50\x14\x51\x45\x01\x45\x14\x50\x15\x5B"=0A=
+    "\xBA\x48\xBD\xF5\x72\x1C\x3F\x1E\xB1\xF8\x84\x55\x91\x55\x6A\xE9"=0A=
+    "\x12\xF7\xD5\xF8\x60\xFC\x7E\xC7\xE2\x11\x41\x30\x25\x0B\xDB\x3F"=0A=
+    "\x91\x1F\x7A\x77\xDF\x34\xF5\x53\x1B\x2A\x5F\xF4\x8B\x25\xFC\xDB"=0A=
+    "\xBE\xF9\xA7\xCA\x80\xAE\x03\xE9\x13\x2F\xBF\x82\x68\xB4\x96\x53"=0A=
+    "\x8A\x09\xFA\xFD\x9D\xB2\x51\x6C\xA2\x9E\x20\x87\x1D\x71\x0D\x25"=0A=
+    "\x7B\x1E\x47\x84\xAF\x8B\x63\xCB\x95\x77\xF5\xA5\x9D\x46\x71\x73"=0A=
+    "\x28\x86\x52\x2F\x99\x42\x97\x61\x92\xB7\x53\x0E\xF0\x1D\x94\x9D"=0A=
+    "\xFA\x29\x27\xEC\x52\x48\x04\x7F\x98\x14\x0D\x46\x1F\xE8\xD1\x00"=0A=
+    "\xB8\xC6\xB1\x79\x2C\x73\x35\x21\x92\xB8\xD8\x5D\xD6\x65\xFC\xBD"=0A=
+    "\xC2\x5E\x53\xA4\x6E\xA5\x23\x85\x61\x20\x6F\xBE\xC0\x83\xCB\x6E"=0A=
+    "\x66\xB4\xFA\xDA\xC6\x66\x39\xAB\xFA\x19\x61\x16\xB7\x56\x6B\x27"=0A=
+    "\x65\x6D\x98\xB3\xB3\xFE\x25\x74\x77\x74\x8B\x26\x9B\x0E\xBE\xE6"=0A=
+    "\xDB\x9D\x86\xEB\x59\x03\x73\xB1\xDB\x99\xAD\xCE\x26\x35\xF4\x8F"=0A=
+    "\x8F\x58\x33\x1F\xC5\x4B\xE0\x59\x6C\x5D\xB2\x03\x36\xF9\x1C\xAD"=0A=
+    "\x9D\xCA\x6F\x83\x60\x6C\x9E\x24\xB6\x78\x14\xA0\x36\xE6\x49\xDF"=0A=
+    "\xED\x26\xBA\x4C\xDC\x0E\x4B\x93\xD4\x7D\x2B\x94\xDD\xE5\x71\xF7"=0A=
+    "\x86\x27\x6D\x7E\x8C\xC3\xCA\x4A\x99\x72\xED\xDB\x8B\x54\x34\x1C"=0A=
+    "\x69\xB4\xA4\xA4\x02\xB4\xA9\x45\x25\x43\x60\x79\x6F\x41\xAD\xD3"=0A=
+    "\x6D\x46\x9A\xE5\x19\xD4\x08\xFC\xA7\x0B\x83\x6E\x61\x0F\x4A\x14"=0A=
+    "\x51\x63\x72\xA6\xEC\x6E\x83\xCC\x29\xD6\x3D\x77\x77\x28\x07\x87"=0A=
+    "\x9A\x95\xD0\x1D\xF6\x1C\xC5\x68\xF4\xCB\x59\xA4\x77\xFA\xAD\x8F"=0A=
+    "\x83\x4B\x2E\xF4\xFF\x00\x28\x73\x16\xEF\xBB\x63\x73\x13\xCA\x2A"=0A=
+    "\xE8\x5B\xB8\xCA\x78\xD4\xD3\xE9\x52\x89\x04\xA0\x28\x83\xB0\x04"=0A=
+    "\xA7\x96\xFC\xF6\x51\x35\xD1\x8C\xF4\x92\xFF\x00\x58\xD4\x33\x36"=0A=
+    "\x56\x2C\x4E\x18\xC5\x23\x1C\xE3\x6A\x5A\x9C\x69\x56\x8D\x6C\xB0"=0A=
+    "\xF0\xE1\x00\x25\x6A\x00\x7A\xA5\x5E\xA9\x3B\xFF\x00\x85\x69\xB4"=0A=
+    "\xFB\x44\x25\xF8\x8D\x51\x84\xCC\xF2\x96\xDA\x77\x8B\x6F\x06\x2F"=0A=
+    "\x5B\xBC\xB5\x8E\x63\xD7\x6B\xE9\x52\xE5\xB1\x69\xB5\xF1\x14\x71"=0A=
+    "\x3C\xBE\x25\x12\xAE\x32\x90\x90\x3D\x5D\xCA\x8D\x06\xE7\x2B\xA8"=0A=
+    "\x7A\xB5\x96\xD5\xE9\xC4\x0A\x09\x81\x8A\x3C\x98\xF0\xB0\x71\xAB"=0A=
+    "\xEC\xAA\xDF\x42\x10\x97\xAD\xC3\x8A\x43\x81\x0A\x25\x6B\x52\x8F"=0A=
+    "\xA9\xC2\x12\x00\x42\xB8\xB7\xE5\x4D\xB6\xAC\xCF\x26\x7A\x81\x0E"=0A=
+    "\xD3\x6B\xFC\x7E\x2F\x09\x8A\xCC\xE3\x75\x1D\x9C\x56\x46\xCE\xF5"=0A=
+    "\x6E\xAD\x0C\xE6\x19\x24\x30\x01\x47\x5B\x7D\x8B\x85\x7F\xDA\x1B"=0A=
+    "\xA0\x24\x9D\x89\x3D\x1D\x95\x8E\xA2\xBF\xF4\x99\xD6\x2B\xCD\x39"=0A=
+    "\xCB\x60\x6D\x6F\x59\x18\x56\xDF\xB5\xCD\x32\xE2\xAD\x9E\x4A\xEC"=0A=
+    "\xB9\x2F\x89\xBF\x59\x2B\x41\x41\xDB\x91\x07\x8D\x5B\xFD\x95\xBA"=0A=
+    "\xB9\xD0\xB9\x1B\x1A\x55\x8D\xC6\xE3\xE4\x78\xF7\xE6\x96\x92\xC4"=0A=
+    "\x4B\xDE\xBE\xBB\x69\x42\xD6\xE7\x20\x09\xDC\x28\x27\xD6\x08\xD8"=0A=
+    "\x81\xB8\x1B\x9E\x1E\x83\x7E\x41\x9C\xF7\x57\xA6\x90\xD5\x47\xE1"=0A=
+    "\x79\x55\xE9\xFD\xBC\xEB\x21\x6A\xED\xED\xF5\xED\xE6\x45\xCB\x4C"=0A=
+    "\x2D\xA3\x01\xD5\x21\xB2\x0B\xA4\x38\xB5\x28\x00\x38\x41\xDF\x74"=0A=
+    "\xA8\x8D\xC7\x44\xD1\x5D\x77\xCD\xDC\xE2\xA7\x58\xBC\xAA\xA1\xB9"=0A=
+    "\x19\x1C\x76\x37\x71\x9D\xB2\xBC\x8F\x5F\x9B\xCC\x6D\xDA\x1B\x42"=0A=
+    "\xBD\x55\x7A\xDC\x69\x29\x5F\x00\x29\x2A\x04\x85\x6F\xCB\x91\x2A"=0A=
+    "\xE7\x9A\x43\x32\x99\xFF\x00\x00\x99\xE5\xC4\x09\xE9\xDD\x85\xA3"=0A=
+    "\xB6\x57\xB6\x97\x78\xD5\xDE\x61\xAE\xD8\x2F\x29\x6D\x80\x97\x41"=0A=
+    "\x71\x0A\x48\x20\xF1\x0E\x7B\xA9\x40\x72\xAF\x18\xF6\x90\xCD\x86"=0A=
+    "\x0E\x5E\xC6\x53\x19\xA5\x78\x3B\x8C\xC4\x6E\xF7\x11\x6A\xCC\x63"=0A=
+    "\x0A\x6D\x92\x5D\x7D\x20\x25\x6E\xBE\xA4\xFA\x4E\x00\x47\x34\x00"=0A=
+    "\x41\xDF\x7D\x89\x48\xA0\xEB\xB4\x3A\x51\xA9\xF3\x3B\x0C\x6C\x9E"=0A=
+    "\x51\x87\x8D\x62\xA3\x99\x1C\x43\x4F\xDB\xB5\x6C\xE3\xCA\xBE\x5D"=0A=
+    "\xC2\x83\x67\xD2\x10\x77\x42\x59\x50\xF4\x8A\x4A\x77\x2B\x00\xA3"=0A=
+    "\x72\x79\xD3\xA3\x5C\xFE\x9A\xE1\x2E\xA3\x5A\x75\x1A\x8E\x5F\x38"=0A=
+    "\xCB\x97\x78\xAC\x45\xAD\x93\xEB\x64\x92\xDA\x96\xD3\x29\x42\x8A"=0A=
+    "\x49\x00\x94\xEE\x93\xB6\xE0\x1D\xBE\xC1\x5D\x05\x01\x55\x9B\xA3"=0A=
+    "\xEB\xDF\x58\xA1\x63\xF3\x05\x87\xC4\x22\xAC\xCA\xAB\x13\x47\x17"=0A=
+    "\xBE\xB2\x42\x7F\xDC\x36\x1F\x10\x8A\x09\x83\x2D\x5E\xD2\x4C\xA0"=0A=
+    "\xFB\xE3\xBE\xF9\xA7\xEA\xA3\xEC\xC1\x7B\x49\xB2\xA3\xEF\xAF\x7B"=0A=
+    "\xE6\xA4\x15\x01\x45\x14\x50\x14\x51\x45\x01\x45\x14\x50\x22\xB4"=0A=
+    "\xC4\xE2\xAC\xF2\x97\xD9\x4B\x4C\x65\x95\xBD\xFE\x43\xD1\xFD\x76"=0A=
+    "\xE9\xA6\x12\x97\x6E\x7D\x1A\x78\x5B\xF4\x8B\x03\x75\xF0\xA4\x90"=0A=
+    "\x37\x27\x61\xC8\x52\xDA\x28\xA0\x28\xA2\x8A\x02\x8A\x28\xA0\x2A"=0A=
+    "\xAF\x34\x69\x7B\xEB\x34\x20\x6F\xFD\xE2\xB0\xF8\x96\xEA\xD0\xEA"=0A=
+    "\xAD\x34\x5D\x7B\xEB\x4C\x1C\x7E\x62\xC7\xFC\x4B\x74\x13\x06\x66"=0A=
+    "\xBD\xA5\x39\x7F\xE7\x5E\xF7\xCD\x48\xAA\x60\xA6\x91\xD9\x02\xA5"=0A=
+    "\x19\x45\xB5\x85\xC8\x3A\xDB\x97\x6E\x38\x85\xB5\x6E\xA5\xA5\x49"=0A=
+    "\x52\x8A\x81\x05\x20\x8E\x84\x7F\xA7\x4E\xB5\xCF\x3F\x1A\x93\x1E"=0A=
+    "\x91\xDC\xB9\xF0\x4E\x7C\xA8\x24\xF5\x15\x14\xDE\x8B\x4A\x4F\x48"=0A=
+    "\xD6\x64\xF8\x17\x7B\x69\x0B\xD1\x39\x61\xDF\x68\xC6\x6F\xFE\x03"=0A=
+    "\xBD\xB4\x12\xEA\x8A\x87\x0F\x44\x25\xE7\xA4\x57\x3A\x7C\xBD\xDE"=0A=
+    "\xDA\x44\xF4\x36\x66\x7A\x44\xB3\xE7\xCB\x9E\xED\xA0\x9A\x94\x54"=0A=
+    "\x1D\x7A\x13\x36\x3D\x21\xF2\x13\xE5\xAF\x76\xD2\x17\xA0\xD3\x93"=0A=
+    "\xD2\x19\x23\x3E\x58\xF7\x6D\x04\xF0\xA2\xA0\x13\xF0\x29\xE1\xE9"=0A=
+    "\x09\x92\x9F\x2A\x7F\xB6\x91\x3D\xA7\xF3\xF3\xD2\x0D\x27\x3E\x52"=0A=
+    "\xFF\x00\x6D\x05\x85\x51\x55\xCE\xF6\x9E\x6A\x11\xE9\x04\x94\x9F"=0A=
+    "\x28\x7F\xB2\x91\x3F\xA7\x3A\x8A\x77\xDA\x03\x2B\x3E\x4F\x71\xD9"=0A=
+    "\x41\x64\xB4\x55\x66\x3D\xA6\xBA\x92\x7A\x69\xF4\xB0\xF9\x35\xC7"=0A=
+    "\x65\x21\x7B\x4C\xB5\x30\xF4\xD3\xB9\x71\xF2\x5B\x8E\xCA\x0B\x41"=0A=
+    "\xAA\xAC\xD1\x45\xFF\x00\x5D\x90\x51\xF9\x8F\x1F\xF1\x2D\xD7\xAB"=0A=
+    "\xDA\x5F\xA9\xE7\xA6\x9C\x4C\x0F\x92\x5C\xF6\x57\x4B\xA2\x7A\x59"=0A=
+    "\xA9\x88\xD6\x68\x6D\xCD\xCC\x06\x4D\x67\x6D\x6B\x9B\xB4\xBA\xB8"=0A=
+    "\xB8\xBB\xC6\xBB\x6E\xD3\x4D\x34\xEA\x5C\x5A\x94\xB7\x12\x12\x36"=0A=
+    "\x4A\x4E\xC3\x7D\xC9\xD8\x0D\xC9\x00\x87\xFF\xD9";=0A=
+=0A=
diff -urNp linux/minidlna.init.d.script linux/minidlna.init.d.script=0A=
--- linux/minidlna.init.d.script	2010-12-16 21:26:22.000000000 +0100=0A=
+++ linux/minidlna.init.d.script	2010-12-16 22:03:06.000000000 +0100=0A=
@@ -33,7 +33,10 @@=0A=
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED =
OF THE=0A=
 # POSSIBILITY OF SUCH DAMAGE.=0A=
 =0A=
+set -e=0A=
+=0A=
 MINIDLNA=3D/usr/sbin/minidlna=0A=
+PIDFILE=3D/var/run/minidlna.pid=0A=
 ARGS=3D'-f /etc/minidlna.conf'=0A=
 =0A=
 test -f $MINIDLNA || exit 0=0A=
@@ -41,21 +44,38 @@ test -f $MINIDLNA || exit 0=0A=
 . /lib/lsb/init-functions=0A=
 =0A=
 case "$1" in=0A=
+reload|force-reload)=0A=
+        ARGS=3D"$ARGS -R"=0A=
+        ;;=0A=
+esac=0A=
+=0A=
+case "$1" in=0A=
 start)  log_daemon_msg "Starting minidlna" "minidlna"=0A=
-        start-stop-daemon --start --quiet --pidfile =
/var/run/minidlna.pid --startas $MINIDLNA -- $ARGS $LSBNAMES=0A=
+        start-stop-daemon --start --quiet --pidfile $PIDFILE --startas =
$MINIDLNA -- $ARGS $LSBNAMES=0A=
         log_end_msg $?=0A=
         ;;=0A=
 stop)   log_daemon_msg "Stopping minidlna" "minidlna"=0A=
-        start-stop-daemon --stop --quiet --pidfile /var/run/minidlna.pid=0A=
+        start-stop-daemon --stop --quiet -oknodo --pidfile $PIDFILE=0A=
         log_end_msg $?=0A=
+        rm -f $PIDFILE=0A=
         ;;=0A=
 restart|reload|force-reload)=0A=
+        set +e=0A=
         log_daemon_msg "Restarting minidlna" "minidlna"=0A=
-        start-stop-daemon --stop --retry 5 --quiet --pidfile =
/var/run/minidlna.pid=0A=
-        start-stop-daemon --start --quiet --pidfile =
/var/run/minidlna.pid --startas $MINIDLNA -- $ARGS $LSBNAMES=0A=
+        if [ -s $PIDFILE ] && kill -0 $(cat $PIDFILE) >/dev/null 2>&1; =
then=0A=
+                start-stop-daemon --stop --retry 5 --quiet -oknodo =
--pidfile $PIDFILE || true=0A=
+                sleep 1=0A=
+        else=0A=
+		log_warning_msg "minidlna is not running, attempting to start."=0A=
+                rm -f $PIDFILE=0A=
+        fi=0A=
+        start-stop-daemon --start --quiet --pidfile $PIDFILE --startas =
$MINIDLNA -- $ARGS $LSBNAMES=0A=
         log_end_msg $?=0A=
         ;;=0A=
-*)      log_action_msg "Usage: /etc/init.d/minidlna =
{start|stop|restart|reload|force-reload}"=0A=
+status)=0A=
+        status_of_proc -p $PIDFILE $MINIDLNA minidlna && exit 0 || exit =
$?=0A=
+        ;;=0A=
+*)      log_action_msg "Usage: /etc/init.d/minidlna =
{start|stop|restart|reload|force-reload|status}"=0A=
         exit 2=0A=
         ;;=0A=
 esac=0A=
diff -urNp Makefile Makefile=0A=
--- Makefile	2010-12-16 21:26:21.000000000 +0100=0A=
+++ Makefile	2010-12-19 20:32:07.000000000 +0100=0A=
@@ -10,20 +10,32 @@=0A=
 # or :=0A=
 # $ make install=0A=
 #=0A=
+=0A=
+# set, if you want to include thumbnail creation support=0A=
+# (requires libffmpegthumbnailer library)=0A=
+CREATE_THUMBNAILS=3Dyes=0A=
+=0A=
+# installation paths=0A=
+INSTALLPREFIX ?=3D $(DESTDIR)/usr=0A=
+SBININSTALLDIR =3D $(INSTALLPREFIX)/sbin=0A=
+ETCINSTALLDIR =3D $(DESTDIR)/etc=0A=
+=0A=
+# needed programs=0A=
+CC =3D gcc=0A=
+RM =3D rm -f=0A=
+INSTALL =3D install=0A=
+=0A=
+# Compile flags=0A=
+=0A=
 #CFLAGS =3D -Wall -O -D_GNU_SOURCE -g -DDEBUG=0A=
 #CFLAGS =3D -Wall -g -Os -D_GNU_SOURCE=0A=
 CFLAGS =3D -Wall -g -O3 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=3D64 \=0A=
+	-I/home/anders/privat/Projekte/minidlna/dev-install/include \=0A=
 	 -I/usr/include/ffmpeg \=0A=
 	 -I/usr/include/libavutil -I/usr/include/libavcodec =
-I/usr/include/libavformat \=0A=
 	 -I/usr/include/ffmpeg/libavutil -I/usr/include/ffmpeg/libavcodec =
-I/usr/include/ffmpeg/libavformat=0A=
-#STATIC_LINKING: LDFLAGS =3D -static=0A=
-CC =3D gcc=0A=
-RM =3D rm -f=0A=
-INSTALL =3D install=0A=
 =0A=
-INSTALLPREFIX ?=3D $(DESTDIR)/usr=0A=
-SBININSTALLDIR =3D $(INSTALLPREFIX)/sbin=0A=
-ETCINSTALLDIR =3D $(DESTDIR)/etc=0A=
+#STATIC_LINKING: LDFLAGS =3D -static=0A=
 =0A=
 BASEOBJS =3D minidlna.o upnphttp.o upnpdescgen.o upnpsoap.o \=0A=
            upnpreplyparse.o minixml.o \=0A=
@@ -36,9 +48,19 @@ BASEOBJS =3D minidlna.o upnphttp.o upnpdes=0A=
 =0A=
 ALLOBJS =3D $(BASEOBJS) $(LNXOBJS)=0A=
 =0A=
+LDFLAGS =3D -L/home/anders/privat/Projekte/minidlna/dev-install/lib=0A=
 LIBS =3D -lpthread -lexif -ljpeg -lsqlite3 -lavformat -lavutil =
-lavcodec -lid3tag -lFLAC -logg -lvorbis=0A=
 #STATIC_LINKING: LIBS =3D -lvorbis -logg -lm -lsqlite3 -lpthread -lexif =
-ljpeg -lFLAC -lm -lid3tag -lz -lavformat -lavutil -lavcodec -lm=0A=
 =0A=
+#LIBS2 =3D -lffmpegthumbnailer -lstdc++ -lbz2 -lswscale -lavutil -lpng=0A=
+LIBS2 =3D -lstdc++ -lbz2 -lswscale -lavutil -lpng=0A=
+=0A=
+ifneq ($(CREATE_THUMBNAILS),no)=0A=
+  #LIBS +=3D -lffmpegthumbnailer=0A=
+  LIBS2 :=3D -lffmpegthumbnailer $(LIBS2)=0A=
+  CFLAGS +=3D -DTHUMBNAIL_CREATION_SUPPORT=0A=
+endif=0A=
+=0A=
 TESTUPNPDESCGENOBJS =3D testupnpdescgen.o upnpdescgen.o=0A=
 =0A=
 EXECUTABLES =3D minidlna testupnpdescgen=0A=
@@ -63,7 +85,7 @@ install:	minidlna=0A=
 =0A=
 minidlna:	$(BASEOBJS) $(LNXOBJS) $(LIBS)=0A=
 	@echo Linking $@=0A=
-	@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BASEOBJS) $(LNXOBJS) $(LIBS)=0A=
+	@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BASEOBJS) $(LNXOBJS) $(LIBS) =
$(LIBS2)=0A=
 =0A=
 =0A=
 testupnpdescgen:	$(TESTUPNPDESCGENOBJS)=0A=
diff -urNp metadata.c metadata.c=0A=
--- metadata.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ metadata.c	2010-12-19 18:41:38.000000000 +0100=0A=
@@ -36,6 +36,7 @@=0A=
 #include "tagutils/tagutils.h"=0A=
 =0A=
 #include "upnpglobalvars.h"=0A=
+#include "upnphttp.h"=0A=
 #include "upnpreplyparse.h"=0A=
 #include "metadata.h"=0A=
 #include "albumart.h"=0A=
@@ -640,7 +641,7 @@ GetVideoMetadata(const char * path, char=0A=
 	int audio_stream =3D -1, video_stream =3D -1;=0A=
 	enum audio_profiles audio_profile =3D PROFILE_AUDIO_UNKNOWN;=0A=
 	ts_timestamp_t ts_timestamp =3D NONE;=0A=
-	int duration, hours, min, sec, ms;=0A=
+	int duration=3D0, hours, min, sec, ms;=0A=
 	aac_object_type_t aac_type =3D AAC_INVALID;=0A=
 	sqlite_int64 album_art =3D 0;=0A=
 	char nfo[PATH_MAX], *ext;=0A=
@@ -1092,6 +1093,10 @@ GetVideoMetadata(const char * path, char=0A=
 	{=0A=
 		ret =3D sqlite3_last_insert_rowid(db);=0A=
 		check_for_captions(path, ret);=0A=
+=0A=
+		/* if option is set, create suitable Samsung MTA file for this video =
*/=0A=
+		if (duration > 0 && GETFLAG(EXTERNAL_MTA_FILE_MASK))=0A=
+			generate_external_samsung_mta_file(path, duration);=0A=
 	}=0A=
 	free_metadata(&m, free_flags);=0A=
 =0A=
diff -urNp minidlna.c minidlna.c=0A=
--- minidlna.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ minidlna.c	2010-12-16 22:03:06.000000000 +0100=0A=
@@ -472,6 +472,10 @@ init(int argc, char * * argv)=0A=
 				if( (strcmp(ary_options[i].value, "yes") =3D=3D 0) || =
atoi(ary_options[i].value) )=0A=
 					SETFLAG(DLNA_STRICT_MASK);=0A=
 				break;=0A=
+			case ENABLE_EXTERNAL_MTA_FILES:=0A=
+				if( (strcmp(ary_options[i].value, "yes") =3D=3D 0) || =
atoi(ary_options[i].value) )=0A=
+					SETFLAG(EXTERNAL_MTA_FILE_MASK);=0A=
+				break;=0A=
 			default:=0A=
 				fprintf(stderr, "Unknown option in file %s\n",=0A=
 				        optionsfile);=0A=
diff -urNp minidlna.conf minidlna.conf=0A=
--- minidlna.conf	2009-11-19 04:22:35.000000000 +0100=0A=
+++ minidlna.conf	2010-12-17 00:48:49.000000000 +0100=0A=
@@ -45,3 +45,19 @@ notify_interval=3D900=0A=
 # in its XML description=0A=
 serial=3D12345678=0A=
 model_number=3D1=0A=
+=0A=
+#=0A=
+# Samsung specific switches=0A=
+#=0A=
+# samsung_external_mta_files =3D yes|no=0A=
+#=0A=
+# Set to yes on Samsung TV (e.g. LE40C650 and similar) if you are =
running=0A=
+# miniDLNA on a slow device.  This will precalculate the MTA files =
needed=0A=
+# for the Smasung TV chapter menu while building the database instead of=0A=
+# generating the MTA file on-the-fly if requested.  Now, consider this: =
if=0A=
+# generating MTA files is too slow for on-the-fly generation, the =
building=0A=
+# of the database will considerably slow down by setting this to yes!=0A=
+# Also note that a precomputed MTA file will always(!) be sent if =
requested. =0A=
+# No on-thy-fly generation takes place. So, to change this, remove all =
MTA=0A=
+# files as well.=0A=
+samsung_external_mta_files =3D no=0A=
diff -urNp options.c options.c=0A=
--- options.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ options.c	2010-12-19 18:42:07.000000000 +0100=0A=
@@ -58,7 +58,8 @@ static const struct {=0A=
 	{ UPNPDBDIR, "db_dir" },=0A=
 	{ UPNPLOGDIR, "log_dir" },=0A=
 	{ ENABLE_TIVO, "enable_tivo" },=0A=
	{ ENABLE_DLNA_STRICT, "strict_dlna" },=0A=
+	{ ENABLE_EXTERNAL_MTA_FILES, "samsung_external_mta_files" },=0A=
	{ UPNPMINISSDPDSOCKET, "minissdpdsocket"}=0A=
 };=0A=
 =0A=
 int=0A=
diff -urNp options.h options.h=0A=
--- options.h	2011-02-03 23:38:12.000000000 +0100=0A=
+++ options.h	2011-02-03 23:47:14.000000000 +0100=0A=
@@ -52,6 +52,7 @@ enum upnpconfigoptions {=0A=
 	UPNPLOGDIR,			/* base directory to store the log file */=0A=
 	ENABLE_TIVO,			/* enable support for streaming images and music to =
TiVo */=0A=
 	ENABLE_DLNA_STRICT,		/* strictly adhere to DLNA specs */=0A=
+	ENABLE_EXTERNAL_MTA_FILES,	/* Samsung: enable generation of external =
MTA files (for slower NAS devices) */=0A=
 	UPNPMINISSDPDSOCKET		/* minissdpdsocket */=0A=
 };=0A=
=0A=
diff -urNp scanner.c scanner.c=0A=
--- scanner.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ scanner.c	2010-12-17 00:50:14.000000000 +0100=0A=
@@ -568,7 +568,8 @@ CreateDatabase(void)=0A=
 					"REF_ID TEXT DEFAULT NULL, "=0A=
 					"CLASS TEXT NOT NULL, "=0A=
 					"DETAIL_ID INTEGER DEFAULT NULL, "=0A=
-					"NAME TEXT DEFAULT NULL"=0A=
+					"NAME TEXT DEFAULT NULL, "=0A=
+                    "BOOKMARK INTEGER DEFAULT 0" /* time position in =
seconds [ESamsungTV] */=0A=
 					");");=0A=
 	if( ret !=3D SQLITE_OK )=0A=
 		goto sql_failed;=0A=
diff -urNp upnpdescgen.c upnpdescgen.c=0A=
--- upnpdescgen.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnpdescgen.c	2010-12-17 00:50:45.000000000 +0100=0A=
@@ -118,6 +118,10 @@ static const char root_service[] =3D=0A=
 	"scpd xmlns=3D\"urn:schemas-upnp-org:service-1-0\"";=0A=
 static const char root_device[] =3D =0A=
 	"root xmlns=3D\"urn:schemas-upnp-org:device-1-0\"";=0A=
+static const char root_device_samsung[] =3D =0A=
+	"root xmlns=3D\"urn:schemas-upnp-org:device-1-0\""=0A=
+    " xmlns:sec=3D\"http://www.sec.co.kr/dlna\""=0A=
+    " xmlns:dlna=3D\"urn:schemas-dlna-org:device-1-0\"";=0A=
 =0A=
 /* root Description of the UPnP Device =0A=
  * fixed to match UPnP_IGD_InternetGatewayDevice 1.0.pdf =0A=
@@ -189,6 +193,75 @@ static const struct XMLElt rootDesc[] =3D=0A=
 	{0, 0}=0A=
 };=0A=
 =0A=
+/* root Description of the UPnP Device for Samsung TV renderers */=0A=
+static const struct XMLElt rootDescSamsung[] =3D=0A=
+{=0A=
+/*0*/	{root_device_samsung, INITHELPER(1,2)},=0A=
+	{"specVersion", INITHELPER(3,2)},=0A=
+	{"device", INITHELPER(5,16)},=0A=
+	{"/major", "1"},=0A=
+	{"/minor", "0"},=0A=
+	{"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"},=0A=
+	{"/friendlyName", friendly_name},	/* required */=0A=
+	{"/manufacturer", ROOTDEV_MANUFACTURER},		/* required */=0A=
+	{"/manufacturerURL", ROOTDEV_MANUFACTURERURL},	/* optional */=0A=
+	{"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */=0A=
+/*10*/	{"/modelName", ROOTDEV_MODELNAME},	/* required */=0A=
+	{"/modelNumber", modelnumber},=0A=
+	{"/modelURL", ROOTDEV_MODELURL},=0A=
+	{"/serialNumber", serialnumber},=0A=
+        {"/sec:ProductCap", =
"smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec"},=0A=
+        {"/sec:X_ProductCap", =
"smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec"},=0A=
+	{"/UDN", uuidvalue},	/* required */=0A=
+	{"/dlna:X_DLNADOC xmlns:dlna=3D\"urn:schemas-dlna-org:device-1-0\"", =
"DMS-1.50"},=0A=
+	{"/presentationURL", presentationurl},	/* recommended */=0A=
+	{"iconList", INITHELPER(21,4)},=0A=
+/*20*/	{"serviceList", INITHELPER(45,3)},=0A=
+	{"icon", INITHELPER(25,5)},=0A=
+	{"icon", INITHELPER(30,5)},=0A=
+	{"icon", INITHELPER(35,5)},=0A=
+	{"icon", INITHELPER(40,5)},=0A=
+	{"/mimetype", "image/png"},=0A=
+	{"/width", "48"},=0A=
+	{"/height", "48"},=0A=
+	{"/depth", "24"},=0A=
+	{"/url", "/icons/sm.png"},=0A=
+/*30*/	{"/mimetype", "image/png"},=0A=
+	{"/width", "120"},=0A=
+	{"/height", "120"},=0A=
+	{"/depth", "24"},=0A=
+	{"/url", "/icons/lrg.png"},=0A=
+	{"/mimetype", "image/jpeg"},=0A=
+	{"/width", "48"},=0A=
+	{"/height", "48"},=0A=
+	{"/depth", "24"},=0A=
+	{"/url", "/icons/sm.jpg"},=0A=
+/*40*/	{"/mimetype", "image/jpeg"},=0A=
+	{"/width", "120"},=0A=
+	{"/height", "120"},=0A=
+	{"/depth", "24"},=0A=
+	{"/url", "/icons/lrg.jpg"},=0A=
+	{"service", INITHELPER(48,5)},=0A=
+	{"service", INITHELPER(53,5)},=0A=
+	{"service", INITHELPER(58,5)},=0A=
+	{"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"},=0A=
+	{"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"},=0A=
+/*50*/	{"/controlURL", CONTENTDIRECTORY_CONTROLURL},=0A=
+	{"/eventSubURL", CONTENTDIRECTORY_EVENTURL},=0A=
+	{"/SCPDURL", CONTENTDIRECTORY_PATH},=0A=
+	{"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"},=0A=
+	{"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"},=0A=
+	{"/controlURL", CONNECTIONMGR_CONTROLURL},=0A=
+	{"/eventSubURL", CONNECTIONMGR_EVENTURL},=0A=
+	{"/SCPDURL", CONNECTIONMGR_PATH},=0A=
+	{"/serviceType", =
"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"},=0A=
+	{"/serviceId", =
"urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"},=0A=
+/*60*/	{"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL},=0A=
+	{"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL},=0A=
+	{"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH},=0A=
+	{0, 0}=0A=
+};=0A=
+=0A=
 static const struct argument AddPortMappingArgs[] =3D=0A=
 {=0A=
 	{NULL, 1, 11},=0A=
@@ -560,7 +633,7 @@ genXML(char * str, int * len, int * tmpl=0A=
 	int top;=0A=
 	const char * eltname, *s;=0A=
 	char c;=0A=
-	char element[64];=0A=
+	char element[256];=0A=
 	struct {=0A=
 		unsigned short i;=0A=
 		unsigned short j;=0A=
@@ -659,6 +732,23 @@ genRootDesc(int * len)=0A=
 	return str;=0A=
 }=0A=
 =0A=
+char *=0A=
+genRootDescSamsung(int * len)=0A=
+{=0A=
+	char * str;=0A=
+	int tmplen;=0A=
+	tmplen =3D 3072;=0A=
+	str =3D (char *)malloc(tmplen);=0A=
+	if(str =3D=3D NULL)=0A=
+		return NULL;=0A=
+	* len =3D strlen(xmlver);=0A=
+	/*strcpy(str, xmlver); */=0A=
+	memcpy(str, xmlver, *len + 1);=0A=
+	str =3D genXML(str, len, &tmplen, rootDescSamsung);=0A=
+	str[*len] =3D '\0';=0A=
+	return str;=0A=
+}=0A=
+=0A=
 /* genServiceDesc() :=0A=
  * Generate service description with allowed methods and =0A=
  * related variables. */=0A=
diff -urNp upnpdescgen.h upnpdescgen.h=0A=
--- upnpdescgen.h	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnpdescgen.h	2010-12-16 22:03:06.000000000 +0100=0A=
@@ -73,6 +73,8 @@ struct stateVar {=0A=
  * returns: NULL on error, string allocated on the heap */=0A=
 char *=0A=
 genRootDesc(int * len);=0A=
+char *=0A=
+genRootDescSamsung(int * len);=0A=
 =0A=
 /* for the two following functions */=0A=
 char *=0A=
diff -urNp upnpglobalvars.h upnpglobalvars.h=0A=
--- upnpglobalvars.h	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnpglobalvars.h	2010-12-16 22:03:06.000000000 +0100=0A=
@@ -128,6 +128,7 @@ extern int runtime_flags;=0A=
 #define INOTIFY_MASK          0x0001=0A=
 #define TIVO_MASK             0x0002=0A=
 #define DLNA_STRICT_MASK      0x0004=0A=
+#define EXTERNAL_MTA_FILE_MASK      0x0008=0A=
 =0A=
 #define SETFLAG(mask)	runtime_flags |=3D mask=0A=
 #define GETFLAG(mask)	runtime_flags & mask=0A=
diff -urNp upnphttp.c upnphttp.c=0A=
--- upnphttp.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnphttp.c	2010-12-19 20:30:35.000000000 +0100=0A=
@@ -75,6 +75,9 @@=0A=
 #include "log.h"=0A=
 #include "sql.h"=0A=
 #include <libexif/exif-loader.h>=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+#include <libffmpegthumbnailer/videothumbnailerc.h>=0A=
+#endif=0A=
 #ifdef TIVO_SUPPORT=0A=
 #include "tivo_utils.h"=0A=
 #include "tivo_commands.h"=0A=
@@ -397,6 +400,10 @@ intervening space) by either an integer =0A=
 			{=0A=
 				h->reqflags |=3D FLAG_CAPTION;=0A=
 			}=0A=
+			else if(strncasecmp(line, "getMediaInfo.sec", 16)=3D=3D0)=0A=
+			{=0A=
+                h->reqflags |=3D FLAG_MEDIA_INFO;=0A=
+			}=0A=
 		}=0A=
 next_header:=0A=
 		while(!(line[0] =3D=3D '\r' && line[1] =3D=3D '\n'))=0A=
@@ -799,11 +806,11 @@ ProcessHttpQuery_upnphttp(struct upnphtt=0A=
 				sendXMLdesc(h, genRootDesc);=0A=
 				friendly_name[strlen(friendly_name)-3] =3D '\0';=0A=
 			}=0A=
+			else if (h->req_client =3D=3D ESamsungTV)=0A=
+				sendXMLdesc(h, genRootDescSamsung);=0A=
 			else=0A=
-			{=0A=
 				sendXMLdesc(h, genRootDesc);=0A=
 			}=0A=
-		}=0A=
 		else if(strcmp(CONTENTDIRECTORY_PATH, HttpUrl) =3D=3D 0)=0A=
 		{=0A=
 			sendXMLdesc(h, genContentDirectory);=0A=
@@ -830,6 +837,11 @@ ProcessHttpQuery_upnphttp(struct upnphtt=0A=
 			SendResp_albumArt(h, HttpUrl+10);=0A=
 			CloseSocket_upnphttp(h);=0A=
 		}=0A=
+		else if((strncmp(HttpUrl, "/MTA/", 5) =3D=3D 0) && (h->req_client =
=3D=3D ESamsungTV))=0A=
+		{=0A=
+			SendResp_samsung_mta_file(h, HttpUrl+5);=0A=
+			CloseSocket_upnphttp(h);=0A=
+		}=0A=
 		#ifdef TIVO_SUPPORT=0A=
 		else if(strncmp(HttpUrl, "/TiVoConnect", 12) =3D=3D 0)=0A=
 		{=0A=
@@ -1169,7 +1181,7 @@ send_file(struct upnphttp * h, int sendf=0A=
 void=0A=
 SendResp_icon(struct upnphttp * h, char * icon)=0A=
 {=0A=
-	char * header;=0A=
+    char * header =3D 0;=0A=
 	char * data;=0A=
 	int size, ret;=0A=
 	char mime[12];=0A=
@@ -1221,6 +1233,8 @@ SendResp_icon(struct upnphttp * h, char =0A=
 	                        "Server: " MINIDLNA_SERVER_STRING "\r\n\r\n",=0A=
 	                        mime, size, date);=0A=
 =0A=
+	DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
+=0A=
 	if( (send_data(h, header, ret, MSG_MORE) =3D=3D 0) && (h->req_command =
!=3D EHead) )=0A=
 	{=0A=
 		send_data(h, data, size, 0);=0A=
@@ -1283,20 +1297,21 @@ SendResp_albumArt(struct upnphttp * h, c=0A=
 				"Connection: close\r\n"=0A=
 				"Date: %s\r\n"=0A=
 				"EXT:\r\n"=0A=
-				"realTimeInfo.dlna.org: DLNA.ORG_TLAG=3D*\r\n"=0A=
 				"contentFeatures.dlna.org: DLNA.ORG_PN=3DJPEG_TN\r\n"=0A=
 				"Server: " MINIDLNA_SERVER_STRING "\r\n",=0A=
 				(intmax_t)size, date);=0A=
 =0A=
+		if( h->reqflags & FLAG_REALTIMEINFO )=0A=
+			strcat(header, "realTimeInfo.dlna.org: DLNA.ORG_TLAG=3D*\r\n");=0A=
+=0A=
 		if( h->reqflags & FLAG_XFERBACKGROUND )=0A=
-		{=0A=
-			strcat(header, "transferMode.dlna.org: Background\r\n\r\n");=0A=
-		}=0A=
+			strcat(header, "transferMode.dlna.org: Background\r\n");=0A=
 		else //if( h->reqflags & FLAG_XFERINTERACTIVE )=0A=
-		{=0A=
-			strcat(header, "transferMode.dlna.org: Interactive\r\n\r\n");=0A=
-		}=0A=
+			strcat(header, "transferMode.dlna.org: Interactive\r\n");=0A=
+=0A=
+        DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
 =0A=
+        strcat(header, "\r\n");=0A=
 =0A=
 		if( (send_data(h, header, strlen(header), MSG_MORE) =3D=3D 0) && =
(h->req_command !=3D EHead) && (sendfh > 0) )=0A=
 		{=0A=
@@ -1348,13 +1363,23 @@ SendResp_caption(struct upnphttp * h, ch=0A=
 	lseek(sendfh, 0, SEEK_SET);=0A=
 =0A=
 	ret =3D snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"=0A=
+/*	                                       "Server: Samsung HTTP =
streaming server\r\n" */=0A=
+	                                       "Server: " =
MINIDLNA_SERVER_STRING "\r\n"=0A=
 	                                       "Content-Type: smi/caption\r\n"=0A=
 	                                       "Content-Length: %jd\r\n"=0A=
-	                                       "Connection: close\r\n"=0A=
+	                                       "Cache-Control: no-cache\r\n"=0A=
+                                           "contentFeatures.dlna.org: =
DLNA.ORG_OP=3D00;DLNA.ORG_CI=3D0;\r\n"=0A=
+/*	                                       "Connection: close\r\n" */=0A=
 	                                       "Date: %s\r\n"=0A=
-	                                       "EXT:\r\n"=0A=
-	                                       "Server: " =
MINIDLNA_SERVER_STRING "\r\n\r\n",=0A=
-	                                       (intmax_t)size, date);=0A=
+	                                       "EXT:\r\n",=0A=
+                                           (intmax_t)size, date);=0A=
+=0A=
+	if( h->reqflags & FLAG_XFERBACKGROUND )=0A=
+		strcat(header, "transferMode.dlna.org:Background\r\n");=0A=
+=0A=
+	DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
+=0A=
+	strcat(header, "\r\n");=0A=
 =0A=
 	if( (send_data(h, header, ret, MSG_MORE) =3D=3D 0) && (h->req_command =
!=3D EHead) && (sendfh > 0) )=0A=
 	{=0A=
@@ -1422,20 +1447,26 @@ SendResp_thumbnail(struct upnphttp * h, =0A=
 				"Connection: close\r\n"=0A=
 				"Date: %s\r\n"=0A=
 				"EXT:\r\n"=0A=
-				"realTimeInfo.dlna.org: DLNA.ORG_TLAG=3D*\r\n"=0A=
 			 	"contentFeatures.dlna.org: DLNA.ORG_PN=3DJPEG_TN\r\n"=0A=
 				"Server: " MINIDLNA_SERVER_STRING "\r\n",=0A=
 				ed->size, date);=0A=
 =0A=
+		if( h->reqflags & FLAG_REALTIMEINFO )=0A=
+			strcat(header, "realTimeInfo.dlna.org: DLNA.ORG_TLAG=3D*\r\n");=0A=
+=0A=
 		if( h->reqflags & FLAG_XFERBACKGROUND )=0A=
 		{=0A=
-			strcat(header, "transferMode.dlna.org: Background\r\n\r\n");=0A=
+			strcat(header, "transferMode.dlna.org: Background\r\n");=0A=
 		}=0A=
 		else //if( h->reqflags & FLAG_XFERINTERACTIVE )=0A=
 		{=0A=
-			strcat(header, "transferMode.dlna.org: Interactive\r\n\r\n");=0A=
+			strcat(header, "transferMode.dlna.org: Interactive\r\n");=0A=
 		}=0A=
 =0A=
+        DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
+=0A=
+        strcat(header, "\r\n");=0A=
+=0A=
 		if( (send_data(h, header, strlen(header), MSG_MORE) =3D=3D 0) && =
(h->req_command !=3D EHead) )=0A=
 		{=0A=
 			send_data(h, (char *)ed->data, ed->size, 0);=0A=
@@ -1572,10 +1603,12 @@ SendResp_resizedimg(struct upnphttp * h,=0A=
 	                                     "Connection: close\r\n"=0A=
 	                                     "Date: %s\r\n"=0A=
 	                                     "EXT:\r\n"=0A=
-	                                     "realTimeInfo.dlna.org: =
DLNA.ORG_TLAG=3D*\r\n"=0A=
 	                                     "contentFeatures.dlna.org: =
DLNA.ORG_PN=3DJPEG_%s;DLNA.ORG_CI=3D1\r\n"=0A=
 	                                     "Server: " MINIDLNA_SERVER_STRING =
"\r\n",=0A=
 	                                     date, dlna_pn);=0A=
+	if( h->reqflags & FLAG_REALTIMEINFO )=0A=
+		strcat(header, "realTimeInfo.dlna.org: DLNA.ORG_TLAG=3D*\r\n");=0A=
+=0A=
 	if( h->reqflags & FLAG_XFERINTERACTIVE )=0A=
 	{=0A=
 		strcat(header, "transferMode.dlna.org: Interactive\r\n");=0A=
@@ -1633,6 +1666,8 @@ SendResp_resizedimg(struct upnphttp * h,=0A=
 		strcat(header, str_buf);=0A=
 	}=0A=
 =0A=
+	DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
+=0A=
 	if( (send_data(h, header, strlen(header), 0) =3D=3D 0) && =
(h->req_command !=3D EHead) )=0A=
 	{=0A=
 		if( chunked )=0A=
@@ -1683,7 +1718,7 @@ SendResp_dlnafile(struct upnphttp * h, c=0A=
 	off_t total, offset, size;=0A=
 	sqlite_int64 id;=0A=
 	int sendfh;=0A=
-	static struct { sqlite_int64 id; char path[PATH_MAX]; char mime[32]; =
char dlna[64]; } last_file =3D { 0 };=0A=
+	static struct { sqlite_int64 id; char path[PATH_MAX]; char mime[32]; =
char dlna[128]; char duration[32]; } last_file =3D { 0 };=0A=
 #if USE_FORK=0A=
 	pid_t newpid =3D 0;=0A=
 #endif=0A=
@@ -1691,7 +1726,7 @@ SendResp_dlnafile(struct upnphttp * h, c=0A=
 	id =3D strtoll(object, NULL, 10);=0A=
 	if( id !=3D last_file.id )=0A=
 	{=0A=
-		sprintf(sql_buf, "SELECT PATH, MIME, DLNA_PN from DETAILS where ID =
=3D '%lld'", id);=0A=
+		sprintf(sql_buf, "SELECT PATH, MIME, DLNA_PN, DURATION from DETAILS =
where ID =3D '%lld'", id);=0A=
 		ret =3D sql_get_table(db, sql_buf, &result, &rows, NULL);=0A=
 		if( (ret !=3D SQLITE_OK) )=0A=
 		{=0A=
@@ -1708,10 +1743,10 @@ SendResp_dlnafile(struct upnphttp * h, c=0A=
 		}=0A=
 		/* Cache the result */=0A=
 		last_file.id =3D id;=0A=
-		strncpy(last_file.path, result[3], sizeof(last_file.path)-1);=0A=
-		if( result[4] )=0A=
+		strncpy(last_file.path, result[4], sizeof(last_file.path)-1);=0A=
+		if( result[5] )=0A=
 		{=0A=
-			strncpy(last_file.mime, result[4], sizeof(last_file.mime)-1);=0A=
+			strncpy(last_file.mime, result[5], sizeof(last_file.mime)-1);=0A=
 			/* From what I read, Samsung TV's expect a [wrong] MIME type of =
x-mkv. */=0A=
 			if( h->req_client =3D=3D ESamsungTV )=0A=
 			{=0A=
@@ -1730,12 +1765,16 @@ SendResp_dlnafile(struct upnphttp * h, c=0A=
 		{=0A=
 			last_file.mime[0] =3D '\0';=0A=
 		}=0A=
-		if( result[5] )=0A=
-			snprintf(last_file.dlna, sizeof(last_file.dlna), "DLNA.ORG_PN=3D%s", =
result[5]);=0A=
+		if( result[6] )=0A=
+			snprintf(last_file.dlna, sizeof(last_file.dlna), "DLNA.ORG_PN=3D%s", =
result[6]);=0A=
 		else if( h->reqflags & FLAG_DLNA )=0A=
 			strcpy(last_file.dlna, dlna_no_conv);=0A=
 		else=0A=
 			last_file.dlna[0] =3D '\0';=0A=
+=0A=
+        if( result[7] )=0A=
+            strncpy(last_file.duration, result[7], =
sizeof(last_file.duration)-1);=0A=
+=0A=
 		sqlite3_free_table(result);=0A=
 	}=0A=
 #if USE_FORK=0A=
@@ -1863,16 +1902,41 @@ SendResp_dlnafile(struct upnphttp * h, c=0A=
 		}=0A=
 	}=0A=
 =0A=
+	if( last_file.duration && h->reqflags & FLAG_MEDIA_INFO )=0A=
+    {=0A=
+        int dur =3D atoi(rindex(last_file.duration, '.')+1) +=0A=
+                (1000*atoi(rindex(last_file.duration, ':')+1)) +=0A=
+                (60000*atoi(rindex(last_file.duration, ':')-2)) +=0A=
+                (3600000*atoi(last_file.duration));=0A=
+        sprintf(hdr_buf, "MediaInfo.sec: SEC_Duration=3D%d;\r\n", dur);=0A=
+        strcat(header, hdr_buf);=0A=
+	}=0A=
+=0A=
+    /* Special Samsung DLNA flags */=0A=
+    if( h->req_client =3D=3D ESamsungTV )=0A=
+    {=0A=
+		if( strncmp(last_file.mime, "image", 5) =3D=3D 0 )=0A=
+            strcat(last_file.dlna, =
";DLNA.ORG_FLAGS=3D00D00000000000000000000000000000");=0A=
+        else if (strncmp(last_file.mime, "video", 5) =3D=3D 0)=0A=
+            strcat(last_file.dlna, =
";DLNA.ORG_FLAGS=3D01500000000000000000000000000000");=0A=
+    }=0A=
+=0A=
 	sprintf(hdr_buf, "Accept-Ranges: bytes\r\n"=0A=
 			 "Connection: close\r\n"=0A=
 			 "Date: %s\r\n"=0A=
 			 "EXT:\r\n"=0A=
-	                 "realTimeInfo.dlna.org: DLNA.ORG_TLAG=3D*\r\n"=0A=
-			 "contentFeatures.dlna.org: %s\r\n"=0A=
-			 "Server: " MINIDLNA_SERVER_STRING "\r\n\r\n",=0A=
+			 "contentFeatures.dlna.org:%s\r\n"=0A=
+			 "Server: " MINIDLNA_SERVER_STRING "\r\n",=0A=
 			 date, last_file.dlna);=0A=
 	strcat(header, hdr_buf);=0A=
 =0A=
+	if( h->reqflags & FLAG_REALTIMEINFO )=0A=
+            strcat(header, "realTimeInfo.dlna.org: =
DLNA.ORG_TLAG=3D*\r\n");=0A=
+=0A=
+	DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
+=0A=
+	strcat(header, "\r\n");=0A=
+=0A=
 	if( (send_data(h, header, strlen(header), MSG_MORE) =3D=3D 0) && =
(h->req_command !=3D EHead) && (sendfh > 0) )=0A=
 	{=0A=
 		send_file(h, sendfh, offset, h->req_RangeEnd);=0A=
@@ -1886,3 +1950,333 @@ SendResp_dlnafile(struct upnphttp * h, c=0A=
 #endif=0A=
 	return;=0A=
 }=0A=
+=0A=
+/* encode 6 bit to base64 char */=0A=
+static char encode_base64(unsigned char c)=0A=
+{=0A=
+  if (c < 26)=0A=
+      return 'A' + c;=0A=
+  if (c < 52)=0A=
+      return 'a' + (c-26);=0A=
+  if (c < 62)=0A=
+      return '0' + (c-52);=0A=
+  if (c =3D=3D 62)=0A=
+      return '+';=0A=
+=0A=
+  /* 63 */=0A=
+  return '/';=0A=
+}=0A=
+=0A=
+void=0A=
+adjust_buffer(char** buffer, int* length)=0A=
+{=0A=
+    *length +=3D *length; /* double buffer size */=0A=
+    *buffer =3D realloc(*buffer, *length+1); /* get one for the =
terminating zero */=0A=
+}=0A=
+=0A=
+/* append data to buffer, if necessary get more memory and rebase =
current ptr */=0A=
+void=0A=
+add_to_buffer(char** buffer, int* length, char** ptr, const char* data, =
int datalen)=0A=
+{=0A=
+    if (*ptr - *buffer > *length) {=0A=
+        *ptr -=3D (int64_t)*buffer;=0A=
+        adjust_buffer(buffer, length);=0A=
+        *ptr +=3D (int64_t)*buffer; /* rebase ptr */=0A=
+    }=0A=
+    memcpy(*ptr, data, datalen);=0A=
+    *ptr +=3D datalen;=0A=
+}=0A=
+=0A=
+/*=0A=
+ * generates samsung MTA files for movies=0A=
+ * An MTA file contains XML with 5 chapter points each having an inline =
thumbnail=0A=
+ * in base64 encoding.=0A=
+ * The files are created with the minidlna-user (e.g. root).=0A=
+ *=0A=
+ * path         char*  IN   path and filename of movie=0A=
+ * duration     int    IN   duration of movie in seconds=0A=
+ */=0A=
+void=0A=
+generate_external_samsung_mta_file(const char* path, int duration)=0A=
+{=0A=
+    char mta_path[PATH_MAX];=0A=
+=0A=
+    snprintf(mta_path, sizeof(mta_path), "%s.mta", path);=0A=
+=0A=
+    if (ends_with(path, ".avi") || ends_with(path, ".mkv") || =
ends_with(path, ".mpg")) {=0A=
+        DPRINTF(E_DEBUG, L_METADATA, "Checking for external MTA file: =
%s\n", mta_path);=0A=
+        if (access(mta_path, F_OK) =3D=3D 0)=0A=
+            return; /* already found one, ok */=0A=
+=0A=
+        /* check movie */=0A=
+        if (access(path, F_OK) =3D=3D 0) {=0A=
+            int mta_size =3D 0;=0A=
+            char* body =3D generate_samsung_mta_file(path, duration);=0A=
+            mta_size =3D strlen(body);=0A=
+=0A=
+            FILE* mtafile =3D fopen(mta_path, "w");=0A=
+            if (mtafile) {=0A=
+                int size_written =3D fwrite((void *)body, 1, mta_size, =
mtafile);=0A=
+                fclose(mtafile);=0A=
+                if (size_written !=3D mta_size) {=0A=
+                    DPRINTF(E_DEBUG, L_METADATA, "Could not write =
external MTA file: '%s'\n", mta_path);=0A=
+                    remove(mta_path);=0A=
+                } else=0A=
+                    DPRINTF(E_DEBUG, L_METADATA, "Could open external =
MTA file for writing: '%s'\n", mta_path);=0A=
+            }=0A=
+	}=0A=
+    }=0A=
+}=0A=
+=0A=
+char*=0A=
+generate_samsung_mta_file(const char* path, int duration)=0A=
+{=0A=
+    static const char mta_header[] =3D=0A=
+        "<?xml version=3D\"1.0\" encoding=3D\"UTF-8\"?>\r\n"=0A=
+        "<SEC:SECMeta xsi:schemaLocation=3D\"urn:samsung:metadata:2009 =
Video_Metadata_v1.0.xsd\" =
xmlns:xsi=3D\"http://www.w3.org/2001/XMLSchema-instance\" =
xmlns:SEC=3D\"urn:samsung:metadata:2009\">\r\n"=0A=
+        "<SpecVersion>1.0</SpecVersion>\r\n"=0A=
+        "<MediaInformation>\r\n"=0A=
+        "<VideoLocator>\r\n"=0A=
+        "<MediaUri>file://samsung_content.con</MediaUri>\r\n"=0A=
+        "</VideoLocator>\r\n"=0A=
+        "</MediaInformation>\r\n"=0A=
+        "<ContentInformation>\r\n"=0A=
+        "<Chaptering>\r\n"=0A=
+        ;=0A=
+    static const char mta_chapter_header[] =3D=0A=
+        "<ChapterSegment>\r\n"=0A=
+        "<KeyFrame>\r\n"=0A=
+        "<InlineMedia>"=0A=
+        ;=0A=
+    static const char mta_chapter_closing[] =3D=0A=
+        "</InlineMedia>\r\n"=0A=
+        "</KeyFrame>\r\n"=0A=
+        "<MediaPosition>\r\n"=0A=
+        "<MediaTime timePoint=3D\"%d\"/>\r\n"=0A=
+        "</MediaPosition>\r\n"=0A=
+        "</ChapterSegment>\r\n"=0A=
+        ;=0A=
+    static const char mta_closing[] =3D=0A=
+        "</Chaptering>\r\n"=0A=
+        "</ContentInformation>\r\n"=0A=
+        "</SEC:SECMeta>\r\n"=0A=
+        ;=0A=
+=0A=
+    char* buffer =3D 0;=0A=
+    if (ends_with(path, ".avi") || ends_with(path, ".mkv") || =
ends_with(path, ".mpg"))=0A=
+    {=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+        video_thumbnailer* vt=3D0;=0A=
+#endif=0A=
+        int percentage;=0A=
+        int length =3D 100*1024;=0A=
+        char* ptr;=0A=
+=0A=
+        buffer =3D malloc(length+1); /* one for the terminating zero */=0A=
+        if (!buffer)=0A=
+            return ""; /* fail (empty string!) */=0A=
+=0A=
+        ptr =3D buffer;=0A=
+        add_to_buffer(&buffer, &length, &ptr, mta_header, =
strlen(mta_header));=0A=
+=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+        vt =3D video_thumbnailer_create();=0A=
+        vt->thumbnail_image_type =3D Jpeg;=0A=
+#endif=0A=
+        /* Samsung accepts exactly 5 positions nothing more, nothing =
less */=0A=
+        for( percentage =3D 16; percentage < 95; percentage+=3D16 )=0A=
+	{=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+            int rc;=0A=
+            image_data* imgdata =3D =
video_thumbnailer_create_image_data();=0A=
+#endif=0A=
+	    unsigned char* src =3D jpeg_chapter;=0A=
+	    int size =3D sizeof(jpeg_chapter)-1;=0A=
+	    int idx;=0A=
+=0A=
+            add_to_buffer(&buffer, &length, &ptr, mta_chapter_header, =
strlen(mta_chapter_header));=0A=
+=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+=0A=
+            vt->seek_percentage =3D percentage;=0A=
+=0A=
+            DPRINTF(E_DEBUG, L_METADATA, "generating %d%%-thumbnail for =
'%s'\n", percentage, path);=0A=
+            rc =3D video_thumbnailer_generate_thumbnail_to_buffer(vt, =
path, imgdata);=0A=
+            DPRINTF(E_DEBUG, L_METADATA, "rc: %d, thumbnail =
size=3D%d\n", rc, imgdata->image_data_size);=0A=
+=0A=
+            if (!rc && imgdata->image_data_size) {=0A=
+		src =3D imgdata->image_data_ptr;=0A=
+		size =3D imgdata->image_data_size;=0A=
+	    }=0A=
+#endif=0A=
+=0A=
+	    /* base 64 encoding of the image */=0A=
+	    for(idx=3D0; idx < size; idx +=3D 3)=0A=
+	    {=0A=
+		unsigned char r1=3D0, r2=3D0, r3=3D0, b1=3D0, b2=3D0, b3=3D0, b4=3D0;=0A=
+=0A=
+		/* get 3 byte / 24 bit */=0A=
+		r1 =3D src[idx];=0A=
+                    =0A=
+		if (idx+1 < size)=0A=
+		    r2 =3D src[idx+1];=0A=
+=0A=
+		if (idx+2 < size)=0A=
+		    r3 =3D src[idx+2];=0A=
+=0A=
+		/* spread to 4 6-bit parts */=0A=
+		b1 =3D r1 >> 2;=0A=
+		b2 =3D ((r1 & 0x3) << 4) | (r2 >> 4);=0A=
+		b3 =3D ((r2 & 0xf) << 2) | (r3 >> 6);=0A=
+		b4 =3D r3 & 0x3f;=0A=
+=0A=
+		/* encode 6-bit output */=0A=
+		*ptr++ =3D encode_base64(b1);=0A=
+		*ptr++ =3D encode_base64(b2);=0A=
+=0A=
+		if (idx+1 < size)=0A=
+		    *ptr++ =3D encode_base64(b3);=0A=
+		else=0A=
+		    *ptr++ =3D '=3D';=0A=
+		=0A=
+		if (idx+2 < size)=0A=
+		    *ptr++ =3D encode_base64(b4);=0A=
+		else=0A=
+		    *ptr++ =3D '=3D';=0A=
+=0A=
+		/* check buffer size, realloc if necessary */=0A=
+		if (ptr+2 > buffer+length) {=0A=
+		    ptr -=3D (int64_t)buffer;=0A=
+		    adjust_buffer(&buffer, &length);=0A=
+		    ptr +=3D (int64_t)buffer; /* rebase ptr */=0A=
+		}=0A=
+            }=0A=
+=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+            video_thumbnailer_destroy_image_data(imgdata);=0A=
+#endif=0A=
+            /* add time code for this thumbnail */=0A=
+            {=0A=
+                char tmp[sizeof(mta_chapter_closing)+10];=0A=
+                int pos =3D (duration * percentage) / 100;=0A=
+                snprintf(tmp, sizeof(mta_chapter_closing)+10, =
mta_chapter_closing, pos);=0A=
+                add_to_buffer(&buffer, &length, &ptr, tmp, strlen(tmp));=0A=
+            }=0A=
+        }=0A=
+#ifdef THUMBNAIL_CREATION_SUPPORT=0A=
+        video_thumbnailer_destroy(vt);=0A=
+#endif=0A=
+        add_to_buffer(&buffer, &length, &ptr, mta_closing, =
strlen(mta_closing));=0A=
+        *ptr =3D 0; /* terminate buffer! */=0A=
+    }=0A=
+    return buffer;=0A=
+}=0A=
+=0A=
+void=0A=
+SendResp_samsung_mta_file(struct upnphttp * h, char * object)=0A=
+{=0A=
+    char header[1500];=0A=
+    char sql_buf[256];=0A=
+    char **result;=0A=
+    int rows =3D 0;=0A=
+    char *path;=0A=
+    int duration =3D 0;=0A=
+    int sendfh =3D -1; /* default: no accessible mta file */=0A=
+    char *dash;=0A=
+=0A=
+    dash =3D strchr(object, '.');=0A=
+    if( dash )=0A=
+        *dash =3D '\0';=0A=
+=0A=
+    /* get path and duration of video */=0A=
+    sprintf(sql_buf, "select PATH, DURATION from DETAILS where ID =3D =
'%s';", object);=0A=
+    DPRINTF(E_DEBUG, L_HTTP, "Get MTA file SQL: %s\n", sql_buf);=0A=
+    sql_get_table(db, sql_buf, &result, &rows, NULL);=0A=
+    if( !rows )=0A=
+    {=0A=
+        DPRINTF(E_WARN, L_HTTP, "Object ID %s not found, responding =
ERROR 404\n", object);=0A=
+        Send404(h);=0A=
+        goto error;=0A=
+    }=0A=
+    path =3D result[2];=0A=
+    duration =3D (   1 * atoi(rindex(result[3], ':')+1)) +=0A=
+               (  60 * atoi(rindex(result[3], ':')-2)) +=0A=
+               (3600 * atoi(result[3]));=0A=
+=0A=
+    /* Is video (still) accessible? */=0A=
+    if( access(path, F_OK) =3D=3D 0 ) {=0A=
+        time_t curtime =3D time(NULL);=0A=
+        char date[30];=0A=
+        char mta_path[PATH_MAX];=0A=
+        char* body =3D 0;=0A=
+        int size =3D 0;=0A=
+=0A=
+        snprintf(mta_path, sizeof(mta_path), "%s.mta", path);=0A=
+        DPRINTF(E_DEBUG, L_HTTP, "Looking for precalculated MTA file =
'%s'\n", mta_path);=0A=
+        if (access(mta_path, F_OK) =3D=3D 0) { /* mta file accessible ? =
*/=0A=
+            /* read MTA file from file*/=0A=
+            sendfh =3D open(mta_path, O_RDONLY);=0A=
+            if( sendfh < 0 ) {=0A=
+		DPRINTF(E_ERROR, L_HTTP, "Error opening precalculated MTA file =
'%s'\n", mta_path);=0A=
+            } else {=0A=
+                size =3D lseek(sendfh, 0, SEEK_END);=0A=
+                lseek(sendfh, 0, SEEK_SET);=0A=
+                DPRINTF(E_DEBUG, L_HTTP, "Found precalculated MTA file =
with size %d\n", size);=0A=
+            }=0A=
+        }=0A=
+=0A=
+        if (sendfh < 0) {        /* nothing could be read ?*/=0A=
+            /* generate MTA file on-the-fly (may take some time =
especially on slow NAS!) */=0A=
+            DPRINTF(E_INFO, L_HTTP, "Generating MTA file on-the-fly for =
object (ID=3D'%s') on [%s], duration=3D%d\n", object, path, duration);=0A=
+            body =3D generate_samsung_mta_file(path, duration);=0A=
+            if (body)=0A=
+                size =3D strlen(body);=0A=
+            if (!size)=0A=
+                free(body);=0A=
+        }=0A=
+=0A=
+        if (!size) { /* still no data */=0A=
+            Send404(h);=0A=
+            goto error; /* give up */=0A=
+        }=0A=
+=0A=
+        /* create corresponding HTTP header for MTA file request */=0A=
+        memset(header, 0, sizeof(header));=0A=
+        strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , =
gmtime(&curtime));=0A=
+        sprintf(header, "HTTP/1.1 200 OK\r\n"=0A=
+                "Content-Type: image/jpeg\r\n"=0A=
+                "Content-Length: %d\r\n"=0A=
+                "Connection: close\r\n"=0A=
+                "Date: %s\r\n"=0A=
+                "EXT:\r\n"=0A=
+                =
"contentFeatures.dlna.org:DLNA.ORG_OP=3D00;DLNA.ORG_CI=3D0;\r\n"=0A=
+                "Server: " MINIDLNA_SERVER_STRING "\r\n",=0A=
+                size, date);=0A=
+=0A=
+        if( h->reqflags & FLAG_REALTIMEINFO )=0A=
+            strcat(header, "realTimeInfo.dlna.org: =
DLNA.ORG_TLAG=3D*\r\n");=0A=
+=0A=
+        if( h->reqflags & FLAG_XFERBACKGROUND )=0A=
+            strcat(header, "transferMode.dlna.org: Background\r\n");=0A=
+        else=0A=
+            strcat(header, "transferMode.dlna.org: Interactive\r\n");=0A=
+=0A=
+        DPRINTF(E_INFO, L_HTTP, "%s", header);=0A=
+=0A=
+        strcat(header, "\r\n");=0A=
+=0A=
+        /* send header and if ok and not only HEAD request, send body */=0A=
+        if( (send_data(h, header, strlen(header), MSG_MORE) =3D=3D 0) =
&& h->req_command !=3D EHead )=0A=
+        {=0A=
+            if (sendfh < 0)=0A=
+                send_data(h, body, size, 0);=0A=
+            else {=0A=
+                send_file(h, sendfh, 0, size); /* always send complete =
file. No RANGEs */=0A=
+                close(sendfh);=0A=
+            }=0A=
+        }=0A=
+        free(body);=0A=
+    }=0A=
+  error:=0A=
+    sqlite3_free_table(result);=0A=
+}=0A=
diff -urNp upnphttp.h upnphttp.h=0A=
--- upnphttp.h	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnphttp.h	2010-12-16 22:06:19.000000000 +0100=0A=
@@ -110,6 +110,7 @@ struct upnphttp {=0A=
 #define FLAG_MIME_FLAC_FLAC     0x00800000=0A=
 #define FLAG_NO_RESIZE          0x01000000=0A=
 #define FLAG_MS_PFS		0x02000000 // Microsoft PlaysForSure client=0A=
+#define FLAG_MEDIA_INFO         0x04000000=0A=
 =0A=
 /* New_upnphttp() */=0A=
 struct upnphttp *=0A=
@@ -170,5 +171,12 @@ SendResp_thumbnail(struct upnphttp *, ch=0A=
  * send the actual file data for a UPnP-A/V or DLNA request. */=0A=
 void=0A=
 SendResp_dlnafile(struct upnphttp *, char * url);=0A=
+void=0A=
+SendResp_samsung_mta_file(struct upnphttp * h, char * object);=0A=
+void=0A=
+generate_external_samsung_mta_file(const char* path, int duration);=0A=
+char*=0A=
+generate_samsung_mta_file(const char* path, int duration);=0A=
+=0A=
 #endif=0A=
 =0A=
diff -urNp upnpsoap.c upnpsoap.c=0A=
--- upnpsoap.c	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnpsoap.c	2010-12-17 12:21:28.000000000 +0100=0A=
@@ -332,6 +332,12 @@ mime_to_ext(const char * mime, char * bu=0A=
 #define FILTER_UPNP_GENRE                        0x00020000=0A=
 #define FILTER_UPNP_ORIGINALTRACKNUMBER          0x00040000=0A=
 #define FILTER_UPNP_SEARCHCLASS                  0x00080000=0A=
+#define FILTER_SEC				                 0x00100000=0A=
+#define FILTER_SEC_CAPTION_INFO			         0x00200000=0A=
+#define FILTER_SEC_CAPTION_INFO_EX               0x00400000=0A=
+#define FILTER_SEC_DCM_INFO	                     0x00800000=0A=
+#define FILTER_SEC_META_FILE_INFO                0x01000000=0A=
+#define FILTER_PARENT_ID                         0x02000000=0A=
 =0A=
 static u_int32_t=0A=
 set_filter_flags(char * filter, enum client_types client)=0A=
@@ -451,6 +457,30 @@ set_filter_flags(char * filter, enum cli=0A=
 			flags |=3D FILTER_RES;=0A=
 			flags |=3D FILTER_RES_SIZE;=0A=
 		}=0A=
+		else if( strcmp(item, "sec:CaptionInfo") =3D=3D 0)=0A=
+		{=0A=
+			flags |=3D FILTER_SEC;=0A=
+			flags |=3D FILTER_SEC_CAPTION_INFO;=0A=
+		}=0A=
+		else if( strcmp(item, "sec:CaptionInfoEx") =3D=3D 0)=0A=
+		{=0A=
+			flags |=3D FILTER_SEC;=0A=
+			flags |=3D FILTER_SEC_CAPTION_INFO_EX;=0A=
+		}=0A=
+		else if( strcmp(item, "sec:dcmInfo") =3D=3D 0)=0A=
+		{=0A=
+			flags |=3D FILTER_SEC;=0A=
+			flags |=3D FILTER_SEC_DCM_INFO;=0A=
+		}=0A=
+		else if( strcmp(item, "sec:MetaFileInfo") =3D=3D 0)=0A=
+		{=0A=
+			flags |=3D FILTER_SEC;=0A=
+			flags |=3D FILTER_SEC_META_FILE_INFO;=0A=
+		}=0A=
+		else if( strcmp(item, "@parentID") =3D=3D 0 )=0A=
+		{=0A=
+			flags |=3D FILTER_PARENT_ID;=0A=
+		}=0A=
 		item =3D strtok_r(NULL, ",", &saveptr);=0A=
 	}=0A=
 =0A=
@@ -562,7 +592,7 @@ static void add_resized_res(int srcw, in=0A=
 		memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
 		passed_args->size +=3D ret;=0A=
 	}=0A=
-	ret =3D sprintf(str_buf, =
"protocolInfo=3D\"http-get:*:image/jpeg:DLNA.ORG_PN=3D%s;DLNA.ORG_CI=3D1\=
"&gt;"=0A=
+	ret =3D sprintf(str_buf, =
"protocolInfo=3D\"http-get:*:image/jpeg:DLNA.ORG_PN=3D%s;DLNA.ORG_CI=3D1;=
DLNA.ORG_FLAGS=3D01500000000000000000000000000000\"&gt;"=0A=
 	                       =
"http://%s:%d/Resized/%s.jpg?width=3D%d,height=3D%d"=0A=
 	                       "&lt;/res&gt;",=0A=
 	                       dlna_pn, lan_addr[0].str, runtime_vars.port,=0A=
@@ -574,7 +604,7 @@ static void add_resized_res(int srcw, in=0A=
 #define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, =
o.DETAIL_ID, o.CLASS," \=0A=
                        " d.SIZE, d.TITLE, d.DURATION, d.BITRATE, =
d.SAMPLERATE, d.ARTIST," \=0A=
                        " d.ALBUM, d.GENRE, d.COMMENT, d.CHANNELS, =
d.TRACK, d.DATE, d.RESOLUTION," \=0A=
-                       " d.THUMBNAIL, d.CREATOR, d.DLNA_PN, d.MIME, =
d.ALBUM_ART, d.DISC "=0A=
+                       " d.THUMBNAIL, d.CREATOR, d.DLNA_PN, d.MIME, =
d.ALBUM_ART, d.DISC, c.PATH "=0A=
 =0A=
 static int=0A=
 callback(void *args, int argc, char **argv, char **azColName)=0A=
@@ -583,7 +613,7 @@ callback(void *args, int argc, char **ar=0A=
 	char *id =3D argv[0], *parent =3D argv[1], *refID =3D argv[2], =
*detailID =3D argv[3], *class =3D argv[4], *size =3D argv[5], *title =3D =
argv[6],=0A=
 	     *duration =3D argv[7], *bitrate =3D argv[8], *sampleFrequency =3D =
argv[9], *artist =3D argv[10], *album =3D argv[11],=0A=
 	     *genre =3D argv[12], *comment =3D argv[13], *nrAudioChannels =3D =
argv[14], *track =3D argv[15], *date =3D argv[16], *resolution =3D =
argv[17],=0A=
-	     *tn =3D argv[18], *creator =3D argv[19], *dlna_pn =3D argv[20], =
*mime =3D argv[21], *album_art =3D argv[22];=0A=
+	     *tn =3D argv[18], *creator =3D argv[19], *dlna_pn =3D argv[20], =
*mime =3D argv[21], *album_art =3D argv[22], *caption_path =3D argv[24];=0A=
 	char dlna_buf[96];=0A=
 	char ext[5];=0A=
 	char str_buf[512];=0A=
@@ -621,12 +651,23 @@ callback(void *args, int argc, char **ar=0A=
 	if( dlna_pn )=0A=
 		sprintf(dlna_buf, "DLNA.ORG_PN=3D%s", dlna_pn);=0A=
 	else if( passed_args->flags & FLAG_DLNA )=0A=
+    {=0A=
 		strcpy(dlna_buf, dlna_no_conv);=0A=
+        if (passed_args->client =3D=3D ESamsungTV && mime && *mime =
=3D=3D 'v')=0A=
+            strcat(dlna_buf, =
";DLNA.ORG_FLAGS=3D01500000000000000000000000000000");=0A=
+    }=0A=
 	else=0A=
 		strcpy(dlna_buf, "*");=0A=
-=0A=
+#if 0=0A=
+        if ( date && passed_args->client =3D=3D ESamsungTV )=0A=
+            *rindex(date, 'T') =3D 0;=0A=
+#endif=0A=
 	if( strncmp(class, "item", 4) =3D=3D 0 )=0A=
 	{=0A=
+#if 0=0A=
+        if( duration && passed_args->client =3D=3D ESamsungTV )=0A=
+            *rindex(duration, '.') =3D 0;=0A=
+#endif=0A=
 		/* We may need special handling for certain MIME types */=0A=
 		if( *mime =3D=3D 'v' )=0A=
 		{=0A=
@@ -640,7 +681,7 @@ callback(void *args, int argc, char **ar=0A=
 						strcpy(mime+6, "avi");=0A=
 				}=0A=
 			}=0A=
-			else if( passed_args->flags & FLAG_MIME_AVI_AVI )=0A=
+			else if( passed_args->flags & FLAG_MIME_AVI_AVI && =
passed_args->client !=3D ESamsungTV)=0A=
 			{=0A=
 				if( strcmp(mime, "video/x-msvideo") =3D=3D 0 )=0A=
 				{=0A=
@@ -711,6 +752,31 @@ callback(void *args, int argc, char **ar=0A=
 			memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
 			passed_args->size +=3D ret;=0A=
 		}=0A=
+		if( passed_args->filter & FILTER_SEC_CAPTION_INFO_EX) {=0A=
+            /* Get bookmark */=0A=
+            int posSecond =3D sql_get_int_field(db, "SELECT BOOKMARK =
from OBJECTS where OBJECT_ID =3D '%s';", id);=0A=
+            ret =3D sprintf(str_buf, =
"&lt;sec:dcmInfo&gt;CREATIONDATE=3D0,FOLDER=3D%s,BM=3D%d&lt;/sec:dcmInfo&=
gt;", parent, posSecond);=0A=
+            memcpy(passed_args->resp+passed_args->size, &str_buf, =
ret+1);=0A=
+            passed_args->size +=3D ret;=0A=
+		}=0A=
+ 		if( caption_path && passed_args->filter & =
FILTER_SEC_CAPTION_INFO_EX) {=0A=
+			char * caption_ext;=0A=
+			caption_ext =3D strrchr(caption_path, '.');=0A=
+			if( caption_ext ) {=0A=
+				++caption_ext;=0A=
+				ret =3D sprintf(str_buf, "&lt;sec:CaptionInfoEx =
sec:type=3D&quot;%s&quot;&gt;http://%s:%d/Captions/%s.%s&lt;/sec:CaptionI=
nfoEx&gt;",=0A=
+					          caption_ext, lan_addr[0].str, runtime_vars.port, =
detailID, caption_ext);=0A=
+			    memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+			    passed_args->size +=3D ret;=0A=
+			}=0A=
+		}=0A=
+		if( passed_args->filter & FILTER_SEC_META_FILE_INFO) {=0A=
+            /* Advertise chapter data */=0A=
+			ret =3D sprintf(str_buf, "&lt;sec:MetaFileInfo =
sec:type=3D&quot;mta&quot;&gt;http://%s:%d/MTA/%s.mta&lt;/sec:MetaFileInf=
o&gt;",=0A=
+                                      lan_addr[0].str, =
runtime_vars.port, detailID);=0A=
+			memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+			passed_args->size +=3D ret;=0A=
+		}=0A=
 		if( artist && (passed_args->filter & FILTER_UPNP_ARTIST) ) {=0A=
 			ret =3D snprintf(str_buf, 512, =
"&lt;upnp:artist&gt;%s&lt;/upnp:artist&gt;", artist);=0A=
 			memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
@@ -780,17 +846,18 @@ callback(void *args, int argc, char **ar=0A=
 			passed_args->size +=3D ret;=0A=
 		}=0A=
 #endif=0A=
+		/* <res>-tag for actual item */=0A=
 		if( passed_args->filter & FILTER_RES ) {=0A=
 			mime_to_ext(mime, ext);=0A=
 			if( (passed_args->client =3D=3D EFreeBox) && tn && atoi(tn) ) {=0A=
 				ret =3D sprintf(str_buf, "&lt;res =
protocolInfo=3D\"http-get:*:%s:%s\"&gt;"=0A=
 				                       "http://%s:%d/Thumbnails/%s.jpg"=0A=
 				                       "&lt;/res&gt;",=0A=
-				                       mime, "DLNA.ORG_PN=3DJPEG_TN", =
lan_addr[0].str, runtime_vars.port, detailID);=0A=
+ 				                       mime, =
"DLNA.ORG_PN=3DJPEG_TN;DLNA.ORG_CI=3D1", lan_addr[0].str, =
runtime_vars.port, detailID);=0A=
 				memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
 				passed_args->size +=3D ret;=0A=
 			}=0A=
-			ret =3D sprintf(str_buf, "&lt;res ");=0A=
+ 			ret =3D sprintf(str_buf, "&lt;res ");=0A=
 			memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
 			passed_args->size +=3D ret;=0A=
 			if( size && (passed_args->filter & FILTER_RES_SIZE) ) {=0A=
@@ -847,12 +914,51 @@ callback(void *args, int argc, char **ar=0A=
 					ret =3D sprintf(str_buf, "&lt;res =
protocolInfo=3D\"http-get:*:%s:%s\"&gt;"=0A=
 					                       "http://%s:%d/Thumbnails/%s.jpg"=0A=
 					                       "&lt;/res&gt;",=0A=
-					                       mime, "DLNA.ORG_PN=3DJPEG_TN", =
lan_addr[0].str, runtime_vars.port, detailID);=0A=
+					                       mime, =
"DLNA.ORG_PN=3DJPEG_TN;DLNA.ORG_CI=3D1;DLNA.ORG_FLAGS=3D01500000000000000=
000000000000000", lan_addr[0].str, runtime_vars.port, detailID);=0A=
 					memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
 					passed_args->size +=3D ret;=0A=
 				}=0A=
 			}=0A=
 		}=0A=
+=0A=
+                /* additional <res>-tags for thumbnails, etc. */=0A=
+		if( album_art && atoi(album_art) )=0A=
+		{=0A=
+			/* Video and audio album art is handled differently */=0A=
+			if( *mime =3D=3D 'v' && (passed_args->filter & FILTER_RES) && =
(passed_args->client !=3D EXbox) )=0A=
+			{=0A=
+                                if( passed_args->client =3D=3D =
ESamsungTV ) {=0A=
+                                    ret =3D sprintf(str_buf, "&lt;res =
protocolInfo=3D\"http-get:*:image/jpeg:DLNA.ORG_PN=3DJPEG_SM;DLNA.ORG_CI=3D=
1;DLNA.ORG_FLAGS=3D00D00000000000000000000000000000\"&gt;"=0A=
+                                                           =
"http://%s:%d/AlbumArt/%s-%s.jpg"=0A=
+				                           "&lt;/res&gt;",=0A=
+				                           lan_addr[0].str, runtime_vars.port, =
album_art, detailID);=0A=
+                                    =
memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+                                    passed_args->size +=3D ret;=0A=
+                                }=0A=
+				ret =3D sprintf(str_buf, "&lt;res =
protocolInfo=3D\"http-get:*:image/jpeg:DLNA.ORG_PN=3DJPEG_TN;DLNA.ORG_CI=3D=
1;DLNA.ORG_FLAGS=3D00D00000000000000000000000000000\"&gt;"=0A=
+				                       "http://%s:%d/AlbumArt/%s-%s.jpg"=0A=
+				                       "&lt;/res&gt;",=0A=
+				                       lan_addr[0].str, runtime_vars.port, =
album_art, detailID);=0A=
+				memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+				passed_args->size +=3D ret;=0A=
+			}=0A=
+			else if( passed_args->filter & FILTER_UPNP_ALBUMARTURI )=0A=
+			{=0A=
+				ret =3D sprintf(str_buf, "&lt;upnp:albumArtURI ");=0A=
+				memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+				passed_args->size +=3D ret;=0A=
+				if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) {=0A=
+					ret =3D sprintf(str_buf, "dlna:profileID=3D\"%s\" =
xmlns:dlna=3D\"urn:schemas-dlna-org:metadata-1-0/\"", "JPEG_TN");=0A=
+					memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+					passed_args->size +=3D ret;=0A=
+				}=0A=
+				ret =3D sprintf(str_buf, =
"&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",=0A=
+						 lan_addr[0].str, runtime_vars.port, album_art, detailID);=0A=
+				memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
+				passed_args->size +=3D ret;=0A=
+			}=0A=
+		}=0A=
+=0A=
 		ret =3D sprintf(str_buf, "&lt;/item&gt;");=0A=
 	}=0A=
 	else if( strncmp(class, "container", 9) =3D=3D 0 )=0A=
@@ -884,7 +990,7 @@ callback(void *args, int argc, char **ar=0A=
 		ret =3D snprintf(str_buf, 512, "&gt;"=0A=
 		                             "&lt;dc:title&gt;%s&lt;/dc:title&gt;"=0A=
 		                             =
"&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",=0A=
-		                             title, class);=0A=
+                                     title, (passed_args->client =3D=3D =
ESamsungTV ? "container" : class));=0A=
 		memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);=0A=
 		passed_args->size +=3D ret;=0A=
 		if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {=0A=
@@ -954,7 +1060,7 @@ BrowseContentDirectory(struct upnphttp *=0A=
 	int StartingIndex =3D 0;=0A=
 	if( (ptr =3D GetValueFromNameValueList(&data, "RequestedCount")) )=0A=
 		RequestedCount =3D atoi(ptr);=0A=
-	if( !RequestedCount )=0A=
+	if( !RequestedCount)=0A=
 		RequestedCount =3D -1;=0A=
 	if( (ptr =3D GetValueFromNameValueList(&data, "StartingIndex")) )=0A=
 		StartingIndex =3D atoi(ptr);=0A=
@@ -979,12 +1085,18 @@ BrowseContentDirectory(struct upnphttp *=0A=
 	args.size =3D sprintf(resp, "%s", resp0);=0A=
 	/* See if we need to include DLNA namespace reference */=0A=
 	args.filter =3D set_filter_flags(Filter, h->req_client);=0A=
-	if( args.filter & FILTER_DLNA_NAMESPACE )=0A=
+	if( args.filter & FILTER_DLNA_NAMESPACE || h->req_client =3D=3D =
ESamsungTV )=0A=
 	{=0A=
 		ret =3D sprintf(str_buf, DLNA_NAMESPACE);=0A=
 		memcpy(resp+args.size, &str_buf, ret+1);=0A=
 		args.size +=3D ret;=0A=
 	}=0A=
+	if ( h->req_client =3D=3D ESamsungTV )=0A=
+	{=0A=
+		ret =3D sprintf(str_buf, SEC_NAMESPACE);=0A=
+		memcpy(resp+args.size, &str_buf, ret+1);=0A=
+		args.size +=3D ret;=0A=
+	}=0A=
 	ret =3D sprintf(str_buf, "&gt;\n");=0A=
 	memcpy(resp+args.size, &str_buf, ret+1);=0A=
 	args.size +=3D ret;=0A=
@@ -1011,6 +1123,11 @@ BrowseContentDirectory(struct upnphttp *=0A=
 				ObjectId =3D sqlite3_mprintf("%s", ObjectId);=0A=
 		}=0A=
 	}=0A=
+    if (h->req_client =3D=3D ESamsungTV )=0A=
+	{=0A=
+		if( strcmp(ObjectId, "V_T") =3D=3D 0 )=0A=
+			ObjectId =3D strdup(VIDEO_DIR_ID);=0A=
+	}=0A=
 	DPRINTF(E_DEBUG, L_HTTP, "Browsing ContentDirectory:\n"=0A=
 	                         " * ObjectID: %s\n"=0A=
 	                         " * Count: %d\n"=0A=
@@ -1021,11 +1138,32 @@ BrowseContentDirectory(struct upnphttp *=0A=
 				ObjectId, RequestedCount, StartingIndex,=0A=
 	                        BrowseFlag, Filter, SortCriteria);=0A=
 =0A=
-	if( strcmp(BrowseFlag+6, "Metadata") =3D=3D 0 )=0A=
+   if ( args.client =3D=3D ESamsungTV && !StartingIndex &&=0A=
+        RequestedCount =3D=3D -1/* && args.filter =3D=3D =
FILTER_PARENT_ID*/ )=0A=
+   {=0A=
+       /* Samsung tries to search @parentID only */=0A=
+       char *parentID =3D strdup(ObjectId);=0A=
+       char *pos =3D rindex(ObjectId, '$');=0A=
+       if (pos)=0A=
+           *pos =3D 0;=0A=
+=0A=
+       sql =3D sqlite3_mprintf( SELECT_COLUMNS=0A=
+		                      "from OBJECTS o left join DETAILS d on (d.ID =
=3D o.DETAIL_ID)"=0A=
+		                      " left join CAPTIONS c on (c.ID =3D =
o.DETAIL_ID)"=0A=
+				              " where OBJECT_ID =3D '%s' %s limit %d, %d;",=0A=
+				              parentID, orderBy, StartingIndex, StartingIndex+1);=0A=
+       DPRINTF(E_DEBUG, L_HTTP, "Browse SQL: %s\n", sql);=0A=
+       ret =3D sqlite3_exec(db, sql, callback, (void *) &args, =
&zErrMsg);=0A=
+=0A=
+       totalMatches =3D args.returned;=0A=
+       free(parentID);=0A=
+    }=0A=
+    else if( strcmp(BrowseFlag+6, "Metadata") =3D=3D 0 )=0A=
 	{=0A=
 		args.requested =3D 1;=0A=
 		sql =3D sqlite3_mprintf( SELECT_COLUMNS=0A=
 		                      "from OBJECTS o left join DETAILS d on (d.ID =
=3D o.DETAIL_ID)"=0A=
+                              " left join CAPTIONS c on (c.ID =3D =
o.DETAIL_ID)"=0A=
 		                      " where OBJECT_ID =3D '%s';"=0A=
 		                      , ObjectId);=0A=
 		ret =3D sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);=0A=
@@ -1062,17 +1200,20 @@ BrowseContentDirectory(struct upnphttp *=0A=
 =0A=
 		sql =3D sqlite3_mprintf( SELECT_COLUMNS=0A=
 		                      "from OBJECTS o left join DETAILS d on (d.ID =
=3D o.DETAIL_ID)"=0A=
+		                      " left join CAPTIONS c on (c.ID =3D =
o.DETAIL_ID)"=0A=
 				      " where PARENT_ID =3D '%s' %s limit %d, %d;",=0A=
 				      ObjectId, orderBy, StartingIndex, RequestedCount);=0A=
 		DPRINTF(E_DEBUG, L_HTTP, "Browse SQL: %s\n", sql);=0A=
 		ret =3D sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);=0A=
 	}=0A=
+	if (sql) {=0A=
 	sqlite3_free(sql);=0A=
 	if( (ret !=3D SQLITE_OK) && (zErrMsg !=3D NULL) )=0A=
 	{=0A=
 		DPRINTF(E_WARN, L_HTTP, "SQL error: %s\nBAD SQL: %s\n", zErrMsg, sql);=0A=
 		sqlite3_free(zErrMsg);=0A=
 	}=0A=
+	}=0A=
 	/* Does the object even exist? */=0A=
 	if( !totalMatches )=0A=
 	{=0A=
@@ -1157,12 +1298,18 @@ SearchContentDirectory(struct upnphttp *=0A=
 	args.size =3D sprintf(resp, "%s", resp0);=0A=
 	/* See if we need to include DLNA namespace reference */=0A=
 	args.filter =3D set_filter_flags(Filter, h->req_client);=0A=
-	if( args.filter & FILTER_DLNA_NAMESPACE )=0A=
+	if( args.filter & FILTER_DLNA_NAMESPACE || h->req_client =3D=3D =
ESamsungTV )=0A=
 	{=0A=
 		ret =3D sprintf(str_buf, DLNA_NAMESPACE);=0A=
 		memcpy(resp+args.size, &str_buf, ret+1);=0A=
 		args.size +=3D ret;=0A=
 	}=0A=
+	if ( h->req_client =3D=3D ESamsungTV )=0A=
+	{=0A=
+		ret =3D sprintf(str_buf, SEC_NAMESPACE);=0A=
+		memcpy(resp+args.size, &str_buf, ret+1);=0A=
+		args.size +=3D ret;=0A=
+	}=0A=
 	ret =3D sprintf(str_buf, "&gt;\n");=0A=
 	memcpy(resp+args.size, &str_buf, ret+1);=0A=
 	args.size +=3D ret;=0A=
@@ -1307,6 +1454,7 @@ SearchContentDirectory(struct upnphttp *=0A=
 =0A=
 	sql =3D sqlite3_mprintf( SELECT_COLUMNS=0A=
 	                      "from OBJECTS o left join DETAILS d on (d.ID =3D =
o.DETAIL_ID)"=0A=
+	                      " left join CAPTIONS c on (c.ID =3D o.DETAIL_ID)"=0A=
 	                      " where OBJECT_ID glob '%s$*' and (%s) %s "=0A=
 	                      "%z %s"=0A=
 	                      " limit %d, %d",=0A=
@@ -1314,6 +1462,7 @@ SearchContentDirectory(struct upnphttp *=0A=
 	                      (*ContainerID =3D=3D '*') ? NULL :=0A=
                               sqlite3_mprintf("UNION ALL " =
SELECT_COLUMNS=0A=
 	                                      "from OBJECTS o left join =
DETAILS d on (d.ID =3D o.DETAIL_ID)"=0A=
+                                          " left join CAPTIONS c on =
(c.ID =3D o.DETAIL_ID)"=0A=
 	                                      " where OBJECT_ID =3D '%s' and =
(%s) ", ContainerID, SearchCriteria),=0A=
 	                      orderBy, StartingIndex, RequestedCount);=0A=
 	DPRINTF(E_DEBUG, L_HTTP, "Search SQL: %s\n", sql);=0A=
@@ -1396,6 +1545,82 @@ QueryStateVariable(struct upnphttp * h, =0A=
 	ClearNameValueList(&data);	=0A=
 }=0A=
 =0A=
+=0A=
+static void=0A=
+SamsungGetFeatureList(struct upnphttp * h, const char * action)=0A=
+{=0A=
+	static const char resp[] =3D=0A=
+		"<u:X_GetFeatureListResponse =
xmlns:u=3D\"urn:schemas-upnp-org:service:ContentDirectory:1\">"=0A=
+		"<FeatureList>"=0A=
+		"&lt;?xml version=3D&quot;1.0&quot; encoding=3D&quot;UTF-8&quot;?&gt;"=0A=
+		"&lt;Features xmlns=3D&quot;urn:schemas-upnp-org:av:avs&quot; "=0A=
+		  "xmlns:xsi=3D&quot;http://www.w3.org/2001/XMLSchema-instance&quot; "=0A=
+		  "xsi:schemaLocation=3D&quot; urn:schemas-upnp-org:av:avs "=0A=
+		  "http://www.upnp.org/schemas/av/avs.xsd&quot;&gt;"=0A=
+		"&lt;Feature name=3D&quot;samsung.com_BASICVIEW&quot; =
version=3D&quot;1&quot;&gt;"=0A=
+		"&lt;container id=3D&quot;2&quot; =
type=3D&quot;object.item.videoItem&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;1&quot; =
type=3D&quot;object.item.audioItem&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;3&quot; =
type=3D&quot;object.item.imageItem&quot;/&gt;"=0A=
+		"&lt;/Feature&gt;"=0A=
+		"&lt;Feature name=3D&quot;samsung.com_DCMVIEW&quot; =
version=3D&quot;1&quot;&gt;"=0A=
+/*		"&lt;container id=3D&quot;I_M&quot; =
type=3D&quot;IMAGE_Monthly&quot;/&gt;" */=0A=
+/*		"&lt;container id=3D&quot;I_C&quot; =
type=3D&quot;IMAGE_Color&quot;/&gt;" */=0A=
+		"&lt;container id=3D&quot;3$12&quot; =
type=3D&quot;IMAGE_Timeline&quot;/&gt;"=0A=
+/*		"&lt;container id=3D&quot;I_P&quot; =
type=3D&quot;IMAGE_Composition&quot;/&gt;" */=0A=
+                "&lt;container id=3D&quot;" IMAGE_DIR_ID "&quot; =
type=3D&quot;IMAGE_Folder&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;3$11&quot; =
type=3D&quot;IMAGE_Title&quot;/&gt;"=0A=
+/*		"&lt;container id=3D&quot;I_L&quot; =
type=3D&quot;IMAGE_LatestDate&quot;/&gt;" */=0A=
+/*		"&lt;container id=3D&quot;I_E&quot; =
type=3D&quot;IMAGE_EarliestDate&quot;/&gt;" */=0A=
+		"&lt;container id=3D&quot;1$5&quot; =
type=3D&quot;AUDIO_Genre&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;1$6&quot; =
type=3D&quot;AUDIO_Artist&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;" MUSIC_DIR_ID "&quot; =
type=3D&quot;AUDIO_Folder&quot;/&gt;"=0A=
+/*		"&lt;container id=3D&quot;A_M&quot; =
type=3D&quot;AUDIO_Mood&quot;/&gt;" */=0A=
+		"&lt;container id=3D&quot;1$4&quot; =
type=3D&quot;AUDIO_Title&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;1$7&quot; =
type=3D&quot;AUDIO_Album&quot;/&gt;"=0A=
+		"&lt;container id=3D&quot;2$8&quot; =
type=3D&quot;VIDEO_Title&quot;/&gt;"=0A=
+/*		"&lt;container id=3D&quot;V_D&quot; =
type=3D&quot;VIDEO_Date&quot;/&gt;" */=0A=
+		"&lt;container id=3D&quot;" VIDEO_DIR_ID "&quot; =
type=3D&quot;VIDEO_Folder&quot;/&gt;"=0A=
+/*		"&lt;container id=3D&quot;V_L&quot; =
type=3D&quot;VIDEO_LatestDate&quot;/&gt;" */=0A=
+/*		"&lt;container id=3D&quot;V_E&quot; =
type=3D&quot;VIDEO_EarliestDate&quot;/&gt;" */=0A=
+		"&lt;/Feature&gt;"=0A=
+		"&lt;/Features&gt;"=0A=
+		"</FeatureList></u:X_GetFeatureListResponse>";=0A=
+=0A=
+	char body[4096];=0A=
+	int bodylen;=0A=
+=0A=
+	bodylen =3D snprintf(body, sizeof(body), resp);=0A=
+	BuildSendAndCloseSoapResp(h, body, bodylen);=0A=
+}=0A=
+=0A=
+static void=0A=
+SamsungSetBookmark(struct upnphttp * h, const char * action)=0A=
+{=0A=
+	static const char resp[] =3D=0A=
+            "<s:Envelope =
xmlns:s=3D\"http://schemas.xmlsoap.org/soap/envelope/\""=0A=
+            " =
s:encodingStyle=3D\"http://schemas.xmlsoap.org/soap/encoding/\">"=0A=
+            "<s:Body><u:X_SetBookmarkResponse"=0A=
+            " =
xmlns:u=3D\"urn:schemas-upnp-org:service:ContentDirectory:1\">"=0A=
+            "</u:X_SetBookmarkResponse></s:Body></s:Envelope>";=0A=
+=0A=
+	char body[512];=0A=
+	int bodylen;=0A=
+	struct NameValueParserData data;=0A=
+=0A=
+	ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, =
&data);=0A=
+	char* ObjectID  =3D GetValueFromNameValueList(&data, "ObjectID");=0A=
+	char* PosSecond =3D GetValueFromNameValueList(&data, "PosSecond");=0A=
+        if (!atoi(PosSecond))=0A=
+            PosSecond=3D"";=0A=
+=0A=
+        /* store Bookmark into OBJECTS */=0A=
+        if( sql_exec(db, "UPDATE OBJECTS set BOOKMARK =3D %d where =
OBJECT_ID=3D'%s'", atoi(PosSecond), ObjectID) !=3D SQLITE_OK )=0A=
+            DPRINTF(E_WARN, L_METADATA, "Error setting bookmark %d on =
objectId=3D'%s'\n", atoi(PosSecond), ObjectID);=0A=
+=0A=
+	bodylen =3D snprintf(body, sizeof(body), resp);=0A=
+	BuildSendAndCloseSoapResp(h, body, bodylen);=0A=
+}=0A=
+=0A=
 static const struct =0A=
 {=0A=
 	const char * methodName; =0A=
@@ -1414,6 +1639,8 @@ soapMethods[] =3D=0A=
 	{ "GetCurrentConnectionInfo", GetCurrentConnectionInfo},=0A=
 	{ "IsAuthorized", IsAuthorizedValidated},=0A=
 	{ "IsValidated", IsAuthorizedValidated},=0A=
+	{ "X_GetFeatureList", SamsungGetFeatureList},=0A=
+	{ "X_SetBookmark", SamsungSetBookmark},=0A=
 	{ 0, 0 }=0A=
 };=0A=
 =0A=
diff -urNp upnpsoap.h upnpsoap.h=0A=
--- upnpsoap.h	2010-12-16 21:26:22.000000000 +0100=0A=
+++ upnpsoap.h	2010-12-16 22:03:06.000000000 +0100=0A=
@@ -24,9 +24,11 @@=0A=
 #define MAX_RESPONSE_SIZE 1048576=0A=
 =0A=
 #define CONTENT_DIRECTORY_SCHEMAS \=0A=
+	" xmlns=3D\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\"" \=0A=
 	" xmlns:dc=3D\"http://purl.org/dc/elements/1.1/\"" \=0A=
-	" xmlns:upnp=3D\"urn:schemas-upnp-org:metadata-1-0/upnp/\"" \=0A=
-	" xmlns=3D\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\""=0A=
+	" xmlns:upnp=3D &apos;urn:schemas-upnp-org:metadata-1-0/upnp/&apos;"=0A=
+#define SEC_NAMESPACE \=0A=
+	" xmlns:sec=3D\"http://www.sec.co.kr/\""=0A=
 #define DLNA_NAMESPACE \=0A=
 	" xmlns:dlna=3D\"urn:schemas-dlna-org:metadata-1-0/\""=0A=
 =0A=

------=_NextPart_000_0052_01CBC461.BB9AB060--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?8BD2DD27A14C43D39338545577C89A74>