From 9867def3838a98060be4a5ffafdf2f8f2c4509d1 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Fri, 7 Nov 2008 06:52:03 +0000 Subject: [PATCH] * Fix bug with HTTP Range header, when there is no range end. * Start adding video metadata support using libdlna. We might need to carry libdlna because it needs some changes, but that project appears to be heading in another direction. --- metadata.c | 67 +++++++++++++++++++++++++++++++++++++----------------- metadata.h | 3 +++ scanner.c | 8 +------ upnphttp.c | 38 +++++++++++++++++++------------ 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/metadata.c b/metadata.c index b73eaaf..b09741c 100644 --- a/metadata.c +++ b/metadata.c @@ -15,6 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define LIBDLNA_SUPPORT 1 + #include #include #include @@ -24,7 +26,9 @@ #include #include #include +#if LIBDLNA_SUPPORT #include +#endif #include "upnpglobalvars.h" #include "metadata.h" @@ -32,6 +36,13 @@ #define FLAG_ARTIST 0x01 +int +ends_with(const char * haystack, const char * needle) +{ + const char *found = strcasestr(haystack, needle); + return (found && found[strlen(needle)] == '\0'); +} + char * trim(char *str) { @@ -124,7 +135,7 @@ GetFolderMetadata(const char * name, const char * artist) sqlite_int64 GetAudioMetadata(const char * path, char * name) { - size_t size = 0; + off_t size = 0; char date[16], duration[16], dlna_pn[24], mime[16]; struct stat file; int seconds, minutes; @@ -238,7 +249,7 @@ GetAudioMetadata(const char * path, char * name) " (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');", + " (%llu, '%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), @@ -280,7 +291,7 @@ GetImageMetadata(const char * path, char * name) ExifEntry *e = NULL; ExifTag tag; int width=0, height=0, thumb=0; - size_t size; + off_t size; char date[64], make[32], model[64]; char b[1024]; struct stat file; @@ -379,7 +390,7 @@ GetImageMetadata(const char * path, char * name) sql = sqlite3_mprintf( "INSERT into DETAILS" " (TITLE, SIZE, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " "VALUES" - " ('%q', %d, '%s', %Q, %d, '%q', %Q, %Q);", + " ('%q', %llu, '%s', %Q, %d, '%q', %Q, %Q);", name, size, date, m.resolution, thumb, model, m.dlna_pn, m.mime); //DEBUG printf("SQL: %s\n", sql); if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK ) @@ -406,11 +417,8 @@ GetImageMetadata(const char * path, char * name) sqlite_int64 GetVideoMetadata(const char * path, char * name) { - size_t size = 0; + off_t size = 0; struct stat file; - dlna_t *dlna; - dlna_profile_t *p; - dlna_item_t *item; char *sql; char *zErrMsg = NULL; int ret; @@ -423,16 +431,21 @@ GetVideoMetadata(const char * path, char * name) strip_ext(name); //DEBUG printf(" * size: %d\n", size); +#if LIBDLNA_SUPPORT + dlna_t *dlna; + dlna_profile_t *p; + dlna_item_t *item; + dlna = dlna_init(); dlna_register_all_media_profiles(dlna); - item = dlna_item_new (dlna, path); + item = dlna_item_new(dlna, path); if (item) { if (item->properties) { if( strlen(item->properties->duration) ) - m.duration = item->properties->duration; + m.duration = strdup(item->properties->duration); if( item->properties->bitrate ) asprintf(&m.bitrate, "%d", item->properties->bitrate); if( item->properties->sample_frequency ) @@ -445,31 +458,41 @@ GetVideoMetadata(const char * path, char * name) } } - p = dlna_guess_media_profile (dlna, path); + p = dlna_guess_media_profile(dlna, path); if (p) { - m.mime = (char *)p->mime; + m.mime = strdup(p->mime); asprintf(&m.dlna_pn, "%s;DLNA.ORG_OP=01;DLNA.ORG_CI=0", p->id); } else + { printf ("Unknown format [%s]\n", path); + if( ends_with(path, ".mpg") || ends_with(path, ".mpeg") || ends_with(path, ".ts") ) + asprintf(&m.mime, "video/mpeg"); + else if( ends_with(path, ".avi") || ends_with(path, ".divx") ) + asprintf(&m.mime, "video/divx"); + } sql = sqlite3_mprintf( "INSERT into DETAILS" " (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION," " TITLE, DLNA_PN, MIME) " "VALUES" - " (%d, %Q, %d, %d, %d, %Q, '%q', %Q, '%q');", + " (%lld, %Q, %Q, %Q, %Q, %Q, '%q', %Q, '%q');", size, m.duration, - item->properties ? item->properties->channels : 0, - item->properties ? item->properties->bitrate : 0, - item->properties ? item->properties->sample_frequency : 0, - m.resolution, name, - m.dlna_pn, m.mime); -/* sql = sqlite3_mprintf( "INSERT into DETAILS" + m.channels, + m.bitrate, + m.frequency, + m.resolution, + name, m.dlna_pn, m.mime); + dlna_item_free(item); + dlna_uninit(dlna); +#else // LIBDLNA_SUPPORT + sql = sqlite3_mprintf( "INSERT into DETAILS" " (TITLE, SIZE, MIME) " "VALUES" " ('%q', %d, %Q);", name, size, "video/mpeg");*/ +#endif // LIBDLNA_SUPPORT //DEBUG printf("SQL: %s\n", sql); if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK ) { @@ -483,10 +506,12 @@ GetVideoMetadata(const char * path, char * name) ret = sqlite3_last_insert_rowid(db); } sqlite3_free(sql); - dlna_item_free(item); - dlna_uninit(dlna); if( m.dlna_pn ) free(m.dlna_pn); + if( m.mime ) + free(m.mime); + if( m.duration ) + free(m.duration); if( m.bitrate ) free(m.bitrate); if( m.frequency ) diff --git a/metadata.h b/metadata.h index dc08cf6..fa31f6c 100644 --- a/metadata.h +++ b/metadata.h @@ -26,6 +26,9 @@ typedef struct metadata_s { char *dlna_pn; } metadata_t; +int +ends_with(const char * haystack, const char * needle); + char * modifyString(char * string, const char * before, const char * after, short like); diff --git a/scanner.c b/scanner.c index 259742b..aca22f1 100644 --- a/scanner.c +++ b/scanner.c @@ -30,13 +30,6 @@ #include "sql.h" #include "scanner.h" -int -ends_with(const char * haystack, const char * needle) -{ - const char *found = strcasestr(haystack, needle); - return (found && found[strlen(needle)] == '\0'); -} - int is_video(const char * file) { @@ -487,6 +480,7 @@ ScanDirectory(const char * dir, const char * parent) setlocale(LC_COLLATE, ""); if( chdir(dir) != 0 ) return; +printf("\nScanning %s\n", dir); n = scandir(".", &namelist, filter_media, alphasort); if (n < 0) { fprintf(stderr, "Error scanning %s [scandir]\n", dir); diff --git a/upnphttp.c b/upnphttp.c index a27810f..2b75984 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -38,6 +38,8 @@ #if 0 //JPEG_RESIZE #include #endif +//#define MAX_BUFFER_SIZE 4194304 // 4MB -- Too much? +#define MAX_BUFFER_SIZE 2147483647 // 2GB -- Too much? struct upnphttp * New_upnphttp(int s) @@ -173,7 +175,7 @@ intervening space) by either an integer or the keyword "infinite". */ h->reqflags |= FLAG_RANGE; h->req_RangeEnd = atoll(index(p+6, '-')+1); h->req_RangeStart = atoll(p+6); -printf("Range Start-End: %lld-%lld\n", h->req_RangeStart, h->req_RangeEnd); +printf("Range Start-End: %lld - %lld\n", h->req_RangeStart, h->req_RangeEnd?h->req_RangeEnd:-1); } } else if(strncasecmp(line, "Host", 4)==0) @@ -1069,7 +1071,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) int rows; char date[30]; time_t curtime = time(NULL); - off_t total; + off_t total, send_size; char *path, *mime, *dlna; memset(header, 0, 1500); @@ -1125,6 +1127,8 @@ SendResp_dlnafile(struct upnphttp * h, char * object) if( h->reqflags & FLAG_RANGE ) { + if( !h->req_RangeEnd ) + h->req_RangeEnd = size; if( (h->req_RangeStart > h->req_RangeEnd) || (h->req_RangeStart < 0) ) { syslog(LOG_NOTICE, "Specified range was invalid!"); @@ -1217,19 +1221,23 @@ SendResp_dlnafile(struct upnphttp * h, char * object) } else if( sendfh > 0 ) { - while( offset < h->req_RangeEnd ) { - int ret = sendfile(h->socket, sendfh, &offset, (h->req_RangeEnd - offset + 1)); - if( ret == -1 ) { - printf("sendfile error :: error no. %d [%s]\n", errno, strerror(errno)); - if( errno == 32 || errno == 9 || errno == 54 || errno == 104 ) - break; - } - else { - printf("sent %d bytes to %d. offset is now %d.\n", ret, h->socket, (int)offset); - } - } - close(sendfh); - } + while( offset < h->req_RangeEnd ) + { + send_size = (( (h->req_RangeEnd - offset) < MAX_BUFFER_SIZE ) ? (h->req_RangeEnd - offset + 1) : MAX_BUFFER_SIZE); + off_t ret = sendfile(h->socket, sendfh, &offset, send_size); + if( ret == -1 ) + { + printf("sendfile error :: error no. %d [%s]\n", errno, strerror(errno)); + if( errno == 32 || errno == 9 || errno == 54 || errno == 104 ) + break; + } + /*else + { + printf("sent %lld bytes to %d. offset is now %lld.\n", ret, h->socket, offset); + }*/ + } + close(sendfh); + } error: sqlite3_free_table(result); }