diff --git a/README b/README index 2672db8..8caead1 100644 --- a/README +++ b/README @@ -1,9 +1,9 @@ MiniDLNA project (c) 2009 Justin Maggard -Parts (c) 2006-2007 Thomas Bernard +Portions (c) 2006-2007 Thomas Bernard webpage: http://sourceforge.net/projects/minidlna/ -This directory contain the MiniDLNA daemon software. +This directory contains the MiniDLNA daemon software. This software is subject to the conditions detailed in the LICENCE file provided with this distribution. diff --git a/image_utils.c b/image_utils.c index e616557..97eff00 100644 --- a/image_utils.c +++ b/image_utils.c @@ -33,10 +33,17 @@ #include #include #include +#include #include "image_utils.h" #include "log.h" +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define SWAP16(w) ( (((w) >> 8) & 0x00ff) | (((w) << 8) & 0xff00) ) +#else +# define SWAP16(w) (w) +#endif + #define JPEG_QUALITY 96 #define COL(red, green, blue) (((red) << 24) | ((green) << 16) | ((blue) << 8) | 0xFF) @@ -222,6 +229,59 @@ put_pix_alpha_replace(image *pimage, int32_t x, int32_t y, pix col) pimage->buf[(y * pimage->width) + x] = col; } +int +image_get_jpeg_resolution(const char * path, int * width, int * height) +{ + FILE *img; + unsigned char buf[8]; + u_int16_t offset; + int ret = 1; + + img = fopen(path, "r"); + if( !img ) + return(-1); + + fread(&buf, 2, 1, img); + if( (buf[0] != 0xFF) || (buf[1] != 0xD8) ) + { + fclose(img); + return(-1); + } + memset(&buf, 0, sizeof(buf)); + + while( !feof(img) ) + { + while( buf[0] != 0xFF && !feof(img) ) + fread(&buf, 1, 1, img); + + while( buf[0] == 0xFF && !feof(img) ) + fread(&buf, 1, 1, img); + + if( (buf[0] >= 0xc0) && (buf[0] <= 0xc3) ) + { + fread(&buf, 7, 1, img); + *width = 0; + *height = 0; + memcpy(height, buf+3, 2); + *height = SWAP16(*height); + memcpy(width, buf+5, 2); + *width = SWAP16(*width); + ret = 0; + break; + } + else + { + offset = 0; + fread(&buf, 2, 1, img); + memcpy(&offset, buf, 2); + offset = SWAP16(offset) - 2; + fseek(img, offset, SEEK_CUR); + } + } + fclose(img); + return ret; +} + image * image_new(int32_t width, int32_t height) { diff --git a/image_utils.h b/image_utils.h index cac6d01..c1a4b38 100644 --- a/image_utils.h +++ b/image_utils.h @@ -20,6 +20,9 @@ typedef struct { void image_free(image *pimage); +int +image_get_jpeg_resolution(const char * path, int * width, int * height); + image * image_new_from_jpeg(const char * path, int is_file, const char * ptr, int size); diff --git a/metadata.c b/metadata.c index 757d06e..23d2c40 100644 --- a/metadata.c +++ b/metadata.c @@ -378,17 +378,6 @@ GetImageMetadata(const char * path, char * name) if( !ed ) goto no_exifdata; - 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 DPRINTF(E_DEBUG, L_METADATA, " * 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 || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME)) ) { @@ -448,8 +437,8 @@ GetImageMetadata(const char * path, char * name) exif_data_unref(ed); no_exifdata: - /* If EXIF parsing fails, then fall through to reading the JPEG data with libjpeg to get the resolution */ - if( !width || !height ) + /* 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"); cinfo.err = jpeg_std_error(&jerr); @@ -466,6 +455,7 @@ no_exifdata: jpeg_destroy_decompress(&cinfo); fclose(infile); } + //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * resolution: %dx%d\n", width, height); if( !width || !height ) { diff --git a/upnpsoap.c b/upnpsoap.c index 46d0a75..87c1d81 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -715,30 +715,41 @@ callback(void *args, int argc, char **argv, char **azColName) "</res>", mime, dlna_buf, lan_addr[0].str, runtime_vars.port, detailID, ext); #if 1 //JPEG_RESIZE - if( dlna_pn && (!strncmp(dlna_pn, "JPEG_L", 6) || !strncmp(dlna_pn, "JPEG_M", 6)) ) { - int srcw = atoi(strsep(&resolution, "x")); - int srch = atoi(resolution); - int dstw = 640; - int dsth = ((((640<<10)/srcw)*srch)>>10); - if( dsth > 480 ) { - dsth = 480; - dstw = (((480<<10)/srch) * srcw>>10); + if( *mime == 'i' ) { + int reqw = 0, reqh = 0; + if( dlna_pn && (!strncmp(dlna_pn, "JPEG_L", 6) || !strncmp(dlna_pn, "JPEG_M", 6)) ) { + reqw = 640; + reqh = 480; } - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - ret = sprintf(str_buf, "<res "); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - if( passed_args->filter & FILTER_RES_RESOLUTION ) { - ret = sprintf(str_buf, "resolution=\"%dx%d\" ", dstw, dsth); + else if( !dlna_pn ) { + reqw = 4096; + reqh = 4096; + } + if( reqw ) { + int srcw = atoi(strsep(&resolution, "x")); + int srch = atoi(resolution); + int dstw = reqw; + int dsth = ((((reqw<<10)/srcw)*srch)>>10); + if( dsth > reqh ) { + dsth = reqh; + dstw = (((reqh<<10)/srch) * srcw>>10); + } memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); passed_args->size += ret; + ret = sprintf(str_buf, "<res "); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + if( passed_args->filter & FILTER_RES_RESOLUTION ) { + ret = sprintf(str_buf, "resolution=\"%dx%d\" ", dstw, dsth); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + ret = sprintf(str_buf, "protocolInfo=\"http-get:*:%s:DLNA.ORG_PN=JPEG_%s\">" + "http://%s:%d/Resized/%s.jpg?width=%d,height=%d" + "</res>", + mime, (reqw==640)?"SM":"LRG", lan_addr[0].str, runtime_vars.port, + detailID, dstw, dsth); } - ret = sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">" - "http://%s:%d/Resized/%s.jpg?width=%d,height=%d" - "</res>", - mime, "DLNA.ORG_PN=JPEG_SM", lan_addr[0].str, runtime_vars.port, - detailID, dstw, dsth); } #endif memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);