* Don't trust EXIF to tell us the accurate resolution; instead, parse the JPEG data ourselves.
* Add on-the-fly downscaling for JPEGs too large to fit the JPEG_LRG DLNA profile.
This commit is contained in:
parent
ecec767f17
commit
1ef627ac3c
4
README
4
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.
|
||||
|
||||
|
@ -33,10 +33,17 @@
|
||||
#include <sys/types.h>
|
||||
#include <setjmp.h>
|
||||
#include <jpeglib.h>
|
||||
#include <endian.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
16
metadata.c
16
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 )
|
||||
{
|
||||
|
51
upnpsoap.c
51
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user