--- a/metadata.c
+++ b/metadata.c
@@ -1,1567 +1,406 @@
-/* MiniDLNA media server
- * Copyright (C) 2008-2009  Justin Maggard
+/*  MiniDLNA media server
+ *  Copyright (C) 2008  Justin Maggard
  *
- * This file is part of MiniDLNA.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * MiniDLNA is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
  *
- * MiniDLNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include "config.h"
-
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
-#include <libgen.h>
-#include <unistd.h>
 #include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <fcntl.h>
-
+
+#include <sqlite3.h>
+#include <taglib/tag_c.h>
 #include <libexif/exif-loader.h>
-#include <jpeglib.h>
-#include <setjmp.h>
-#include "libav.h"
 
 #include "upnpglobalvars.h"
-#include "tagutils/tagutils.h"
-#include "image_utils.h"
-#include "upnpreplyparse.h"
-#include "tivo_utils.h"
 #include "metadata.h"
-#include "albumart.h"
-#include "utils.h"
-#include "sql.h"
-#include "log.h"
-
-#define FLAG_TITLE	0x00000001
-#define FLAG_ARTIST	0x00000002
-#define FLAG_ALBUM	0x00000004
-#define FLAG_GENRE	0x00000008
-#define FLAG_COMMENT	0x00000010
-#define FLAG_CREATOR	0x00000020
-#define FLAG_DATE	0x00000040
-#define FLAG_DLNA_PN	0x00000080
-#define FLAG_MIME	0x00000100
-#define FLAG_DURATION	0x00000200
-#define FLAG_RESOLUTION	0x00000400
-
-/* Audio profile flags */
-enum audio_profiles {
-	PROFILE_AUDIO_UNKNOWN,
-	PROFILE_AUDIO_MP3,
-	PROFILE_AUDIO_AC3,
-	PROFILE_AUDIO_WMA_BASE,
-	PROFILE_AUDIO_WMA_FULL,
-	PROFILE_AUDIO_WMA_PRO,
-	PROFILE_AUDIO_MP2,
-	PROFILE_AUDIO_PCM,
-	PROFILE_AUDIO_AAC,
-	PROFILE_AUDIO_AAC_MULT5,
-	PROFILE_AUDIO_AMR
-};
-
-/* This function shamelessly copied from libdlna */
-#define MPEG_TS_SYNC_CODE 0x47
-#define MPEG_TS_PACKET_LENGTH 188
-#define MPEG_TS_PACKET_LENGTH_DLNA 192 /* prepends 4 bytes to TS packet */
-int
-dlna_timestamp_is_present(const char *filename, int *raw_packet_size)
-{
-	unsigned char buffer[3*MPEG_TS_PACKET_LENGTH_DLNA];
-	int fd, i;
-
-	/* read file header */
-	fd = open(filename, O_RDONLY);
-	if( fd < 0 )
-		return 0;
-	i = read(fd, buffer, MPEG_TS_PACKET_LENGTH_DLNA*3);
-	close(fd);
-	if( i < 0 )
-		return 0;
-	for( i = 0; i < MPEG_TS_PACKET_LENGTH_DLNA; i++ )
-	{
-		if( buffer[i] == MPEG_TS_SYNC_CODE )
-		{
-			if (buffer[i + MPEG_TS_PACKET_LENGTH_DLNA] == MPEG_TS_SYNC_CODE &&
-			    buffer[i + MPEG_TS_PACKET_LENGTH_DLNA*2] == MPEG_TS_SYNC_CODE)
-			{
-			        *raw_packet_size = MPEG_TS_PACKET_LENGTH_DLNA;
-				if (buffer[i+MPEG_TS_PACKET_LENGTH] == 0x00 &&
-				    buffer[i+MPEG_TS_PACKET_LENGTH+1] == 0x00 &&
-				    buffer[i+MPEG_TS_PACKET_LENGTH+2] == 0x00 &&
-				    buffer[i+MPEG_TS_PACKET_LENGTH+3] == 0x00)
-					return 0;
-				else
-					return 1;
-			} else if (buffer[i + MPEG_TS_PACKET_LENGTH] == MPEG_TS_SYNC_CODE &&
-				   buffer[i + MPEG_TS_PACKET_LENGTH*2] == MPEG_TS_SYNC_CODE) {
-			    *raw_packet_size = MPEG_TS_PACKET_LENGTH;
-			    return 0;
-			}
-		}
-	}
-	*raw_packet_size = 0;
-	return 0;
+
+#define FLAG_ARTIST 0x01
+
+char *
+trim(char *str)
+{
+        if (!str)
+                return(NULL);
+        int i;
+        for (i=0; i <= strlen(str) && (isspace(str[i]) || str[i] == '"'); i++) {
+		str++;
+	}
+        for (i=(strlen(str)-1); i >= 0 && (isspace(str[i]) || str[i] == '"'); i--) {
+                str[i] = '\0';
+        }
+        return str;
+}
+
+char *
+modifyString(char * string, const char * before, const char * after, short like)
+{
+	int oldlen, newlen, chgcnt = 0;
+	char *s, *p, *t;
+
+	oldlen = strlen(before);
+	newlen = strlen(after);
+	if( newlen > oldlen )
+	{
+		s = string;
+		while( (p = strstr(s, before)) )
+		{
+			chgcnt++;
+			s = p+oldlen;
+		}
+		string = realloc(string, strlen(string)+((newlen-oldlen)*chgcnt)+1);
+	}
+
+	s = string;
+	while( s )
+	{
+		p = strcasestr(s, before);
+		if( !p )
+			return string;
+		if( like )
+		{
+			t = p+oldlen;
+			while( isspace(*t) )
+				t++;
+			if( *t == '"' )
+				while( *++t != '"' )
+					continue;
+			memmove(t+1, t, strlen(t)+1);
+			*t = '%';
+		}
+		memmove(p + newlen, p + oldlen, strlen(p + oldlen) + 1);
+		memcpy(p, after, newlen);
+		s = p + newlen;
+	}
+	if( newlen < oldlen )
+		string = realloc(string, strlen(string)+1);
+
+	return string;
 }
 
 void
-check_for_captions(const char *path, int64_t detailID)
-{
-	char file[MAXPATHLEN];
-	char *p;
-	int ret;
-
-	strncpyt(file, path, sizeof(file));
-	p = strip_ext(file);
-	if (!p)
-		p = strrchr(file, '\0');
-
-	/* If we weren't given a detail ID, look for one. */
-	if (!detailID)
-	{
-		detailID = sql_get_int64_field(db, "SELECT ID from DETAILS where (PATH > '%q.' and PATH <= '%q.z')"
-		                            " and MIME glob 'video/*' limit 1", file, file);
-		if (detailID <= 0)
-		{
-			//DPRINTF(E_MAXDEBUG, L_METADATA, "No file found for caption %s.\n", path);
-			return;
-		}
-	}
-
-	strcpy(p, ".srt");
-	ret = access(file, R_OK);
-	if (ret != 0)
-	{
-		strcpy(p, ".smi");
-		ret = access(file, R_OK);
-	}
-
-	if (ret == 0)
-	{
-		sql_exec(db, "INSERT OR REPLACE into CAPTIONS"
-		             " (ID, PATH) "
-		             "VALUES"
-		             " (%lld, %Q)", detailID, file);
-	}
-}
-
-void
-parse_nfo(const char *path, metadata_t *m)
-{
-	FILE *nfo;
-	char buf[65536];
-	struct NameValueParserData xml;
+strip_ext(char * name)
+{
+	if( rindex(name, '.') )
+		*rindex(name, '.') = '\0';
+}
+
+sqlite_int64
+GetAudioMetadata(const char * path, char * name)
+{
+	size_t size = 0;
+	char date[16], duration[16], dlna_pn[24], mime[16];
 	struct stat file;
-	size_t nread;
-	char *val, *val2;
-
-	if( stat(path, &file) != 0 ||
-	    file.st_size > 65536 )
-	{
-		DPRINTF(E_INFO, L_METADATA, "Not parsing very large .nfo file %s\n", path);
-		return;
-	}
-	DPRINTF(E_DEBUG, L_METADATA, "Parsing .nfo file: %s\n", path);
-	nfo = fopen(path, "r");
-	if( !nfo )
-		return;
-	nread = fread(&buf, 1, sizeof(buf), nfo);
-	
-	ParseNameValue(buf, nread, &xml, 0);
-
-	//printf("\ttype: %s\n", GetValueFromNameValueList(&xml, "rootElement"));
-	val = GetValueFromNameValueList(&xml, "title");
-	if( val )
-	{
-		char *esc_tag, *title;
-		val2 = GetValueFromNameValueList(&xml, "episodetitle");
-		if( val2 )
-			xasprintf(&title, "%s - %s", val, val2);
-		else
-			title = strdup(val);
-		esc_tag = unescape_tag(title, 1);
-		m->title = escape_tag(esc_tag, 1);
-		free(esc_tag);
-		free(title);
-	}
-
-	val = GetValueFromNameValueList(&xml, "plot");
-	if( val ) {
-		char *esc_tag = unescape_tag(val, 1);
-		m->comment = escape_tag(esc_tag, 1);
-		free(esc_tag);
-	}
-
-	val = GetValueFromNameValueList(&xml, "capturedate");
-	if( val ) {
-		char *esc_tag = unescape_tag(val, 1);
-		m->date = escape_tag(esc_tag, 1);
-		free(esc_tag);
-	}
-
-	val = GetValueFromNameValueList(&xml, "genre");
-	if( val )
-	{
-		free(m->genre);
-		char *esc_tag = unescape_tag(val, 1);
-		m->genre = escape_tag(esc_tag, 1);
-		free(esc_tag);
-	}
-
-	val = GetValueFromNameValueList(&xml, "mime");
-	if( val )
-	{
-		free(m->mime);
-		char *esc_tag = unescape_tag(val, 1);
-		m->mime = escape_tag(esc_tag, 1);
-		free(esc_tag);
-	}
-
-	ClearNameValueList(&xml);
-	fclose(nfo);
-}
-
-void
-free_metadata(metadata_t *m, uint32_t flags)
-{
-	if( flags & FLAG_TITLE )
-		free(m->title);
-	if( flags & FLAG_ARTIST )
-		free(m->artist);
-	if( flags & FLAG_ALBUM )
-		free(m->album);
-	if( flags & FLAG_GENRE )
-		free(m->genre);
-	if( flags & FLAG_CREATOR )
-		free(m->creator);
-	if( flags & FLAG_DATE )
-		free(m->date);
-	if( flags & FLAG_COMMENT )
-		free(m->comment);
-	if( flags & FLAG_DLNA_PN )
-		free(m->dlna_pn);
-	if( flags & FLAG_MIME )
-		free(m->mime);
-	if( flags & FLAG_DURATION )
-		free(m->duration);
-	if( flags & FLAG_RESOLUTION )
-		free(m->resolution);
-}
-
-int64_t
-GetFolderMetadata(const char *name, const char *path, const char *artist, const char *genre, int64_t album_art)
-{
-	int ret;
-
-	ret = sql_exec(db, "INSERT into DETAILS"
-	                   " (TITLE, PATH, CREATOR, ARTIST, GENRE, ALBUM_ART) "
-	                   "VALUES"
-	                   " ('%q', %Q, %Q, %Q, %Q, %lld);",
-	                   name, path, artist, artist, genre, album_art);
-	if( ret != SQLITE_OK )
-		ret = 0;
-	else
-		ret = sqlite3_last_insert_rowid(db);
-
-	return ret;
-}
-
-int64_t
-GetAudioMetadata(const char *path, char *name)
-{
-	char type[4];
-	static char lang[6] = { '\0' };
-	struct stat file;
-	int64_t ret;
-	char *esc_tag;
-	int i;
-	int64_t album_art = 0;
-	struct song_metadata song;
-	metadata_t m;
-	uint32_t free_flags = FLAG_MIME|FLAG_DURATION|FLAG_DLNA_PN|FLAG_DATE;
-	memset(&m, '\0', sizeof(metadata_t));
-
-	if ( stat(path, &file) != 0 )
+	int seconds, minutes;
+	sqlite_int64 ret;
+	TagLib_File *audio_file;
+	TagLib_Tag *tag;
+	const TagLib_AudioProperties *properties;
+	char *sql;
+	char *zErrMsg = NULL;
+	char *title, *artist, *album, *genre, *comment;
+	int free_flags = 0;
+
+	if ( stat(path, &file) == 0 )
+		size = file.st_size;
+	else
 		return 0;
 	strip_ext(name);
 
-	if( ends_with(path, ".mp3") )
-	{
-		strcpy(type, "mp3");
-		m.mime = strdup("audio/mpeg");
-	}
-	else if( ends_with(path, ".m4a") || ends_with(path, ".mp4") ||
-	         ends_with(path, ".aac") || ends_with(path, ".m4p") )
-	{
-		strcpy(type, "aac");
-		m.mime = strdup("audio/mp4");
-	}
-	else if( ends_with(path, ".3gp") )
-	{
-		strcpy(type, "aac");
-		m.mime = strdup("audio/3gpp");
-	}
-	else if( ends_with(path, ".wma") || ends_with(path, ".asf") )
-	{
-		strcpy(type, "asf");
-		m.mime = strdup("audio/x-ms-wma");
-	}
-	else if( ends_with(path, ".flac") || ends_with(path, ".fla") || ends_with(path, ".flc") )
-	{
-		strcpy(type, "flc");
-		m.mime = strdup("audio/x-flac");
-	}
-	else if( ends_with(path, ".wav") )
-	{
-		strcpy(type, "wav");
-		m.mime = strdup("audio/x-wav");
-	}
-	else if( ends_with(path, ".ogg") || ends_with(path, ".oga") )
-	{
-		strcpy(type, "ogg");
-		m.mime = strdup("audio/ogg");
-	}
-	else if( ends_with(path, ".pcm") )
-	{
-		strcpy(type, "pcm");
-		m.mime = strdup("audio/L16");
-	}
-	else
-	{
-		DPRINTF(E_WARN, L_METADATA, "Unhandled file extension on %s\n", path);
+	taglib_set_strings_unicode(1);
+
+	audio_file = taglib_file_new(path);
+	if(audio_file == NULL)
 		return 0;
-	}
-
-	if( !(*lang) )
-	{
-		if( !getenv("LANG") )
-			strcpy(lang, "en_US");
-		else
-			strncpyt(lang, getenv("LANG"), sizeof(lang));
-	}
-
-	if( readtags((char *)path, &song, &file, lang, type) != 0 )
-	{
-		DPRINTF(E_WARN, L_METADATA, "Cannot extract tags from %s!\n", path);
-        	freetags(&song);
-		free_metadata(&m, free_flags);
-		return 0;
-	}
-
-	if( song.dlna_pn )
-		m.dlna_pn = strdup(song.dlna_pn);
-	if( song.year )
-		xasprintf(&m.date, "%04d-01-01", song.year);
-	xasprintf(&m.duration, "%d:%02d:%02d.%03d",
-	                      (song.song_length/3600000),
-	                      (song.song_length/60000%60),
-	                      (song.song_length/1000%60),
-	                      (song.song_length%1000));
-	if( song.title && *song.title )
-	{
-		m.title = trim(song.title);
-		if( (esc_tag = escape_tag(m.title, 0)) )
-		{
-			free_flags |= FLAG_TITLE;
-			m.title = esc_tag;
-		}
-	}
-	else
-	{
-		m.title = name;
-	}
-	for( i = ROLE_START; i < N_ROLE; i++ )
-	{
-		if( song.contributor[i] && *song.contributor[i] )
-		{
-			m.creator = trim(song.contributor[i]);
-			if( strlen(m.creator) > 48 )
-			{
-				m.creator = strdup("Various Artists");
-				free_flags |= FLAG_CREATOR;
-			}
-			else if( (esc_tag = escape_tag(m.creator, 0)) )
-			{
-				m.creator = esc_tag;
-				free_flags |= FLAG_CREATOR;
-			}
-			m.artist = m.creator;
-			break;
-		}
-	}
-	/* If there is a album artist or band associated with the album,
-	   use it for virtual containers. */
-	if( i < ROLE_ALBUMARTIST )
-	{
-		for( i = ROLE_ALBUMARTIST; i <= ROLE_BAND; i++ )
-		{
-			if( song.contributor[i] && *song.contributor[i] )
-				break;
-		}
-	        if( i <= ROLE_BAND )
-		{
-			m.artist = trim(song.contributor[i]);
-			if( strlen(m.artist) > 48 )
-			{
-				m.artist = strdup("Various Artists");
-				free_flags |= FLAG_ARTIST;
-			}
-			else if( (esc_tag = escape_tag(m.artist, 0)) )
-			{
-				m.artist = esc_tag;
-				free_flags |= FLAG_ARTIST;
-			}
-		}
-	}
-	if( song.album && *song.album )
-	{
-		m.album = trim(song.album);
-		if( (esc_tag = escape_tag(m.album, 0)) )
-		{
-			free_flags |= FLAG_ALBUM;
-			m.album = esc_tag;
-		}
-	}
-	if( song.genre && *song.genre )
-	{
-		m.genre = trim(song.genre);
-		if( (esc_tag = escape_tag(m.genre, 0)) )
-		{
-			free_flags |= FLAG_GENRE;
-			m.genre = esc_tag;
-		}
-	}
-	if( song.comment && *song.comment )
-	{
-		m.comment = trim(song.comment);
-		if( (esc_tag = escape_tag(m.comment, 0)) )
-		{
-			free_flags |= FLAG_COMMENT;
-			m.comment = esc_tag;
-		}
-	}
-
-	album_art = find_album_art(path, song.image, song.image_size);
-
-	ret = sql_exec(db, "INSERT into DETAILS"
-	                   " (PATH, SIZE, TIMESTAMP, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE,"
-	                   "  TITLE, CREATOR, ARTIST, ALBUM, GENRE, COMMENT, DISC, TRACK, DLNA_PN, MIME, ALBUM_ART) "
-	                   "VALUES"
-	                   " (%Q, %lld, %lld, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d, %d, %Q, '%s', %lld);",
-	                   path, (long long)file.st_size, (long long)file.st_mtime, m.duration, song.channels, song.bitrate,
-	                   song.samplerate, m.date, m.title, m.creator, m.artist, m.album, m.genre, m.comment, song.disc,
-	                   song.track, m.dlna_pn, song.mime?song.mime:m.mime, album_art);
-	if( ret != SQLITE_OK )
-	{
-		DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path);
+
+	tag = taglib_file_tag(audio_file);
+	properties = taglib_file_audioproperties(audio_file);
+
+	seconds = taglib_audioproperties_length(properties) % 60;
+	minutes = (taglib_audioproperties_length(properties) - seconds) / 60;
+
+	date[0] = '\0';
+	if( taglib_tag_year(tag) )
+		sprintf(date, "%04d-01-01", taglib_tag_year(tag));
+	sprintf(duration, "%d:%02d:%02d.000", minutes/60, minutes, seconds);
+
+	title = taglib_tag_title(tag);
+	if( strlen(title) )
+	{
+		title = trim(title);
+		if( index(title, '&') )
+		{
+			title = modifyString(strdup(title), "&", "&amp;amp;", 0);
+		}
+	}
+	else
+	{
+		title = name;
+	}
+	artist = taglib_tag_artist(tag);
+	if( strlen(artist) )
+	{
+		artist = trim(artist);
+		if( index(artist, '&') )
+		{
+			free_flags |= FLAG_ARTIST;
+			artist = modifyString(strdup(artist), "&", "&amp;amp;", 0);
+		}
+	}
+	else
+	{
+		artist = NULL;
+	}
+	album = taglib_tag_album(tag);
+	if( strlen(album) )
+	{
+		album = trim(album);
+		if( index(album, '&') )
+		{
+			album = modifyString(strdup(album), "&", "&amp;amp;", 0);
+		}
+	}
+	else
+	{
+		album = NULL;
+	}
+	genre = taglib_tag_genre(tag);
+	if( strlen(genre) )
+	{
+		genre = trim(genre);
+		if( index(genre, '&') )
+		{
+			genre = modifyString(strdup(genre), "&", "&amp;amp;", 0);
+		}
+	}
+	else
+	{
+		genre = NULL;
+	}
+	comment = taglib_tag_comment(tag);
+	if( strlen(comment) )
+	{
+		comment = trim(comment);
+		if( index(comment, '&') )
+		{
+			comment = modifyString(strdup(comment), "&", "&amp;amp;", 0);
+		}
+	}
+	else
+	{
+		comment = NULL;
+	}
+		
+
+	if( 1 ) // Switch on audio file type
+	{
+		strcpy(dlna_pn, "MP3;DLNA.ORG_OP=01");
+		strcpy(mime, "audio/mpeg");
+	}
+
+	sql = sqlite3_mprintf(	"INSERT into DETAILS"
+				" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE,"
+				"  TITLE, ARTIST, ALBUM, GENRE, COMMENT, TRACK, DLNA_PN, MIME) "
+				"VALUES"
+				" (%d, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %d, '%s', '%s');",
+				size, duration, taglib_audioproperties_channels(properties),
+				taglib_audioproperties_bitrate(properties)*1024,
+				taglib_audioproperties_samplerate(properties),
+				strlen(date) ? date : NULL,
+				title,
+				artist,
+				album,
+				genre,
+				comment,
+				taglib_tag_track(tag),
+				dlna_pn, mime);
+
+	taglib_tag_free_strings();
+	taglib_file_free(audio_file);
+
+	if( free_flags & FLAG_ARTIST )
+		free(artist);
+
+	//DEBUG printf("SQL: %s\n", sql);
+	if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
+	{
+		fprintf(stderr, "Error inserting details for '%s'! [%s]\n", path, zErrMsg);
+		if (zErrMsg)
+			sqlite3_free(zErrMsg);
 		ret = 0;
 	}
 	else
 	{
 		ret = sqlite3_last_insert_rowid(db);
 	}
-        freetags(&song);
-	free_metadata(&m, free_flags);
-
+	sqlite3_free(sql);
 	return ret;
 }
 
-/* For libjpeg error handling */
-jmp_buf setjmp_buffer;
-static void
-libjpeg_error_handler(j_common_ptr cinfo)
-{
-	cinfo->err->output_message (cinfo);
-	longjmp(setjmp_buffer, 1);
-	return;
-}
-
-int64_t
-GetImageMetadata(const char *path, char *name)
+sqlite_int64
+GetImageMetadata(const char * path, char * name)
 {
 	ExifData *ed;
 	ExifEntry *e = NULL;
-	ExifLoader *l;
-	struct jpeg_decompress_struct cinfo;
-	struct jpeg_error_mgr jerr;
-	FILE *infile;
+	ExifTag tag;
 	int width=0, height=0, thumb=0;
-	char make[32], model[64] = {'\0'};
+	size_t size;
+	char date[64], make[32], model[64], dlna_pn[64];
 	char b[1024];
 	struct stat file;
-	int64_t ret;
-	image_s *imsrc;
-	metadata_t m;
-	uint32_t free_flags = 0xFFFFFFFF;
-	memset(&m, '\0', sizeof(metadata_t));
-
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path);
-	if ( stat(path, &file) != 0 )
+	sqlite_int64 ret;
+	char *sql;
+	char *zErrMsg = NULL;
+
+	date[0] = '\0';
+	model[0] = '\0';
+	dlna_pn[0] = '\0';
+
+	//DEBUG printf("Parsing %s...\n", path);
+	if ( stat(path, &file) == 0 )
+		size = file.st_size;
+	else
 		return 0;
 	strip_ext(name);
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);
-
-	/* MIME hard-coded to JPEG for now, until we add PNG support */
-	m.mime = strdup("image/jpeg");
-
-	l = exif_loader_new();
+	//DEBUG printf(" * size: %d\n", size);
+
+	ExifLoader * l = exif_loader_new();
 	exif_loader_write_file(l, path);
 	ed = exif_loader_get_data(l);
 	exif_loader_unref(l);
-	if( !ed )
-		goto no_exifdata;
-
-	e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL);
-	if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) )
-	{
-		m.date = strdup(exif_entry_get_value(e, b, sizeof(b)));
-		if( strlen(m.date) > 10 )
-		{
-			m.date[4] = '-';
-			m.date[7] = '-';
-			m.date[10] = 'T';
+
+	tag = EXIF_TAG_PIXEL_X_DIMENSION;
+	e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], tag);
+	if( e )
+		width = atoi( exif_entry_get_value(e, b, sizeof(b)) );
+
+	tag = EXIF_TAG_PIXEL_Y_DIMENSION;
+	e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], tag);
+	if( e )
+		height = atoi( exif_entry_get_value(e, b, sizeof(b)) );
+	//DEBUG printf(" * resolution: %dx%d\n", width, height);
+
+	tag = EXIF_TAG_DATE_TIME_ORIGINAL;
+	e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], tag);
+	if( e ) {
+		strncpy(date, exif_entry_get_value(e, b, sizeof(b)), sizeof(date));
+		if( strlen(date) > 10 )
+		{
+			date[4] = '-';
+			date[7] = '-';
+			date[10] = 'T';
 		}
 		else {
-			free(m.date);
-			m.date = NULL;
+			strcpy(date, "0000-00-00");
 		}
 	}
 	else {
-		/* One last effort to get the date from XMP */
-		image_get_jpeg_date_xmp(path, &m.date);
-	}
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * date: %s\n", m.date);
-
-	e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE);
+		strcpy(date, "0000-00-00");
+	}
+	//DEBUG printf(" * date: %s\n", date);
+
+	model[0] = '\0';
+	tag = EXIF_TAG_MAKE;
+	e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], tag);
 	if( e )
 	{
-		strncpyt(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make));
-		e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL);
+		strncpy(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make));
+		tag = EXIF_TAG_MODEL;
+		e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], tag);
 		if( e )
 		{
-			strncpyt(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model));
+			strncpy(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model));
 			if( !strcasestr(model, make) )
 				snprintf(model, sizeof(model), "%s %s", make, exif_entry_get_value(e, b, sizeof(b)));
