* Downscale album art files to JPEG_TN specs and cache them if we find album art at a larger resolution.
This commit is contained in:
parent
8614319bbe
commit
5413646e1c
3
Makefile
3
Makefile
@ -32,8 +32,7 @@ BASEOBJS = minidlna.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
|||||||
|
|
||||||
ALLOBJS = $(BASEOBJS) $(LNXOBJS)
|
ALLOBJS = $(BASEOBJS) $(LNXOBJS)
|
||||||
|
|
||||||
#LIBS = -liptc
|
LIBS = -lexif -ljpeg -ltag_c -lid3tag -lsqlite3 -lavformat -luuid -lgd
|
||||||
LIBS = -lexif -ljpeg -ltag_c -lid3tag -lsqlite3 -lavformat -luuid #-lgd
|
|
||||||
|
|
||||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||||
|
|
||||||
|
100
albumart.c
100
albumart.c
@ -21,13 +21,16 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
|
#include <gd.h>
|
||||||
|
|
||||||
#include "upnpglobalvars.h"
|
#include "upnpglobalvars.h"
|
||||||
#include "sql.h"
|
#include "sql.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
/* For libjpeg error handling */
|
/* For libjpeg error handling */
|
||||||
jmp_buf setjmp_buffer;
|
jmp_buf setjmp_buffer;
|
||||||
@ -56,6 +59,68 @@ check_res(int width, int height, char * dlna_pn)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
save_resized_album_art(void * ptr, const char * path, int srcw, int srch, int file, int size)
|
||||||
|
{
|
||||||
|
FILE *dstfile;
|
||||||
|
gdImagePtr imsrc = 0, imdst = 0;
|
||||||
|
int dstw, dsth;
|
||||||
|
char * cache_file;
|
||||||
|
char * cache_dir;
|
||||||
|
|
||||||
|
asprintf(&cache_file, DB_PATH "/art_cache%s", path);
|
||||||
|
if( access(cache_file, F_OK) == 0 )
|
||||||
|
return cache_file;
|
||||||
|
|
||||||
|
cache_dir = strdup(cache_file);
|
||||||
|
make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
|
||||||
|
free(cache_dir);
|
||||||
|
|
||||||
|
if( file )
|
||||||
|
imsrc = gdImageCreateFromJpeg((FILE *)ptr);
|
||||||
|
else
|
||||||
|
imsrc = gdImageCreateFromJpegPtr(size, ptr);
|
||||||
|
if( !imsrc )
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
dstfile = fopen(cache_file, "w");
|
||||||
|
if( !dstfile )
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if( srcw > srch )
|
||||||
|
{
|
||||||
|
dstw = 160;
|
||||||
|
dsth = (srch<<8) / ((srcw<<8)/160);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstw = (srcw<<8) / ((srch<<8)/160);
|
||||||
|
dsth = 160;
|
||||||
|
}
|
||||||
|
imdst = gdImageCreateTrueColor(dstw, dsth);
|
||||||
|
if( !imdst )
|
||||||
|
{
|
||||||
|
gdImageDestroy(imsrc);
|
||||||
|
fclose(dstfile);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#ifdef __sparc__
|
||||||
|
gdImageCopyResized(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy);
|
||||||
|
#else
|
||||||
|
gdImageCopyResampled(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy);
|
||||||
|
#endif
|
||||||
|
gdImageJpeg(imdst, dstfile, -1);
|
||||||
|
fclose(dstfile);
|
||||||
|
gdImageDestroy(imsrc);
|
||||||
|
gdImageDestroy(imdst);
|
||||||
|
|
||||||
|
return cache_file;
|
||||||
|
error:
|
||||||
|
free(cache_file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBID3TAG
|
#ifdef HAVE_LIBID3TAG
|
||||||
#include <id3tag.h>
|
#include <id3tag.h>
|
||||||
|
|
||||||
@ -120,7 +185,7 @@ jpeg_memory_src(j_decompress_ptr cinfo, unsigned char const *buffer, size_t bufs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* And our main album art functions */
|
/* And our main album art functions */
|
||||||
int
|
char *
|
||||||
check_embedded_art(const char * path, char * dlna_pn)
|
check_embedded_art(const char * path, char * dlna_pn)
|
||||||
{
|
{
|
||||||
struct id3_file *file;
|
struct id3_file *file;
|
||||||
@ -130,9 +195,10 @@ check_embedded_art(const char * path, char * dlna_pn)
|
|||||||
id3_latin1_t const *mime;
|
id3_latin1_t const *mime;
|
||||||
id3_length_t length;
|
id3_length_t length;
|
||||||
int index;
|
int index;
|
||||||
struct jpeg_decompress_struct cinfo;
|
struct jpeg_decompress_struct cinfo;
|
||||||
struct jpeg_error_mgr jerr;
|
struct jpeg_error_mgr jerr;
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
|
char * art_path = NULL;
|
||||||
|
|
||||||
file = id3_file_open(path, ID3_FILE_MODE_READONLY);
|
file = id3_file_open(path, ID3_FILE_MODE_READONLY);
|
||||||
if( !file )
|
if( !file )
|
||||||
@ -164,9 +230,17 @@ check_embedded_art(const char * path, char * dlna_pn)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( width > 160 || height > 160 )
|
||||||
|
{
|
||||||
|
art_path = save_resized_album_art((void *)image, path, width, height, 0, length);
|
||||||
|
}
|
||||||
|
else if( width > 0 && height > 0 )
|
||||||
|
{
|
||||||
|
art_path = path;
|
||||||
|
}
|
||||||
id3_file_close(file);
|
id3_file_close(file);
|
||||||
|
|
||||||
return( check_res(width, height, dlna_pn) );
|
return(art_file);
|
||||||
}
|
}
|
||||||
#endif // HAVE_LIBID3TAG
|
#endif // HAVE_LIBID3TAG
|
||||||
|
|
||||||
@ -177,8 +251,9 @@ check_for_album_file(char * dir, char * dlna_pn)
|
|||||||
struct album_art_name_s * album_art_name;
|
struct album_art_name_s * album_art_name;
|
||||||
struct jpeg_decompress_struct cinfo;
|
struct jpeg_decompress_struct cinfo;
|
||||||
struct jpeg_error_mgr jerr;
|
struct jpeg_error_mgr jerr;
|
||||||
FILE *infile;
|
static FILE * infile;
|
||||||
int width=0, height=0;
|
int width=0, height=0;
|
||||||
|
char * art_file;
|
||||||
|
|
||||||
for( album_art_name = album_art_names; album_art_name; album_art_name = album_art_name->next )
|
for( album_art_name = album_art_names; album_art_name; album_art_name = album_art_name->next )
|
||||||
{
|
{
|
||||||
@ -196,14 +271,18 @@ check_for_album_file(char * dir, char * dlna_pn)
|
|||||||
jpeg_start_decompress(&cinfo);
|
jpeg_start_decompress(&cinfo);
|
||||||
width = cinfo.output_width;
|
width = cinfo.output_width;
|
||||||
height = cinfo.output_height;
|
height = cinfo.output_height;
|
||||||
|
if( width > 160 || height > 160 )
|
||||||
|
{
|
||||||
|
art_file = file;
|
||||||
|
rewind(infile);
|
||||||
|
file = save_resized_album_art((void *)infile, art_file, width, height, 1, 0);
|
||||||
|
free(art_file);
|
||||||
|
}
|
||||||
error:
|
error:
|
||||||
jpeg_destroy_decompress(&cinfo);
|
jpeg_destroy_decompress(&cinfo);
|
||||||
fclose(infile);
|
fclose(infile);
|
||||||
|
|
||||||
if( check_res(width, height, dlna_pn) )
|
return(file);
|
||||||
return(file);
|
|
||||||
else
|
|
||||||
return(NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(file);
|
free(file);
|
||||||
@ -226,6 +305,7 @@ find_album_art(const char * path, char * dlna_pn)
|
|||||||
if( (album_art = check_for_album_file(dirname(mypath), dlna_pn)) )
|
if( (album_art = check_for_album_file(dirname(mypath), dlna_pn)) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
strcpy(dlna_pn, "JPEG_TN");
|
||||||
sql = sqlite3_mprintf("SELECT ID from ALBUM_ART where PATH = '%q'", album_art ? album_art : path);
|
sql = sqlite3_mprintf("SELECT ID from ALBUM_ART where PATH = '%q'", album_art ? album_art : path);
|
||||||
if( (sql_get_table(db, sql, &result, &rows, &cols) == SQLITE_OK) && rows )
|
if( (sql_get_table(db, sql, &result, &rows, &cols) == SQLITE_OK) && rows )
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ UPNP_VERSION=20070827
|
|||||||
# Facility to syslog
|
# Facility to syslog
|
||||||
LOG_MINIDLNA="LOG_DAEMON"
|
LOG_MINIDLNA="LOG_DAEMON"
|
||||||
# Database path
|
# Database path
|
||||||
DB_PATH="/tmp/files.db"
|
DB_PATH="/tmp/minidlna"
|
||||||
|
|
||||||
# detecting the OS name and version
|
# detecting the OS name and version
|
||||||
OS_NAME=`uname -s`
|
OS_NAME=`uname -s`
|
||||||
|
@ -404,6 +404,7 @@ int
|
|||||||
inotify_remove_file(const char * path)
|
inotify_remove_file(const char * path)
|
||||||
{
|
{
|
||||||
char * sql;
|
char * sql;
|
||||||
|
char * art_cache;
|
||||||
char **result;
|
char **result;
|
||||||
sqlite_int64 detailID = 0;
|
sqlite_int64 detailID = 0;
|
||||||
int rows, ret = 1;
|
int rows, ret = 1;
|
||||||
@ -428,6 +429,12 @@ inotify_remove_file(const char * path)
|
|||||||
sql_exec(db, sql);
|
sql_exec(db, sql);
|
||||||
free(sql);
|
free(sql);
|
||||||
}
|
}
|
||||||
|
asprintf(&art_cache, "%s/art_cache%s", DB_PATH, path);
|
||||||
|
if( access(art_cache, F_OK) == 0 )
|
||||||
|
{
|
||||||
|
remove(art_cache);
|
||||||
|
}
|
||||||
|
free(art_cache);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
14
minidlna.c
14
minidlna.c
@ -37,6 +37,7 @@
|
|||||||
#include "getifaddr.h"
|
#include "getifaddr.h"
|
||||||
#include "upnpsoap.h"
|
#include "upnpsoap.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "utils.h"
|
||||||
#include "minissdp.h"
|
#include "minissdp.h"
|
||||||
#include "minidlnatypes.h"
|
#include "minidlnatypes.h"
|
||||||
#include "daemonize.h"
|
#include "daemonize.h"
|
||||||
@ -606,7 +607,13 @@ main(int argc, char * * argv)
|
|||||||
|
|
||||||
LIST_INIT(&upnphttphead);
|
LIST_INIT(&upnphttphead);
|
||||||
|
|
||||||
if( sqlite3_open(DB_PATH, &db) != SQLITE_OK )
|
if( access(DB_PATH, F_OK) != 0 )
|
||||||
|
{
|
||||||
|
char *db_path = strdup(DB_PATH);
|
||||||
|
make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
|
||||||
|
free(db_path);
|
||||||
|
}
|
||||||
|
if( sqlite3_open(DB_PATH "/files.db", &db) != SQLITE_OK )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: Failed to open sqlite database! Exiting...\n");
|
fprintf(stderr, "ERROR: Failed to open sqlite database! Exiting...\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@ -622,8 +629,9 @@ main(int argc, char * * argv)
|
|||||||
struct media_dir_s * media_path = media_dirs;
|
struct media_dir_s * media_path = media_dirs;
|
||||||
printf("Database version mismatch; need to recreate...\n");
|
printf("Database version mismatch; need to recreate...\n");
|
||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
unlink(DB_PATH);
|
unlink(DB_PATH "/files.db");
|
||||||
sqlite3_open(DB_PATH, &db);
|
system("rm -rf " DB_PATH "/art_cache");
|
||||||
|
sqlite3_open(DB_PATH "/files.db", &db);
|
||||||
freopen("/dev/null", "a", stderr);
|
freopen("/dev/null", "a", stderr);
|
||||||
if( CreateDatabase() != 0 )
|
if( CreateDatabase() != 0 )
|
||||||
{
|
{
|
||||||
|
45
utils.c
45
utils.c
@ -24,6 +24,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
ends_with(const char * haystack, const char * needle)
|
ends_with(const char * haystack, const char * needle)
|
||||||
@ -102,3 +103,47 @@ strip_ext(char * name)
|
|||||||
if( period )
|
if( period )
|
||||||
*period = '\0';
|
*period = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Code basically stolen from busybox */
|
||||||
|
int
|
||||||
|
make_dir(char * path, mode_t mode)
|
||||||
|
{
|
||||||
|
char * s = path;
|
||||||
|
char c;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
/* Bypass leading non-'/'s and then subsequent '/'s. */
|
||||||
|
while (*s) {
|
||||||
|
if (*s == '/') {
|
||||||
|
do {
|
||||||
|
++s;
|
||||||
|
} while (*s == '/');
|
||||||
|
c = *s; /* Save the current char */
|
||||||
|
*s = 0; /* and replace it with nul. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mkdir(path, mode) < 0) {
|
||||||
|
/* If we failed for any other reason than the directory
|
||||||
|
* already exists, output a diagnostic and return -1.*/
|
||||||
|
if (errno != EEXIST
|
||||||
|
|| (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!c)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Remove any inserted nul from the path. */
|
||||||
|
*s = c;
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
printf("make_dir: cannot create directory '%s'", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user