* 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.
This commit is contained in:
parent
ccd9b957f6
commit
9867def383
67
metadata.c
67
metadata.c
@ -15,6 +15,8 @@
|
|||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
#define LIBDLNA_SUPPORT 1
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -24,7 +26,9 @@
|
|||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#include <taglib/tag_c.h>
|
#include <taglib/tag_c.h>
|
||||||
#include <libexif/exif-loader.h>
|
#include <libexif/exif-loader.h>
|
||||||
|
#if LIBDLNA_SUPPORT
|
||||||
#include <dlna.h>
|
#include <dlna.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "upnpglobalvars.h"
|
#include "upnpglobalvars.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
@ -32,6 +36,13 @@
|
|||||||
|
|
||||||
#define FLAG_ARTIST 0x01
|
#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 *
|
char *
|
||||||
trim(char *str)
|
trim(char *str)
|
||||||
{
|
{
|
||||||
@ -124,7 +135,7 @@ GetFolderMetadata(const char * name, const char * artist)
|
|||||||
sqlite_int64
|
sqlite_int64
|
||||||
GetAudioMetadata(const char * path, char * name)
|
GetAudioMetadata(const char * path, char * name)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
off_t size = 0;
|
||||||
char date[16], duration[16], dlna_pn[24], mime[16];
|
char date[16], duration[16], dlna_pn[24], mime[16];
|
||||||
struct stat file;
|
struct stat file;
|
||||||
int seconds, minutes;
|
int seconds, minutes;
|
||||||
@ -238,7 +249,7 @@ GetAudioMetadata(const char * path, char * name)
|
|||||||
" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE,"
|
" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE,"
|
||||||
" TITLE, ARTIST, ALBUM, GENRE, COMMENT, TRACK, DLNA_PN, MIME) "
|
" TITLE, ARTIST, ALBUM, GENRE, COMMENT, TRACK, DLNA_PN, MIME) "
|
||||||
"VALUES"
|
"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),
|
size, duration, taglib_audioproperties_channels(properties),
|
||||||
taglib_audioproperties_bitrate(properties)*1024,
|
taglib_audioproperties_bitrate(properties)*1024,
|
||||||
taglib_audioproperties_samplerate(properties),
|
taglib_audioproperties_samplerate(properties),
|
||||||
@ -280,7 +291,7 @@ GetImageMetadata(const char * path, char * name)
|
|||||||
ExifEntry *e = NULL;
|
ExifEntry *e = NULL;
|
||||||
ExifTag tag;
|
ExifTag tag;
|
||||||
int width=0, height=0, thumb=0;
|
int width=0, height=0, thumb=0;
|
||||||
size_t size;
|
off_t size;
|
||||||
char date[64], make[32], model[64];
|
char date[64], make[32], model[64];
|
||||||
char b[1024];
|
char b[1024];
|
||||||
struct stat file;
|
struct stat file;
|
||||||
@ -379,7 +390,7 @@ GetImageMetadata(const char * path, char * name)
|
|||||||
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||||
" (TITLE, SIZE, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
|
" (TITLE, SIZE, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
|
||||||
"VALUES"
|
"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);
|
name, size, date, m.resolution, thumb, model, m.dlna_pn, m.mime);
|
||||||
//DEBUG printf("SQL: %s\n", sql);
|
//DEBUG printf("SQL: %s\n", sql);
|
||||||
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
|
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
|
||||||
@ -406,11 +417,8 @@ GetImageMetadata(const char * path, char * name)
|
|||||||
sqlite_int64
|
sqlite_int64
|
||||||
GetVideoMetadata(const char * path, char * name)
|
GetVideoMetadata(const char * path, char * name)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
off_t size = 0;
|
||||||
struct stat file;
|
struct stat file;
|
||||||
dlna_t *dlna;
|
|
||||||
dlna_profile_t *p;
|
|
||||||
dlna_item_t *item;
|
|
||||||
char *sql;
|
char *sql;
|
||||||
char *zErrMsg = NULL;
|
char *zErrMsg = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -423,16 +431,21 @@ GetVideoMetadata(const char * path, char * name)
|
|||||||
strip_ext(name);
|
strip_ext(name);
|
||||||
//DEBUG printf(" * size: %d\n", size);
|
//DEBUG printf(" * size: %d\n", size);
|
||||||
|
|
||||||
|
#if LIBDLNA_SUPPORT
|
||||||
|
dlna_t *dlna;
|
||||||
|
dlna_profile_t *p;
|
||||||
|
dlna_item_t *item;
|
||||||
|
|
||||||
dlna = dlna_init();
|
dlna = dlna_init();
|
||||||
dlna_register_all_media_profiles(dlna);
|
dlna_register_all_media_profiles(dlna);
|
||||||
|
|
||||||
item = dlna_item_new (dlna, path);
|
item = dlna_item_new(dlna, path);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
if (item->properties)
|
if (item->properties)
|
||||||
{
|
{
|
||||||
if( strlen(item->properties->duration) )
|
if( strlen(item->properties->duration) )
|
||||||
m.duration = item->properties->duration;
|
m.duration = strdup(item->properties->duration);
|
||||||
if( item->properties->bitrate )
|
if( item->properties->bitrate )
|
||||||
asprintf(&m.bitrate, "%d", item->properties->bitrate);
|
asprintf(&m.bitrate, "%d", item->properties->bitrate);
|
||||||
if( item->properties->sample_frequency )
|
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)
|
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);
|
asprintf(&m.dlna_pn, "%s;DLNA.ORG_OP=01;DLNA.ORG_CI=0", p->id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
printf ("Unknown format [%s]\n", path);
|
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"
|
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||||
" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION,"
|
" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION,"
|
||||||
" TITLE, DLNA_PN, MIME) "
|
" TITLE, DLNA_PN, MIME) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" (%d, %Q, %d, %d, %d, %Q, '%q', %Q, '%q');",
|
" (%lld, %Q, %Q, %Q, %Q, %Q, '%q', %Q, '%q');",
|
||||||
size, m.duration,
|
size, m.duration,
|
||||||
item->properties ? item->properties->channels : 0,
|
m.channels,
|
||||||
item->properties ? item->properties->bitrate : 0,
|
m.bitrate,
|
||||||
item->properties ? item->properties->sample_frequency : 0,
|
m.frequency,
|
||||||
m.resolution, name,
|
m.resolution,
|
||||||
m.dlna_pn, m.mime);
|
name, m.dlna_pn, m.mime);
|
||||||
/* sql = sqlite3_mprintf( "INSERT into DETAILS"
|
dlna_item_free(item);
|
||||||
|
dlna_uninit(dlna);
|
||||||
|
#else // LIBDLNA_SUPPORT
|
||||||
|
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||||
" (TITLE, SIZE, MIME) "
|
" (TITLE, SIZE, MIME) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" ('%q', %d, %Q);",
|
" ('%q', %d, %Q);",
|
||||||
name, size, "video/mpeg");*/
|
name, size, "video/mpeg");*/
|
||||||
|
#endif // LIBDLNA_SUPPORT
|
||||||
//DEBUG printf("SQL: %s\n", sql);
|
//DEBUG printf("SQL: %s\n", sql);
|
||||||
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
|
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);
|
ret = sqlite3_last_insert_rowid(db);
|
||||||
}
|
}
|
||||||
sqlite3_free(sql);
|
sqlite3_free(sql);
|
||||||
dlna_item_free(item);
|
|
||||||
dlna_uninit(dlna);
|
|
||||||
if( m.dlna_pn )
|
if( m.dlna_pn )
|
||||||
free(m.dlna_pn);
|
free(m.dlna_pn);
|
||||||
|
if( m.mime )
|
||||||
|
free(m.mime);
|
||||||
|
if( m.duration )
|
||||||
|
free(m.duration);
|
||||||
if( m.bitrate )
|
if( m.bitrate )
|
||||||
free(m.bitrate);
|
free(m.bitrate);
|
||||||
if( m.frequency )
|
if( m.frequency )
|
||||||
|
@ -26,6 +26,9 @@ typedef struct metadata_s {
|
|||||||
char *dlna_pn;
|
char *dlna_pn;
|
||||||
} metadata_t;
|
} metadata_t;
|
||||||
|
|
||||||
|
int
|
||||||
|
ends_with(const char * haystack, const char * needle);
|
||||||
|
|
||||||
char *
|
char *
|
||||||
modifyString(char * string, const char * before, const char * after, short like);
|
modifyString(char * string, const char * before, const char * after, short like);
|
||||||
|
|
||||||
|
@ -30,13 +30,6 @@
|
|||||||
#include "sql.h"
|
#include "sql.h"
|
||||||
#include "scanner.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
|
int
|
||||||
is_video(const char * file)
|
is_video(const char * file)
|
||||||
{
|
{
|
||||||
@ -487,6 +480,7 @@ ScanDirectory(const char * dir, const char * parent)
|
|||||||
setlocale(LC_COLLATE, "");
|
setlocale(LC_COLLATE, "");
|
||||||
if( chdir(dir) != 0 )
|
if( chdir(dir) != 0 )
|
||||||
return;
|
return;
|
||||||
|
printf("\nScanning %s\n", dir);
|
||||||
n = scandir(".", &namelist, filter_media, alphasort);
|
n = scandir(".", &namelist, filter_media, alphasort);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(stderr, "Error scanning %s [scandir]\n", dir);
|
fprintf(stderr, "Error scanning %s [scandir]\n", dir);
|
||||||
|
38
upnphttp.c
38
upnphttp.c
@ -38,6 +38,8 @@
|
|||||||
#if 0 //JPEG_RESIZE
|
#if 0 //JPEG_RESIZE
|
||||||
#include <gd.h>
|
#include <gd.h>
|
||||||
#endif
|
#endif
|
||||||
|
//#define MAX_BUFFER_SIZE 4194304 // 4MB -- Too much?
|
||||||
|
#define MAX_BUFFER_SIZE 2147483647 // 2GB -- Too much?
|
||||||
|
|
||||||
struct upnphttp *
|
struct upnphttp *
|
||||||
New_upnphttp(int s)
|
New_upnphttp(int s)
|
||||||
@ -173,7 +175,7 @@ intervening space) by either an integer or the keyword "infinite". */
|
|||||||
h->reqflags |= FLAG_RANGE;
|
h->reqflags |= FLAG_RANGE;
|
||||||
h->req_RangeEnd = atoll(index(p+6, '-')+1);
|
h->req_RangeEnd = atoll(index(p+6, '-')+1);
|
||||||
h->req_RangeStart = atoll(p+6);
|
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)
|
else if(strncasecmp(line, "Host", 4)==0)
|
||||||
@ -1069,7 +1071,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
|
|||||||
int rows;
|
int rows;
|
||||||
char date[30];
|
char date[30];
|
||||||
time_t curtime = time(NULL);
|
time_t curtime = time(NULL);
|
||||||
off_t total;
|
off_t total, send_size;
|
||||||
char *path, *mime, *dlna;
|
char *path, *mime, *dlna;
|
||||||
|
|
||||||
memset(header, 0, 1500);
|
memset(header, 0, 1500);
|
||||||
@ -1125,6 +1127,8 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
|
|||||||
|
|
||||||
if( h->reqflags & FLAG_RANGE )
|
if( h->reqflags & FLAG_RANGE )
|
||||||
{
|
{
|
||||||
|
if( !h->req_RangeEnd )
|
||||||
|
h->req_RangeEnd = size;
|
||||||
if( (h->req_RangeStart > h->req_RangeEnd) || (h->req_RangeStart < 0) )
|
if( (h->req_RangeStart > h->req_RangeEnd) || (h->req_RangeStart < 0) )
|
||||||
{
|
{
|
||||||
syslog(LOG_NOTICE, "Specified range was invalid!");
|
syslog(LOG_NOTICE, "Specified range was invalid!");
|
||||||
@ -1217,19 +1221,23 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
|
|||||||
}
|
}
|
||||||
else if( sendfh > 0 )
|
else if( sendfh > 0 )
|
||||||
{
|
{
|
||||||
while( offset < h->req_RangeEnd ) {
|
while( offset < h->req_RangeEnd )
|
||||||
int ret = sendfile(h->socket, sendfh, &offset, (h->req_RangeEnd - offset + 1));
|
{
|
||||||
if( ret == -1 ) {
|
send_size = (( (h->req_RangeEnd - offset) < MAX_BUFFER_SIZE ) ? (h->req_RangeEnd - offset + 1) : MAX_BUFFER_SIZE);
|
||||||
printf("sendfile error :: error no. %d [%s]\n", errno, strerror(errno));
|
off_t ret = sendfile(h->socket, sendfh, &offset, send_size);
|
||||||
if( errno == 32 || errno == 9 || errno == 54 || errno == 104 )
|
if( ret == -1 )
|
||||||
break;
|
{
|
||||||
}
|
printf("sendfile error :: error no. %d [%s]\n", errno, strerror(errno));
|
||||||
else {
|
if( errno == 32 || errno == 9 || errno == 54 || errno == 104 )
|
||||||
printf("sent %d bytes to %d. offset is now %d.\n", ret, h->socket, (int)offset);
|
break;
|
||||||
}
|
}
|
||||||
}
|
/*else
|
||||||
close(sendfh);
|
{
|
||||||
}
|
printf("sent %lld bytes to %d. offset is now %lld.\n", ret, h->socket, offset);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
close(sendfh);
|
||||||
|
}
|
||||||
error:
|
error:
|
||||||
sqlite3_free_table(result);
|
sqlite3_free_table(result);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user