-			m.creator = escape_tag(trim(model), 1);
-		}
-	}
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * model: %s\n", model);
-
-	e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION);
-	if( e )
-	{
-		switch( exif_get_short(e->data, exif_data_get_byte_order(ed)) )
-		{
-		case 3:
-			m.rotation = 180;
-			break;
-		case 6:
-			m.rotation = 90;
-			break;
-		case 8:
-			m.rotation = 270;
-			break;
-		default:
-			m.rotation = 0;
-			break;
-		}
-	}
+		}
+	}
+	if( !strlen(model) )
+		strcpy(model, "Unknown");
+	//DEBUG printf(" * model: %s\n", model);
 
 	if( ed->size )
-	{
-		/* We might need to verify that the thumbnail is 160x160 or smaller */
-		if( ed->size > 12000 )
-		{
-			imsrc = image_new_from_jpeg(NULL, 0, ed->data, ed->size, 1, ROTATE_NONE);
-			if( imsrc )
-			{
- 				if( (imsrc->width <= 160) && (imsrc->height <= 160) )
-					thumb = 1;
-				image_free(imsrc);
-			}
-		}
-		else
-			thumb = 1;
-	}
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * thumbnail: %d\n", thumb);
+		thumb = 1;
+	else
+		thumb = 0;
+	//DEBUG printf(" * thumbnail: %d\n", thumb);
 
 	exif_data_unref(ed);
 
-no_exifdata:
-	/* If SOF parsing fails, then fall through to reading the JPEG data with libjpeg to get the resolution */
-	if( image_get_jpeg_resolution(path, &width, &height) != 0 || !width || !height )
-	{
-		infile = fopen(path, "r");
-		if( infile )
-		{
-			cinfo.err = jpeg_std_error(&jerr);
-			jerr.error_exit = libjpeg_error_handler;
-			jpeg_create_decompress(&cinfo);
-			if( setjmp(setjmp_buffer) )
-				goto error;
-			jpeg_stdio_src(&cinfo, infile);
-			jpeg_read_header(&cinfo, TRUE);
-			jpeg_start_decompress(&cinfo);
-			width = cinfo.output_width;
-			height = cinfo.output_height;
-			error:
-			jpeg_destroy_decompress(&cinfo);
-			fclose(infile);
-		}
-	}
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * resolution: %dx%d\n", width, height);
-
-	if( !width || !height )
-	{
-		free_metadata(&m, free_flags);
-		return 0;
-	}
 	if( width <= 640 && height <= 480 )
-		m.dlna_pn = strdup("JPEG_SM");
+		strcpy(dlna_pn, "JPEG_SM;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
 	else if( width <= 1024 && height <= 768 )
-		m.dlna_pn = strdup("JPEG_MED");
-	else if( (width <= 4096 && height <= 4096) || !GETFLAG(DLNA_STRICT_MASK) )
-		m.dlna_pn = strdup("JPEG_LRG");
-	xasprintf(&m.resolution, "%dx%d", width, height);
-
-	ret = sql_exec(db, "INSERT into DETAILS"
-	                   " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION,"
-	                    " ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
-	                   "VALUES"
-	                   " (%Q, '%q', %lld, %lld, %Q, %Q, %u, %d, %Q, %Q, %Q);",
-	                   path, name, (long long)file.st_size, (long long)file.st_mtime, m.date,
-	                   m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime);
-	if( ret != SQLITE_OK )
-	{
-		DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path);
+		strcpy(dlna_pn, "JPEG_MED;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
+	else if( width <= 4096 && height <= 4096 )
+		strcpy(dlna_pn, "JPEG_LRG;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
+	else
+		strcpy(dlna_pn, "JPEG_XL");
+
+	sql = sqlite3_mprintf(	"INSERT into DETAILS"
+				" (TITLE, SIZE, DATE, WIDTH, HEIGHT, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
+				"VALUES"
+				" ('%q', %d, '%s', %d, %d, %d, '%q', '%s', '%s');",
+				name, size, date, width, height, thumb, model, dlna_pn, "image/jpeg");
+	//DEBUG printf("SQL: %s\n", sql);
+	if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
+	{
+		fprintf(stderr, "Error inserting details for '%s'! [%s]\n", path, zErrMsg);
+		if (zErrMsg)
+			sqlite3_free(zErrMsg);
 		ret = 0;
 	}
 	else
 	{
 		ret = sqlite3_last_insert_rowid(db);
 	}
-	free_metadata(&m, free_flags);
-
+	sqlite3_free(sql);
 	return ret;
 }
 
-int64_t
-GetVideoMetadata(const char *path, char *name)
-{
+sqlite_int64
+GetVideoMetadata(const char * path, char * name)
+{
+	size_t size = 0;
 	struct stat file;
-	int ret, i;
-	struct tm *modtime;
-	AVFormatContext *ctx = NULL;
-	AVStream *astream = NULL, *vstream = NULL;
-	int audio_stream = -1, video_stream = -1;
-	enum audio_profiles audio_profile = PROFILE_AUDIO_UNKNOWN;
-	char fourcc[4];
-	int64_t album_art = 0;
-	char nfo[MAXPATHLEN], *ext;
-	struct song_metadata video;
-	metadata_t m;
-	uint32_t free_flags = 0xFFFFFFFF;
-	char *path_cpy, *basepath;
-
-	memset(&m, '\0', sizeof(m));
-	memset(&video, '\0', sizeof(video));
-
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing video %s...\n", name);
-	if ( stat(path, &file) != 0 )
-		return 0;
+	char *sql;
+	char *zErrMsg = NULL;
+	int ret;
+
+	//DEBUG printf("Parsing %s...\n", path);
+	if ( stat(path, &file) == 0 )
+		size = file.st_size;
 	strip_ext(name);
-	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);
-
-	ret = lav_open(&ctx, path);
-	if( ret != 0 )
-	{
-		char err[128];
-		av_strerror(ret, err, sizeof(err));
-		DPRINTF(E_WARN, L_METADATA, "Opening %s failed! [%s]\n", path, err);
-		return 0;
-	}
-	//dump_format(ctx, 0, NULL, 0);
-	for( i=0; i < ctx->nb_streams; i++)
-	{
-		if( lav_codec_type(ctx->streams[i]) == AVMEDIA_TYPE_AUDIO &&
-		    audio_stream == -1 )
-		{
-			audio_stream = i;
-			astream = ctx->streams[audio_stream];
-			continue;
-		}
-		else if( lav_codec_type(ctx->streams[i]) == AVMEDIA_TYPE_VIDEO &&
-		         !lav_is_thumbnail_stream(ctx->streams[i], &m.thumb_data, &m.thumb_size) &&
-		         video_stream == -1 )
-		{
-			video_stream = i;
-			vstream = ctx->streams[video_stream];
-			continue;
-		}
-	}
-	path_cpy = strdup(path);
-	basepath = basename(path_cpy);
-	if( !vstream )
-	{
-		/* This must not be a video file. */
-		lav_close(ctx);
-		if( !is_audio(path) )
-			DPRINTF(E_DEBUG, L_METADATA, "File %s does not contain a video stream.\n", basepath);
-		free(path_cpy);
-		return 0;
-	}
-
-	if( astream )
-	{
-		aac_object_type_t aac_type = AAC_INVALID;
-		switch( lav_codec_id(astream) )
-		{
-			case AV_CODEC_ID_MP3:
-				audio_profile = PROFILE_AUDIO_MP3;
-				break;
-			case AV_CODEC_ID_AAC:
-				if( !lav_codec_extradata(astream) )
-				{
-					DPRINTF(E_DEBUG, L_METADATA, "No AAC type\n");
-				}
-				else
-				{
-					uint8_t data;
-					memcpy(&data, lav_codec_extradata(astream), 1);
-					aac_type = data >> 3;
-				}
-				switch( aac_type )
-				{
-					/* AAC Low Complexity variants */
-					case AAC_LC:
-					case AAC_LC_ER:
-						if( lav_sample_rate(astream) < 8000 ||
-						    lav_sample_rate(astream) > 48000 )
-						{
-							DPRINTF(E_DEBUG, L_METADATA, "Unsupported AAC: sample rate is not 8000 < %d < 48000\n",
-								lav_sample_rate(astream));
-							break;
-						}
-						/* AAC @ Level 1/2 */
-						if( lav_channels(astream) <= 2 &&
-						    lav_bit_rate(astream) <= 576000 )
-							audio_profile = PROFILE_AUDIO_AAC;
-						else if( lav_channels(astream) <= 6 &&
-							 lav_bit_rate(astream) <= 1440000 )
-							audio_profile = PROFILE_AUDIO_AAC_MULT5;
-						else
-							DPRINTF(E_DEBUG, L_METADATA, "Unhandled AAC: %lld channels, %lld bitrate\n",
-								(long long)lav_channels(astream),
-								(long long)lav_bit_rate(astream));
-						break;
-					default:
-						DPRINTF(E_DEBUG, L_METADATA, "Unhandled AAC type [%d]\n", aac_type);
-						break;
-				}
-				break;
-			case AV_CODEC_ID_AC3:
-			case AV_CODEC_ID_DTS:
-				audio_profile = PROFILE_AUDIO_AC3;
-				break;
-			case AV_CODEC_ID_WMAV1:
-			case AV_CODEC_ID_WMAV2:
-				/* WMA Baseline: stereo, up to 48 KHz, up to 192,999 bps */
-				if ( lav_bit_rate(astream) <= 193000 )
-					audio_profile = PROFILE_AUDIO_WMA_BASE;
-				/* WMA Full: stereo, up to 48 KHz, up to 385 Kbps */
-				else if ( lav_bit_rate(astream) <= 385000 )
-					audio_profile = PROFILE_AUDIO_WMA_FULL;
-				break;
-			case AV_CODEC_ID_WMAPRO:
-				audio_profile = PROFILE_AUDIO_WMA_PRO;
-				break;
-			case AV_CODEC_ID_MP2:
-				audio_profile = PROFILE_AUDIO_MP2;
-				break;
-			case AV_CODEC_ID_AMR_NB:
-				audio_profile = PROFILE_AUDIO_AMR;
-				break;
-			default:
-				if( (lav_codec_id(astream) >= AV_CODEC_ID_PCM_S16LE) &&
-				    (lav_codec_id(astream) < AV_CODEC_ID_ADPCM_IMA_QT) )
-					audio_profile = PROFILE_AUDIO_PCM;
-				else
-					DPRINTF(E_DEBUG, L_METADATA, "Unhandled audio codec [0x%X]\n", lav_codec_id(astream));
-				break;
-		}
-		m.frequency = lav_sample_rate(astream);
-		m.channels = lav_channels(astream);
-	}
-	if( vstream )
-	{
-		int off;
-		int duration, hours, min, sec, ms;
-		ts_timestamp_t ts_timestamp = NONE;
-		DPRINTF(E_DEBUG, L_METADATA, "Container: '%s' [%s]\n", ctx->iformat->name, basepath);
-		xasprintf(&m.resolution, "%dx%d", lav_width(vstream), lav_height(vstream));
-		if( ctx->bit_rate > 8 )
-			m.bitrate = ctx->bit_rate / 8;
-		if( ctx->duration > 0 ) {
-			duration = (int)(ctx->duration / AV_TIME_BASE);
-			hours = (int)(duration / 3600);
-			min = (int)(duration / 60 % 60);
-			sec = (int)(duration % 60);
-			ms = (int)(ctx->duration / (AV_TIME_BASE/1000) % 1000);
-			xasprintf(&m.duration, "%d:%02d:%02d.%03d", hours, min, sec, ms);
-		}
-
-		/* NOTE: The DLNA spec only provides for ASF (WMV), TS, PS, and MP4 containers.
-		 * Skip DLNA parsing for everything else. */
-		if( strcmp(ctx->iformat->name, "avi") == 0 )
-		{
-			xasprintf(&m.mime, "video/x-msvideo");
-			if( lav_codec_id(vstream) == AV_CODEC_ID_MPEG4 )
-			{
-				fourcc[0] = lav_codec_tag(vstream)     & 0xff;
-				fourcc[1] = lav_codec_tag(vstream)>>8  & 0xff;
-				fourcc[2] = lav_codec_tag(vstream)>>16 & 0xff;
-				fourcc[3] = lav_codec_tag(vstream)>>24 & 0xff;
-				if( memcmp(fourcc, "XVID", 4) == 0 ||
-				    memcmp(fourcc, "DX50", 4) == 0 ||
-				    memcmp(fourcc, "DIVX", 4) == 0 )
-					xasprintf(&m.creator, "DiVX");
-			}
-		}
-		else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 &&
-		         ends_with(path, ".mov") )
-			xasprintf(&m.mime, "video/quicktime");
-		else if( strncmp(ctx->iformat->name, "matroska", 8) == 0 )
-			xasprintf(&m.mime, "video/x-matroska");
-		else if( strcmp(ctx->iformat->name, "flv") == 0 )
-			xasprintf(&m.mime, "video/x-flv");
-		if( m.mime )
-			goto video_no_dlna;
-
-		switch( lav_codec_id(vstream) )
-		{
-			case AV_CODEC_ID_MPEG1VIDEO:
-				if( strcmp(ctx->iformat->name, "mpeg") == 0 )
-				{
-					if( (lav_width(vstream)  == 352) &&
-					    (lav_height(vstream) <= 288) )
-					{
-						m.dlna_pn = strdup("MPEG1");
-					}
-					xasprintf(&m.mime, "video/mpeg");
-				}
-				break;
-			case AV_CODEC_ID_MPEG2VIDEO:
-				m.dlna_pn = malloc(64);
-				off = sprintf(m.dlna_pn, "MPEG_");
-				if( strcmp(ctx->iformat->name, "mpegts") == 0 )
-				{
-					int raw_packet_size;
-					int dlna_ts_present = dlna_timestamp_is_present(path, &raw_packet_size);
-					DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is %s MPEG2 TS packet size %d\n",
-						video_stream, basepath, m.resolution, raw_packet_size);
-					off += sprintf(m.dlna_pn+off, "TS_");
-					if( (lav_width(vstream)  >= 1280) &&
-					    (lav_height(vstream) >= 720) )
-					{
-						off += sprintf(m.dlna_pn+off, "HD_NA");
-					}
-					else
-					{
-						off += sprintf(m.dlna_pn+off, "SD_");
-						if( (lav_height(vstream) == 576) ||
-						    (lav_height(vstream) == 288) )
-							off += sprintf(m.dlna_pn+off, "EU");
-						else
-							off += sprintf(m.dlna_pn+off, "NA");
-					}
-					if( raw_packet_size == MPEG_TS_PACKET_LENGTH_DLNA )
-					{
-						if (dlna_ts_present)
-							ts_timestamp = VALID;
-						else
-							ts_timestamp = EMPTY;
-					}
-					else if( raw_packet_size != MPEG_TS_PACKET_LENGTH )
-					{
-						DPRINTF(E_DEBUG, L_METADATA, "Unsupported DLNA TS packet size [%d] (%s)\n",
-							raw_packet_size, basepath);
-						free(m.dlna_pn);
-						m.dlna_pn = NULL;
-					}
-					switch( ts_timestamp )
-					{
-						case NONE:
-							xasprintf(&m.mime, "video/mpeg");
-							if( m.dlna_pn )
-								off += sprintf(m.dlna_pn+off, "_ISO");
-							break;
-						case VALID:
-							off += sprintf(m.dlna_pn+off, "_T");
-						case EMPTY:
-							xasprintf(&m.mime, "video/vnd.dlna.mpeg-tts");
-						default:
-							break;
-					}
-				}
-				else if( strcmp(ctx->iformat->name, "mpeg") == 0 )
-				{
-					DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is %s MPEG2 PS\n",
-						video_stream, basepath, m.resolution);
-					off += sprintf(m.dlna_pn+off, "PS_");
-					if( (lav_height(vstream) == 576) ||
-					    (lav_height(vstream) == 288) )
-						off += sprintf(m.dlna_pn+off, "PAL");
-					else
-						off += sprintf(m.dlna_pn+off, "NTSC");
-					xasprintf(&m.mime, "video/mpeg");
-				}
-				else
-				{
-					DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s [%s] is %s non-DLNA MPEG2\n",
-						video_stream, basepath, ctx->iformat->name, m.resolution);
-					free(m.dlna_pn);
-					m.dlna_pn = NULL;
-				}
-				break;
-			case AV_CODEC_ID_H264:
-				m.dlna_pn = malloc(128);
-				off = sprintf(m.dlna_pn, "AVC_");
-
-				if( strcmp(ctx->iformat->name, "mpegts") == 0 )
-				{
-					AVRational display_aspect_ratio;
-					int fps, interlaced;
-					int raw_packet_size;
-					int dlna_ts_present = dlna_timestamp_is_present(path, &raw_packet_size);
-
-					off += sprintf(m.dlna_pn+off, "TS_");
-					if (lav_sample_aspect_ratio(vstream).num) {
-						av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
-						          lav_width(vstream) * lav_sample_aspect_ratio(vstream).num,
-						          lav_height(vstream) * lav_sample_aspect_ratio(vstream).den,
-						          1024*1024);
-					}
-					fps = lav_get_fps(vstream);
-					interlaced = lav_get_interlaced(vstream);
-					if( ((((lav_width(vstream) == 1920 || lav_width(vstream) == 1440) && lav_height(vstream) == 1080) ||
-					      (lav_width(vstream) == 720 && lav_height(vstream) == 480)) && fps == 59 && interlaced) ||
-					    ((lav_width(vstream) == 1280 && lav_height(vstream) == 720) && fps == 59 && !interlaced) )
-					{
-						if( (lav_profile(vstream) == FF_PROFILE_H264_MAIN || lav_profile(vstream) == FF_PROFILE_H264_HIGH) &&
-						    audio_profile == PROFILE_AUDIO_AC3 )
-						{
-							off += sprintf(m.dlna_pn+off, "HD_60_");
-							lav_profile(vstream) = FF_PROFILE_SKIP;
-						}
-					}
-					else if( ((lav_width(vstream) == 1920 && lav_height(vstream) == 1080) ||
-					          (lav_width(vstream) == 1440 && lav_height(vstream) == 1080) ||
-					          (lav_width(vstream) == 1280 && lav_height(vstream) ==  720) ||
-					          (lav_width(vstream) ==  720 && lav_height(vstream) ==  576)) &&
-					          interlaced && fps == 50 )
-					{
-						if( (lav_profile(vstream) == FF_PROFILE_H264_MAIN || lav_profile(vstream) == FF_PROFILE_H264_HIGH) &&
-						    audio_profile == PROFILE_AUDIO_AC3 )
-						{
-							off += sprintf(m.dlna_pn+off, "HD_50_");
-							lav_profile(vstream) = FF_PROFILE_SKIP;
-						}
-					}
-					switch( lav_profile(vstream) )
-					{
-						case FF_PROFILE_H264_BASELINE:
-						case FF_PROFILE_H264_CONSTRAINED_BASELINE:
-							off += sprintf(m.dlna_pn+off, "BL_");
-							if( lav_width(vstream)  <= 352 &&
-							    lav_height(vstream) <= 288 &&
-							    lav_bit_rate(vstream) <= 384000 )
-							{
-								off += sprintf(m.dlna_pn+off, "CIF15_");
-								break;
-							}
-							else if( lav_width(vstream)  <= 352 &&
-							         lav_height(vstream) <= 288 &&
-							         lav_bit_rate(vstream) <= 3000000 )
-							{
-								off += sprintf(m.dlna_pn+off, "CIF30_");
-								break;
-							}
-							/* Fall back to Main Profile if it doesn't match a Baseline DLNA profile. */
-							else
-								off -= 3;
-						default:
-						case FF_PROFILE_H264_MAIN:
-							off += sprintf(m.dlna_pn+off, "MP_");
-							if( lav_profile(vstream) != FF_PROFILE_H264_BASELINE &&
-							    lav_profile(vstream) != FF_PROFILE_H264_CONSTRAINED_BASELINE &&
-							    lav_profile(vstream) != FF_PROFILE_H264_MAIN )
-							{
-								DPRINTF(E_DEBUG, L_METADATA, "Unknown AVC profile %d; assuming MP. [%s]\n",
-									lav_profile(vstream), basepath);
-							}
-							if( lav_width(vstream)  <= 720 &&
-							    lav_height(vstream) <= 576 &&
-							    lav_bit_rate(vstream) <= 10000000 )
-							{
-								off += sprintf(m.dlna_pn+off, "SD_");
-							}
-							else if( lav_width(vstream)  <= 1920 &&
-							         lav_height(vstream) <= 1152 &&
-							         lav_bit_rate(vstream) <= 20000000 )
-							{
-								off += sprintf(m.dlna_pn+off, "HD_");
-							}
-							else
-							{
-								DPRINTF(E_DEBUG, L_METADATA, "Unsupported h.264 video profile! [%s, %dx%d, %lldbps : %s]\n",
-									m.dlna_pn, lav_width(vstream), lav_height(vstream),
-									(long long)lav_bit_rate(vstream), basepath);
-								free(m.dlna_pn);
-								m.dlna_pn = NULL;
-							}
-							break;
-						case FF_PROFILE_H264_HIGH:
-							off += sprintf(m.dlna_pn+off, "HP_");
-							if( lav_width(vstream)  <= 1920 &&
-							    lav_height(vstream) <= 1152 &&
-							    lav_bit_rate(vstream) <= 30000000 &&
-							    audio_profile == PROFILE_AUDIO_AC3 )
-							{
-								off += sprintf(m.dlna_pn+off, "HD_");
-							}
-							else
-							{
-								DPRINTF(E_DEBUG, L_METADATA, "Unsupported h.264 HP video profile! [%lldbps, %d audio : %s]\n",
-									(long long)lav_bit_rate(vstream), audio_profile, basepath);
-								free(m.dlna_pn);
-								m.dlna_pn = NULL;
-							}
-							break;
-						case FF_PROFILE_SKIP:
-							break;
-					}
-					if( !m.dlna_pn )
-						break;
-					switch( audio_profile )
-					{
-						case PROFILE_AUDIO_MP3:
-							off += sprintf(m.dlna_pn+off, "MPEG1_L3");
-							break;
-						case PROFILE_AUDIO_AC3:
-							off += sprintf(m.dlna_pn+off, "AC3");
-							break;
-						case PROFILE_AUDIO_AAC:
-						case PROFILE_AUDIO_AAC_MULT5:
-							off += sprintf(m.dlna_pn+off, "AAC_MULT5");
-							break;
-						default:
-							DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for %s file [%s]\n",
-								m.dlna_pn, basepath);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-							break;
-					}
-					if( !m.dlna_pn )
-						break;
-					if( raw_packet_size == MPEG_TS_PACKET_LENGTH_DLNA )
-					{
-						if( lav_profile(vstream) == FF_PROFILE_H264_HIGH ||
-						    dlna_ts_present )
-							ts_timestamp = VALID;
-						else
-							ts_timestamp = EMPTY;
-					}
-					else if( raw_packet_size != MPEG_TS_PACKET_LENGTH )
-					{
-						DPRINTF(E_DEBUG, L_METADATA, "Unsupported DLNA TS packet size [%d] (%s)\n",
-							raw_packet_size, basepath);
-						free(m.dlna_pn);
-						m.dlna_pn = NULL;
-					}
-					switch( ts_timestamp )
-					{
-						case NONE:
-							if( m.dlna_pn )
-								off += sprintf(m.dlna_pn+off, "_ISO");
-							break;
-						case VALID:
-							off += sprintf(m.dlna_pn+off, "_T");
-						case EMPTY:
-							xasprintf(&m.mime, "video/vnd.dlna.mpeg-tts");
-						default:
-							break;
-					}
-				}
-				else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 )
-				{
-					off += sprintf(m.dlna_pn+off, "MP4_");
-
-					switch( lav_profile(vstream) ) {
-					case FF_PROFILE_H264_BASELINE:
-					case FF_PROFILE_H264_CONSTRAINED_BASELINE:
-						if( lav_width(vstream)  <= 352 &&
-						    lav_height(vstream) <= 288 )
-						{
-							if( ctx->bit_rate < 600000 )
-								off += sprintf(m.dlna_pn+off, "BL_CIF15_");
-							else if( ctx->bit_rate < 5000000 )
-								off += sprintf(m.dlna_pn+off, "BL_CIF30_");
-							else
-								goto mp4_mp_fallback;
-
-							if( audio_profile == PROFILE_AUDIO_AMR )
-							{
-								off += sprintf(m.dlna_pn+off, "AMR");
-							}
-							else if( audio_profile == PROFILE_AUDIO_AAC )
-							{
-								off += sprintf(m.dlna_pn+off, "AAC_");
-								if( ctx->bit_rate < 520000 )
-								{
-									off += sprintf(m.dlna_pn+off, "520");
-								}
-								else if( ctx->bit_rate < 940000 )
-								{
-									off += sprintf(m.dlna_pn+off, "940");
-								}
-								else
-								{
-									off -= 13;
-									goto mp4_mp_fallback;
-								}
-							}
-							else
-							{
-								off -= 9;
-								goto mp4_mp_fallback;
-							}
-						}
-						else if( lav_width(vstream)  <= 720 &&
-						         lav_height(vstream) <= 576 )
-						{
-							if( lav_level(vstream) == 30 &&
-							    audio_profile == PROFILE_AUDIO_AAC &&
-							    ctx->bit_rate <= 5000000 )
-								off += sprintf(m.dlna_pn+off, "BL_L3L_SD_AAC");
-							else if( lav_level(vstream) <= 31 &&
-							         audio_profile == PROFILE_AUDIO_AAC &&
-							         ctx->bit_rate <= 15000000 )
-								off += sprintf(m.dlna_pn+off, "BL_L31_HD_AAC");
-							else
-								goto mp4_mp_fallback;
-						}
-						else if( lav_width(vstream)  <= 1280 &&
-						         lav_height(vstream) <= 720 )
-						{
-							if( lav_level(vstream) <= 31 &&
-							    audio_profile == PROFILE_AUDIO_AAC &&
-							    ctx->bit_rate <= 15000000 )
-								off += sprintf(m.dlna_pn+off, "BL_L31_HD_AAC");
-							else if( lav_level(vstream) <= 32 &&
-							         audio_profile == PROFILE_AUDIO_AAC &&
-							         ctx->bit_rate <= 21000000 )
-								off += sprintf(m.dlna_pn+off, "BL_L32_HD_AAC");
-							else
-								goto mp4_mp_fallback;
-						}
-						else
-							goto mp4_mp_fallback;
-						break;
-					case FF_PROFILE_H264_MAIN:
-					mp4_mp_fallback:
-						off += sprintf(m.dlna_pn+off, "MP_");
-						/* AVC MP4 SD profiles - 10 Mbps max */
-						if( lav_width(vstream)  <= 720 &&
-						    lav_height(vstream) <= 576 &&
-						    lav_bit_rate(vstream) <= 10000000 )
-						{
-							sprintf(m.dlna_pn+off, "SD_");
-							if( audio_profile == PROFILE_AUDIO_AC3 )
-								off += sprintf(m.dlna_pn+off, "AC3");
-							else if( audio_profile == PROFILE_AUDIO_AAC ||
-							         audio_profile == PROFILE_AUDIO_AAC_MULT5 )
-								off += sprintf(m.dlna_pn+off, "AAC_MULT5");
-							else if( audio_profile == PROFILE_AUDIO_MP3 )
-								off += sprintf(m.dlna_pn+off, "MPEG1_L3");
-							else
-								m.dlna_pn[10] = '\0';
-						}
-						else if( lav_width(vstream)  <= 1280 &&
-						         lav_height(vstream) <= 720 &&
-						         lav_bit_rate(vstream) <= 15000000 &&
-						         audio_profile == PROFILE_AUDIO_AAC )
-						{
-							off += sprintf(m.dlna_pn+off, "HD_720p_AAC");
-						}
-						else if( lav_width(vstream)  <= 1920 &&
-						         lav_height(vstream) <= 1080 &&
-						         lav_bit_rate(vstream) <= 21000000 &&
-						         audio_profile == PROFILE_AUDIO_AAC )
-						{
-							off += sprintf(m.dlna_pn+off, "HD_1080i_AAC");
-						}
-						if( strlen(m.dlna_pn) <= 11 )
-						{
-							DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for %s file %s\n",
-								m.dlna_pn, basepath);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-						}
-						break;
-					case FF_PROFILE_H264_HIGH:
-						if( lav_width(vstream)  <= 1920 &&
-						    lav_height(vstream) <= 1080 &&
-						    lav_bit_rate(vstream) <= 25000000 &&
-						    audio_profile == PROFILE_AUDIO_AAC )
-						{
-							off += sprintf(m.dlna_pn+off, "HP_HD_AAC");
-						}
-						break;
-					default:
-						DPRINTF(E_DEBUG, L_METADATA, "AVC profile [%d] not recognized for file %s\n",
-							lav_profile(vstream), basepath);
-						free(m.dlna_pn);
-						m.dlna_pn = NULL;
-						break;
-					}
-				}
-				else
-				{
-					free(m.dlna_pn);
-					m.dlna_pn = NULL;
-				}
-				DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is h.264\n", video_stream, basepath);
-				break;
-			case AV_CODEC_ID_MPEG4:
-				fourcc[0] = lav_codec_tag(vstream)     & 0xff;
-				fourcc[1] = lav_codec_tag(vstream)>>8  & 0xff;
-				fourcc[2] = lav_codec_tag(vstream)>>16 & 0xff;
-				fourcc[3] = lav_codec_tag(vstream)>>24 & 0xff;
-				DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is MPEG4 [%c%c%c%c/0x%X]\n",
-					video_stream, basepath,
-					isprint(fourcc[0]) ? fourcc[0] : '_',
-					isprint(fourcc[1]) ? fourcc[1] : '_',
-					isprint(fourcc[2]) ? fourcc[2] : '_',
-					isprint(fourcc[3]) ? fourcc[3] : '_',
-					lav_codec_tag(vstream));
-
-				if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 )
-				{
-					m.dlna_pn = malloc(128);
-					off = sprintf(m.dlna_pn, "MPEG4_P2_");
-
-					if( ends_with(path, ".3gp") )
-					{
-						xasprintf(&m.mime, "video/3gpp");
-						switch( audio_profile )
-						{
-							case PROFILE_AUDIO_AAC:
-								off += sprintf(m.dlna_pn+off, "3GPP_SP_L0B_AAC");
-								break;
-							case PROFILE_AUDIO_AMR:
-								off += sprintf(m.dlna_pn+off, "3GPP_SP_L0B_AMR");
-								break;
-							default:
-								DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for MPEG4-P2 3GP/0x%X file %s\n",
-								        lav_codec_id(astream), basepath);
-								free(m.dlna_pn);
-								m.dlna_pn = NULL;
-								break;
-						}
-					}
-					else
-					{
-						if( ctx->bit_rate <= 1000000 &&
-						    audio_profile == PROFILE_AUDIO_AAC )
-						{
-							off += sprintf(m.dlna_pn+off, "MP4_ASP_AAC");
-						}
-						else if( ctx->bit_rate <= 4000000 &&
-						         lav_width(vstream)  <= 640 &&
-						         lav_height(vstream) <= 480 &&
-						         audio_profile == PROFILE_AUDIO_AAC )
-						{
-							off += sprintf(m.dlna_pn+off, "MP4_SP_VGA_AAC");
-						}
-						else
-						{
-							DPRINTF(E_DEBUG, L_METADATA, "Unsupported h.264 video profile! [%dx%d, %lldbps]\n",
-								lav_width(vstream),
-								lav_height(vstream),
-								(long long)ctx->bit_rate);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-						}
-					}
-				}
-				break;
-			case AV_CODEC_ID_WMV3:
-				/* I'm not 100% sure this is correct, but it works on everything I could get my hands on */
-				if( lav_codec_extradata(vstream) )
-				{
-					if( !((lav_codec_extradata(vstream)[0] >> 3) & 1) )
-						lav_level(vstream) = 0;
-					if( !((lav_codec_extradata(vstream)[0] >> 6) & 1) )
-						lav_profile(vstream) = 0;
-				}
-			case AV_CODEC_ID_VC1:
-				if( strcmp(ctx->iformat->name, "asf") != 0 )
-				{
-					DPRINTF(E_DEBUG, L_METADATA, "Skipping DLNA parsing for non-ASF VC1 file %s\n", path);
-					break;
-				}
-				m.dlna_pn = malloc(64);
-				off = sprintf(m.dlna_pn, "WMV");
-				DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is VC1\n", video_stream, basepath);
-				xasprintf(&m.mime, "video/x-ms-wmv");
-				if( (lav_width(vstream)  <= 176) &&
-				    (lav_height(vstream) <= 144) &&
-				    (lav_level(vstream) == 0) )
-				{
-					off += sprintf(m.dlna_pn+off, "SPLL_");
-					switch( audio_profile )
-					{
-						case PROFILE_AUDIO_MP3:
-							off += sprintf(m.dlna_pn+off, "MP3");
-							break;
-						case PROFILE_AUDIO_WMA_BASE:
-							off += sprintf(m.dlna_pn+off, "BASE");
-							break;
-						default:
-							DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVSPLL/0x%X file %s\n",
-								audio_profile, basepath);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-							break;
-					}
-				}
-				else if( (lav_width(vstream)  <= 352) &&
-				         (lav_height(vstream) <= 288) &&
-				         (lav_profile(vstream) == 0) &&
-				         (ctx->bit_rate/8 <= 384000) )
-				{
-					off += sprintf(m.dlna_pn+off, "SPML_");
-					switch( audio_profile )
-					{
-						case PROFILE_AUDIO_MP3:
-							off += sprintf(m.dlna_pn+off, "MP3");
-							break;
-						case PROFILE_AUDIO_WMA_BASE:
-							off += sprintf(m.dlna_pn+off, "BASE");
-							break;
-						default:
-							DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVSPML/0x%X file %s\n",
-								audio_profile, basepath);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-							break;
-					}
-				}
-				else if( (lav_width(vstream)  <= 720) &&
-				         (lav_height(vstream) <= 576) &&
-				         (ctx->bit_rate/8 <= 10000000) )
-				{
-					off += sprintf(m.dlna_pn+off, "MED_");
-					switch( audio_profile )
-					{
-						case PROFILE_AUDIO_WMA_PRO:
-							off += sprintf(m.dlna_pn+off, "PRO");
-							break;
-						case PROFILE_AUDIO_WMA_FULL:
-							off += sprintf(m.dlna_pn+off, "FULL");
-							break;
-						case PROFILE_AUDIO_WMA_BASE:
-							off += sprintf(m.dlna_pn+off, "BASE");
-							break;
-						default:
-							DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVMED/0x%X file %s\n",
-								audio_profile, basepath);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-							break;
-					}
-				}
-				else if( (lav_width(vstream)  <= 1920) &&
-				         (lav_height(vstream) <= 1080) &&
-				         (ctx->bit_rate/8 <= 20000000) )
-				{
-					off += sprintf(m.dlna_pn+off, "HIGH_");
-					switch( audio_profile )
-					{
-						case PROFILE_AUDIO_WMA_PRO:
-							off += sprintf(m.dlna_pn+off, "PRO");
-							break;
-						case PROFILE_AUDIO_WMA_FULL:
-							off += sprintf(m.dlna_pn+off, "FULL");
-							break;
-						default:
-							DPRINTF(E_DEBUG, L_METADATA, "No DLNA profile found for WMVHIGH/0x%X file %s\n",
-								audio_profile, basepath);
-							free(m.dlna_pn);
-							m.dlna_pn = NULL;
-							break;
-					}
-				}
-				break;
-			case AV_CODEC_ID_MSMPEG4V3:
-				xasprintf(&m.mime, "video/x-msvideo");
-			default:
-				DPRINTF(E_DEBUG, L_METADATA, "Stream %d of %s is %s [type %d]\n",
-					video_stream, basepath, m.resolution, lav_codec_id(vstream));
-				break;
-		}
-	}
-
-	if( strcmp(ctx->iformat->name, "asf") == 0 )
-	{
-		if( readtags((char *)path, &video, &file, "en_US", "asf") == 0 )
-		{
-			if( video.title && *video.title )
-			{
-				m.title = escape_tag(trim(video.title), 1);
-			}
-			if( video.genre && *video.genre )
-			{
-				m.genre = escape_tag(trim(video.genre), 1);
-			}
-			if( video.contributor[ROLE_TRACKARTIST] && *video.contributor[ROLE_TRACKARTIST] )
-			{
-				m.artist = escape_tag(trim(video.contributor[ROLE_TRACKARTIST]), 1);
-			}
-			if( video.contributor[ROLE_ALBUMARTIST] && *video.contributor[ROLE_ALBUMARTIST] )
-			{
-				m.creator = escape_tag(trim(video.contributor[ROLE_ALBUMARTIST]), 1);
-			}
-			else
-			{
-				m.creator = m.artist;
-				free_flags &= ~FLAG_CREATOR;
-			}
-			if (!m.thumb_data)
-			{
-				m.thumb_data = video.image;
-				m.thumb_size = video.image_size;
-			}
-		}
-	}
-	#ifndef NETGEAR
-	#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
-	else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 )
-	{
-		if( ctx->metadata )
-		{
-			AVDictionaryEntry *tag = NULL;
-
-			//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Metadata:\n");
-			while( (tag = av_dict_get(ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)) )
-			{
-				//DEBUG DPRINTF(E_DEBUG, L_METADATA, "  %-16s: %s\n", tag->key, tag->value);
-				if( strcmp(tag->key, "title") == 0 )
-					m.title = escape_tag(trim(tag->value), 1);
-				else if( strcmp(tag->key, "genre") == 0 )
-					m.genre = escape_tag(trim(tag->value), 1);
-				else if( strcmp(tag->key, "artist") == 0 )
-					m.artist = escape_tag(trim(tag->value), 1);
-				else if( strcmp(tag->key, "comment") == 0 )
-					m.comment = escape_tag(trim(tag->value), 1);
-			}
-		}
-	}
-	#endif
-	#endif
-video_no_dlna:
-
-#ifdef TIVO_SUPPORT
-	if( ends_with(path, ".TiVo") && is_tivo_file(path) )
-	{
-		if( m.dlna_pn )
-		{
-			free(m.dlna_pn);
-			m.dlna_pn = NULL;
-		}
-		m.mime = realloc(m.mime, 21);
-		strcpy(m.mime, "video/x-tivo-mpeg");
-	}
-#endif
-
-	strcpy(nfo, path);
-	ext = strrchr(nfo, '.');
-	if( ext )
-	{
-		strcpy(ext+1, "nfo");
-		if( access(nfo, F_OK) == 0 )
-		{
-			parse_nfo(nfo, &m);
-		}
-	}
-
-	if( !m.mime )
-	{
-		if( strcmp(ctx->iformat->name, "avi") == 0 )
-			xasprintf(&m.mime, "video/x-msvideo");
-		else if( strncmp(ctx->iformat->name, "mpeg", 4) == 0 )
-			xasprintf(&m.mime, "video/mpeg");
-		else if( strcmp(ctx->iformat->name, "asf") == 0 )
-			xasprintf(&m.mime, "video/x-ms-wmv");
-		else if( strcmp(ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 )
-			if( ends_with(path, ".mov") )
-				xasprintf(&m.mime, "video/quicktime");
-			else
-				xasprintf(&m.mime, "video/mp4");
-		else if( strncmp(ctx->iformat->name, "matroska", 8) == 0 )
-			xasprintf(&m.mime, "video/x-matroska");
-		else if( strcmp(ctx->iformat->name, "flv") == 0 )
-			xasprintf(&m.mime, "video/x-flv");
-		else
-			DPRINTF(E_WARN, L_METADATA, "%s: Unhandled format: %s\n", path, ctx->iformat->name);
-	}
-
-	if( !m.date )
-	{
-		m.date = malloc(20);
-		modtime = localtime(&file.st_mtime);
-		strftime(m.date, 20, "%FT%T", modtime);
-	}
-
-	if( !m.title )
-		m.title = strdup(name);
-
-	album_art = find_album_art(path, m.thumb_data, m.thumb_size);
-	freetags(&video);
-	lav_close(ctx);
-
-	ret = sql_exec(db, "INSERT into DETAILS"
-	                   " (PATH, SIZE, TIMESTAMP, DURATION, DATE, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION,"
-	                   "  TITLE, CREATOR, ARTIST, GENRE, COMMENT, DLNA_PN, MIME, ALBUM_ART) "
-	                   "VALUES"
-	                   " (%Q, %lld, %lld, %Q, %Q, %u, %u, %u, %Q, '%q', %Q, %Q, %Q, %Q, %Q, '%q', %lld);",
-	                   path, (long long)file.st_size, (long long)file.st_mtime, m.duration,
-	                   m.date, m.channels, m.bitrate, m.frequency, m.resolution,
-			   m.title, m.creator, m.artist, m.genre, m.comment, m.dlna_pn,
-                           m.mime, album_art);
-	if( ret != SQLITE_OK )
-	{
-		DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path);
+	//DEBUG printf(" * size: %d\n", size);
+
+	sql = sqlite3_mprintf(	"INSERT into DETAILS"
+				" (TITLE, SIZE, MIME) "
+				"VALUES"
+				" ('%q', %d, %Q);",
+				name, size, "video/mpeg");
+	//DEBUG printf("SQL: %s\n", sql);
+	if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
+	{
+		fprintf(stderr, "Error inserting details for '%s'! [%s]\n", path, zErrMsg);
+		if (zErrMsg)
+			sqlite3_free(zErrMsg);
 		ret = 0;
 	}
 	else
 	{
 		ret = sqlite3_last_insert_rowid(db);
-		check_for_captions(path, ret);
-	}
-	free_metadata(&m, free_flags);
-	free(path_cpy);
-
+	}
+	sqlite3_free(sql);
 	return ret;
 }