diff --git a/NEWS b/NEWS index 3093c3f..ebb3c6c 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ - Add support for the av:mediaClass tag, so some Sony devices can filter items by media type. - Fix inotify detection issues on first-level folders. - Work around LifeTab's broken DLNA support. +- Add image rotation support during resize. (mostly useful for TiVo) 1.0.22 - Released 24-Aug-2011 -------------------------------- diff --git a/albumart.c b/albumart.c index 4f94b13..3dde221 100644 --- a/albumart.c +++ b/albumart.c @@ -218,7 +218,7 @@ check_embedded_art(const char *path, const char *image_data, int image_size) } last_hash = hash; - imsrc = image_new_from_jpeg(NULL, 0, image_data, image_size, 1); + imsrc = image_new_from_jpeg(NULL, 0, image_data, image_size, 1, ROTATE_NONE); if( !imsrc ) { last_success = 0; @@ -302,7 +302,7 @@ check_for_album_file(const char *path) if( art_cache_exists(file, &art_file) ) goto existing_file; free(art_file); - imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1); + imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE); if( imsrc ) goto found_file; } @@ -315,7 +315,7 @@ check_for_album_file(const char *path) if( art_cache_exists(file, &art_file) ) goto existing_file; free(art_file); - imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1); + imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE); if( imsrc ) goto found_file; } @@ -332,7 +332,7 @@ existing_file: return art_file; } free(art_file); - imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1); + imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE); if( !imsrc ) continue; found_file: diff --git a/image_utils.c b/image_utils.c index f2cadd4..0821507 100644 --- a/image_utils.c +++ b/image_utils.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #ifdef HAVE_MACHINE_ENDIAN_H @@ -240,7 +239,7 @@ image_get_jpeg_resolution(const char * path, int * width, int * height) { FILE *img; unsigned char buf[8]; - u_int16_t offset, h, w; + uint16_t offset, h, w; int ret = 1; size_t nread; long size; @@ -306,7 +305,7 @@ image_get_jpeg_date_xmp(const char * path, char ** date) FILE *img; unsigned char buf[8]; char *data = NULL, *newdata; - u_int16_t offset; + uint16_t offset; struct NameValueParserData xml; char * exif; int ret = 1; @@ -425,7 +424,7 @@ image_new(int32_t width, int32_t height) } image_s * -image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, int scale) +image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, int scale, int rotate) { image_s *vimage; FILE *file = NULL; @@ -435,7 +434,6 @@ image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, int maxbuf; struct jpeg_error_mgr pub; - cinfo.err = jpeg_std_error(&pub); pub.error_exit = libjpeg_error_handler; jpeg_create_decompress(&cinfo); @@ -465,7 +463,7 @@ image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, jpeg_start_decompress(&cinfo); w = cinfo.output_width; h = cinfo.output_height; - vimage = image_new(w, h); + vimage = (rotate & (ROTATE_90|ROTATE_270)) ? image_new(h, w) : image_new(w, h); if(!vimage) { jpeg_destroy_decompress(&cinfo); @@ -498,8 +496,9 @@ image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, maxbuf = vimage->width * vimage->height; if(cinfo.output_components == 3) { + int rx, ry; ofs = 0; - if((ptr = (unsigned char *)malloc(w * 3 * cinfo.rec_outbuf_height + 16)) == NULL) + if((ptr = malloc(w * 3 * cinfo.rec_outbuf_height + 16)) == NULL) { DPRINTF(E_WARN, L_METADATA, "malloc failed\n"); image_free(vimage); @@ -510,6 +509,7 @@ image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, for(y = 0; y < h; y += cinfo.rec_outbuf_height) { + ry = (rotate & (ROTATE_90|ROTATE_180)) ? (y - h + 1) * -1 : y; for(i = 0; i < cinfo.rec_outbuf_height; i++) { line[i] = ptr + (w * 3 * i); @@ -517,11 +517,10 @@ image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); for(x = 0; x < w * cinfo.rec_outbuf_height; x++) { + rx = (rotate & (ROTATE_180|ROTATE_270)) ? (x - w + 1) * -1 : x; + ofs = (rotate & (ROTATE_90|ROTATE_270)) ? ry + (rx * h) : rx + (ry * w); if( ofs < maxbuf ) - { vimage->buf[ofs] = COL(ptr[x + x + x], ptr[x + x + x + 1], ptr[x + x + x + 2]); - ofs++; - } } } free(ptr); @@ -531,7 +530,7 @@ image_new_from_jpeg(const char * path, int is_file, const char * buf, int size, ofs = 0; for(i = 0; i < cinfo.rec_outbuf_height; i++) { - if((line[i] = (unsigned char *)malloc(w)) == NULL) + if((line[i] = malloc(w)) == NULL) { int t = 0; @@ -607,19 +606,19 @@ image_upsize(image_s * pdest, image_s * psrc, int32_t width, int32_t height) x_dist = rx - ((float)((int32_t)rx)); y_dist = ry - ((float)((int32_t)ry)); - vcol = COL_FULL( (u_int8_t)((COL_RED(vcol1)*(1.0-x_dist) + vcol = COL_FULL( (uint8_t)((COL_RED(vcol1)*(1.0-x_dist) + COL_RED(vcol2)*(x_dist))*(1.0-y_dist) + (COL_RED(vcol3)*(1.0-x_dist) + COL_RED(vcol4)*(x_dist))*(y_dist)), - (u_int8_t)((COL_GREEN(vcol1)*(1.0-x_dist) + (uint8_t)((COL_GREEN(vcol1)*(1.0-x_dist) + COL_GREEN(vcol2)*(x_dist))*(1.0-y_dist) + (COL_GREEN(vcol3)*(1.0-x_dist) + COL_GREEN(vcol4)*(x_dist))*(y_dist)), - (u_int8_t)((COL_BLUE(vcol1)*(1.0-x_dist) + (uint8_t)((COL_BLUE(vcol1)*(1.0-x_dist) + COL_BLUE(vcol2)*(x_dist))*(1.0-y_dist) + (COL_BLUE(vcol3)*(1.0-x_dist) + COL_BLUE(vcol4)*(x_dist))*(y_dist)), - (u_int8_t)((COL_ALPHA(vcol1)*(1.0-x_dist) + (uint8_t)((COL_ALPHA(vcol1)*(1.0-x_dist) + COL_ALPHA(vcol2)*(x_dist))*(1.0-y_dist) + (COL_ALPHA(vcol3)*(1.0-x_dist) + COL_ALPHA(vcol4)*(x_dist))*(y_dist)) @@ -769,7 +768,7 @@ image_downsize(image_s * pdest, image_s * psrc, int32_t width, int32_t height) alpha = (alpha > 255.0)? 255.0 : ((alpha < 0.0)? 0.0:alpha); #endif put_pix_alpha_replace(pdest, vx, vy, - COL_FULL((u_int8_t)red, (u_int8_t)green, (u_int8_t)blue, (u_int8_t)alpha)); + COL_FULL((uint8_t)red, (uint8_t)green, (uint8_t)blue, (uint8_t)alpha)); } } } @@ -823,9 +822,9 @@ image_save_to_jpeg_buf(image_s * pimage, int * size) { for(x = 0; x < pimage->width; x++) { - data[x + x + x] = COL_RED(pimage->buf[i]); - data[x + x + x + 1] = COL_GREEN(pimage->buf[i]); - data[x + x + x + 2] = COL_BLUE(pimage->buf[i]); + data[x * 3] = COL_RED(pimage->buf[i]); + data[x * 3 + 1] = COL_GREEN(pimage->buf[i]); + data[x * 3 + 2] = COL_BLUE(pimage->buf[i]); i++; } row_pointer[0] = (unsigned char *)data; diff --git a/image_utils.h b/image_utils.h index 40ffaea..4c1a79f 100644 --- a/image_utils.h +++ b/image_utils.h @@ -21,9 +21,14 @@ * You should have received a copy of the GNU General Public License * along with MiniDLNA. If not, see . */ -#include +#include -typedef u_int32_t pix; +#define ROTATE_NONE 0x0 +#define ROTATE_90 0x1 +#define ROTATE_180 0x2 +#define ROTATE_270 0x4 + +typedef uint32_t pix; typedef struct { int32_t width; @@ -41,7 +46,7 @@ int image_get_jpeg_resolution(const char * path, int * width, int * height); image_s * -image_new_from_jpeg(const char * path, int is_file, const char * ptr, int size, int scale); +image_new_from_jpeg(const char * path, int is_file, const char * ptr, int size, int scale, int resize); image_s * image_resize(image_s * src_image, int32_t width, int32_t height); diff --git a/metadata.c b/metadata.c index fe0bb01..af376f4 100644 --- a/metadata.c +++ b/metadata.c @@ -114,6 +114,7 @@ #define FLAG_FREQUENCY 0x00001000 #define FLAG_BPS 0x00002000 #define FLAG_CHANNELS 0x00004000 +#define FLAG_ROTATION 0x00008000 /* Audio profile flags */ enum audio_profiles { @@ -281,36 +282,38 @@ parse_nfo(const char * path, metadata_t * m) void free_metadata(metadata_t * m, uint32_t flags) { - if( m->title && (flags & FLAG_TITLE) ) + if( flags & FLAG_TITLE ) free(m->title); - if( m->artist && (flags & FLAG_ARTIST) ) + if( flags & FLAG_ARTIST ) free(m->artist); - if( m->album && (flags & FLAG_ALBUM) ) + if( flags & FLAG_ALBUM ) free(m->album); - if( m->genre && (flags & FLAG_GENRE) ) + if( flags & FLAG_GENRE ) free(m->genre); - if( m->creator && (flags & FLAG_CREATOR) ) + if( flags & FLAG_CREATOR ) free(m->creator); - if( m->date && (flags & FLAG_DATE) ) + if( flags & FLAG_DATE ) free(m->date); - if( m->comment && (flags & FLAG_COMMENT) ) + if( flags & FLAG_COMMENT ) free(m->comment); - if( m->dlna_pn && (flags & FLAG_DLNA_PN) ) + if( flags & FLAG_DLNA_PN ) free(m->dlna_pn); - if( m->mime && (flags & FLAG_MIME) ) + if( flags & FLAG_MIME ) free(m->mime); - if( m->duration && (flags & FLAG_DURATION) ) + if( flags & FLAG_DURATION ) free(m->duration); - if( m->resolution && (flags & FLAG_RESOLUTION) ) + if( flags & FLAG_RESOLUTION ) free(m->resolution); - if( m->bitrate && (flags & FLAG_BITRATE) ) + if( flags & FLAG_BITRATE ) free(m->bitrate); - if( m->frequency && (flags & FLAG_FREQUENCY) ) + if( flags & FLAG_FREQUENCY ) free(m->frequency); - if( m->bps && (flags & FLAG_BPS) ) + if( flags & FLAG_BPS ) free(m->bps); - if( m->channels && (flags & FLAG_CHANNELS) ) + if( flags & FLAG_CHANNELS ) free(m->channels); + if( flags & FLAG_ROTATION ) + free(m->rotation); } sqlite_int64 @@ -562,7 +565,7 @@ GetImageMetadata(const char * path, char * name) //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size); /* MIME hard-coded to JPEG for now, until we add PNG support */ - asprintf(&m.mime, "image/jpeg"); + m.mime = strdup("image/jpeg"); l = exif_loader_new(); exif_loader_write_file(l, path); @@ -572,7 +575,8 @@ GetImageMetadata(const char * path, char * name) goto no_exifdata; e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL); - if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) ) { + if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) ) + { m.date = strdup(exif_entry_get_value(e, b, sizeof(b))); if( strlen(m.date) > 10 ) { @@ -591,11 +595,11 @@ GetImageMetadata(const char * path, char * name) } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * date: %s\n", m.date); - e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); + e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); if( e ) { strncpyt(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make)); - e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL); + e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL); if( e ) { strncpyt(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model)); @@ -606,12 +610,38 @@ GetImageMetadata(const char * path, char * name) } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * model: %s\n", model); + e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION); + if( e ) + { + int rotate; + switch( exif_get_short(e->data, exif_data_get_byte_order(ed)) ) + { + case 3: + rotate = 180; + break; + case 6: + rotate = 270; + break; + case 8: + rotate = 90; + break; + default: + rotate = 0; + break; + } + if( rotate ) + { + if( asprintf(&m.rotation, "%d", rotate) < 0 ) + m.rotation = NULL; + } + } + if( ed->size ) { /* We might need to verify that the thumbnail is 160x160 or smaller */ if( ed->size > 12000 ) { - imsrc = image_new_from_jpeg(NULL, 0, (char *)ed->data, ed->size, 1); + imsrc = image_new_from_jpeg(NULL, 0, (char *)ed->data, ed->size, 1, ROTATE_NONE); if( imsrc ) { if( (imsrc->width <= 160) && (imsrc->height <= 160) ) @@ -664,10 +694,12 @@ no_exifdata: asprintf(&m.resolution, "%dx%d", width, height); ret = sql_exec(db, "INSERT into DETAILS" - " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " + " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION," + " ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " "VALUES" - " (%Q, '%q', %lld, %ld, %Q, %Q, %d, %Q, %Q, %Q);", - path, name, file.st_size, file.st_mtime, m.date, m.resolution, thumb, m.creator, m.dlna_pn, m.mime); + " (%Q, '%q', %lld, %ld, %Q, %Q, %Q, %d, %Q, %Q, %Q);", + path, name, file.st_size, file.st_mtime, m.date, m.resolution, + m.rotation, thumb, m.creator, m.dlna_pn, m.mime); if( ret != SQLITE_OK ) { fprintf(stderr, "Error inserting details for '%s'!\n", path); diff --git a/metadata.h b/metadata.h index 5d9c6e3..89e55ad 100644 --- a/metadata.h +++ b/metadata.h @@ -36,6 +36,7 @@ typedef struct metadata_s { char *frequency; char *bps; char *resolution; + char *rotation; char *duration; char *date; char *mime; diff --git a/scanner.c b/scanner.c index edb84c7..1a50346 100644 --- a/scanner.c +++ b/scanner.c @@ -577,25 +577,26 @@ CreateDatabase(void) "ID INTEGER PRIMARY KEY AUTOINCREMENT, " "PATH TEXT DEFAULT NULL, " "SIZE INTEGER, " + "TIMESTAMP INTEGER, " "TITLE TEXT COLLATE NOCASE, " "DURATION TEXT, " "BITRATE INTEGER, " "SAMPLERATE INTEGER, " + "CREATOR TEXT COLLATE NOCASE, " "ARTIST TEXT COLLATE NOCASE, " "ALBUM TEXT COLLATE NOCASE, " "GENRE TEXT COLLATE NOCASE, " "COMMENT TEXT, " "CHANNELS INTEGER, " + "DISC INTEGER, " "TRACK INTEGER, " "DATE DATE, " "RESOLUTION TEXT, " "THUMBNAIL BOOL DEFAULT 0, " - "CREATOR TEXT COLLATE NOCASE, " - "DLNA_PN TEXT, " - "MIME TEXT, " "ALBUM_ART INTEGER DEFAULT 0, " - "DISC INTEGER, " - "TIMESTAMP INTEGER" + "ROTATION INTEGER, " + "DLNA_PN TEXT, " + "MIME TEXT" ")"); if( ret != SQLITE_OK ) goto sql_failed; diff --git a/sql.c b/sql.c index 1a59336..3b85404 100644 --- a/sql.c +++ b/sql.c @@ -216,13 +216,19 @@ db_upgrade(sqlite3 *db) return 5; if (db_vers < 6) { - DPRINTF(E_WARN, L_DB_SQL, "Updating DB version to v%d.\n", DB_VERSION); ret = sql_exec(db, "CREATE TABLE BOOKMARKS (" "ID INTEGER PRIMARY KEY, " "SEC INTEGER)"); if( ret != SQLITE_OK ) return 6; } + if (db_vers < 7) + { + DPRINTF(E_WARN, L_DB_SQL, "Updating DB version to v%d.\n", DB_VERSION); + ret = sql_exec(db, "ALTER TABLE DETAILS ADD rotation INTEGER"); + if( ret != SQLITE_OK ) + return 7; + } sql_exec(db, "PRAGMA user_version = %d", DB_VERSION); return 0; diff --git a/upnpglobalvars.h b/upnpglobalvars.h index 1a4b44d..51a0f5f 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -56,7 +56,7 @@ #include -#define MINIDLNA_VERSION "1.0.22" +#define MINIDLNA_VERSION "1.1.0-cvs" #ifdef NETGEAR # define SERVER_NAME "ReadyDLNA" @@ -66,7 +66,7 @@ #define CLIENT_CACHE_SLOTS 20 #define USE_FORK 1 -#define DB_VERSION 6 +#define DB_VERSION 7 #ifdef ENABLE_NLS #define _(string) gettext(string) diff --git a/upnphttp.c b/upnphttp.c index 7cc5f5f..feb8f42 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -900,7 +900,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h) return; } /* 7.3.33.4 */ - else if( ((h->reqflags & FLAG_TIMESEEK) || (h->reqflags & FLAG_PLAYSPEED)) && + else if( (h->reqflags & (FLAG_TIMESEEK|FLAG_PLAYSPEED)) && !(h->reqflags & FLAG_RANGE) ) { DPRINTF(E_WARN, L_HTTP, "DLNA %s requested, responding ERROR 406\n", @@ -1366,7 +1366,7 @@ SendResp_albumArt(struct upnphttp * h, char * object) int fd; int ret; - if( h->reqflags & FLAG_XFERSTREAMING || h->reqflags & FLAG_RANGE ) + if( h->reqflags & (FLAG_XFERSTREAMING|FLAG_RANGE) ) { DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Streaming with an image!\n"); Send406(h); @@ -1481,7 +1481,7 @@ SendResp_thumbnail(struct upnphttp * h, char * object) ExifData *ed; ExifLoader *l; - if( h->reqflags & FLAG_XFERSTREAMING || h->reqflags & FLAG_RANGE ) + if( h->reqflags & (FLAG_XFERSTREAMING|FLAG_RANGE) ) { DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Streaming with an image!\n"); Send406(h); @@ -1545,7 +1545,7 @@ void SendResp_resizedimg(struct upnphttp * h, char * object) { char header[512]; - char str_buf[256]; + char buf[128]; struct string_s str; char **result; char date[30]; @@ -1557,50 +1557,39 @@ SendResp_resizedimg(struct upnphttp * h, char * object) char *path, *file_path; char *resolution; char *key, *val; - char *saveptr=NULL, *item=NULL; + char *saveptr, *item=NULL; + int rotate; /* Not implemented yet * - char *pixelshape=NULL; - int rotation; */ + char *pixelshape=NULL; */ sqlite_int64 id; int rows=0, chunked, ret; image_s *imsrc = NULL, *imdst = NULL; int scale = 1; - id = strtoll(object, NULL, 10); - sprintf(str_buf, "SELECT PATH, RESOLUTION from DETAILS where ID = '%lld'", id); - ret = sql_get_table(db, str_buf, &result, &rows, NULL); + id = strtoll(object, &saveptr, 10); + snprintf(buf, sizeof(buf), "SELECT PATH, RESOLUTION, ROTATION from DETAILS where ID = '%lld'", id); + ret = sql_get_table(db, buf, &result, &rows, NULL); if( (ret != SQLITE_OK) ) { DPRINTF(E_ERROR, L_HTTP, "Didn't find valid file for %lld!\n", id); Send500(h); return; } - if( !rows || (access(result[2], F_OK) != 0) ) + file_path = result[3]; + resolution = result[4]; + rotate = result[5] ? atoi(result[5]) : 0; + if( !rows || !file_path || !resolution || (access(file_path, F_OK) != 0) ) { DPRINTF(E_WARN, L_HTTP, "%s not found, responding ERROR 404\n", object); sqlite3_free_table(result); Send404(h); return; } -#if USE_FORK - pid_t newpid = 0; - newpid = fork(); - if( newpid ) - { - CloseSocket_upnphttp(h); - goto resized_error; - } -#endif - file_path = result[2]; - resolution = result[3]; - srcw = strtol(resolution, &saveptr, 10); - srch = strtol(saveptr+1, NULL, 10); - path = strdup(object); - if( strtok_r(path, "?", &saveptr) ) - { - item = strtok_r(NULL, "&,", &saveptr); - } + if( saveptr ) + saveptr = strchr(saveptr, '?'); + path = saveptr ? saveptr + 1 : object; + item = strtok_r(path, "&,", &saveptr); while( item != NULL ) { #ifdef TIVO_SUPPORT @@ -1617,29 +1606,39 @@ SendResp_resizedimg(struct upnphttp * h, char * object) { height = atoi(val); } - /* Not implemented yet * else if( strcasecmp(key, "rotation") == 0 ) { - rotation = atoi(val); + rotate = (rotate + atoi(val)) % 360; + sql_exec(db, "UPDATE DETAILS set ROTATION = %d where ID = %lld", rotate, id); } + /* Not implemented yet * else if( strcasecmp(key, "pixelshape") == 0 ) { pixelshape = val; } */ item = strtok_r(NULL, "&,", &saveptr); } - free(path); - if( h->reqflags & FLAG_XFERSTREAMING || h->reqflags & FLAG_RANGE ) +#if USE_FORK + pid_t newpid = 0; + newpid = fork(); + if( newpid ) { - DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Streaming with a resized image!\n"); + CloseSocket_upnphttp(h); + goto resized_error; + } +#endif + if( h->reqflags & (FLAG_XFERSTREAMING|FLAG_RANGE) ) + { + DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Streaming with an image!\n"); Send406(h); goto resized_error; } DPRINTF(E_INFO, L_HTTP, "Serving resized image for ObjectId: %lld [%s]\n", id, file_path); - /* Figure out the best destination resolution we can use */ + srcw = strtol(resolution, &saveptr, 10); + srch = strtol(saveptr+1, NULL, 10); dstw = width; dsth = ((((width<<10)/srcw)*srch)>>10); if( dsth > height ) @@ -1647,6 +1646,27 @@ SendResp_resizedimg(struct upnphttp * h, char * object) dsth = height; dstw = (((height<<10)/srch) * srcw>>10); } + switch( rotate ) + { + case 90: + rotate = dsth; + dsth = dstw; + dstw = rotate; + rotate = ROTATE_90; + break; + case 270: + rotate = dsth; + dsth = dstw; + dstw = rotate; + rotate = ROTATE_270; + break; + case 180: + rotate = ROTATE_180; + break; + default: + rotate = ROTATE_NONE; + break; + } if( dstw <= 640 && dsth <= 480 ) strcpy(dlna_pn, "SM"); @@ -1655,11 +1675,11 @@ SendResp_resizedimg(struct upnphttp * h, char * object) else strcpy(dlna_pn, "LRG"); - if( srcw>>3 >= dstw && srch>>3 >= dsth) + if( srcw>>4 >= dstw && srch>>4 >= dsth) scale = 8; - else if( srcw>>2 >= dstw && srch>>2 >= dsth ) + else if( srcw>>3 >= dstw && srch>>3 >= dsth ) scale = 4; - else if( srcw>>1 >= dstw && srch>>1 >= dsth ) + else if( srcw>>2 >= dstw && srch>>2 >= dsth ) scale = 2; str.data = header; @@ -1688,7 +1708,7 @@ SendResp_resizedimg(struct upnphttp * h, char * object) if( strcmp(h->HttpVer, "HTTP/1.0") == 0 ) { chunked = 0; - imsrc = image_new_from_jpeg(file_path, 1, NULL, 0, scale); + imsrc = image_new_from_jpeg(file_path, 1, NULL, 0, scale, rotate); } else { @@ -1715,7 +1735,7 @@ SendResp_resizedimg(struct upnphttp * h, char * object) { if( chunked ) { - imsrc = image_new_from_jpeg(file_path, 1, NULL, 0, scale); + imsrc = image_new_from_jpeg(file_path, 1, NULL, 0, scale, rotate); if( !imsrc ) { DPRINTF(E_WARN, L_HTTP, "Unable to open image %s!\n", file_path); @@ -1725,8 +1745,8 @@ SendResp_resizedimg(struct upnphttp * h, char * object) imdst = image_resize(imsrc, dstw, dsth); data = image_save_to_jpeg_buf(imdst, &size); - ret = sprintf(str_buf, "%x\r\n", size); - send_data(h, str_buf, ret, MSG_MORE); + ret = sprintf(buf, "%x\r\n", size); + send_data(h, buf, ret, MSG_MORE); send_data(h, (char *)data, size, MSG_MORE); send_data(h, "\r\n0\r\n\r\n", 7, 0); } @@ -1754,7 +1774,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) { char header[1024]; struct string_s str; - char sql_buf[256]; + char buf[128]; char **result; int rows, ret; char date[30]; @@ -1775,15 +1795,15 @@ SendResp_dlnafile(struct upnphttp * h, char * object) id = strtoll(object, NULL, 10); if( id != last_file.id || h->req_client != last_file.client ) { - sprintf(sql_buf, "SELECT PATH, MIME, DLNA_PN from DETAILS where ID = '%lld'", id); - ret = sql_get_table(db, sql_buf, &result, &rows, NULL); + snprintf(buf, sizeof(buf), "SELECT PATH, MIME, DLNA_PN from DETAILS where ID = '%lld'", id); + ret = sql_get_table(db, buf, &result, &rows, NULL); if( (ret != SQLITE_OK) ) { DPRINTF(E_ERROR, L_HTTP, "Didn't find valid file for %lld!\n", id); Send500(h); return; } - if( !rows || !result[3] ) + if( !rows || !result[3] || !result[4] ) { DPRINTF(E_WARN, L_HTTP, "%s not found, responding ERROR 404\n", object); sqlite3_free_table(result); @@ -1817,10 +1837,6 @@ SendResp_dlnafile(struct upnphttp * h, char * object) strcpy(last_file.mime+6, "divx"); } } - else - { - last_file.mime[0] = '\0'; - } if( result[5] ) snprintf(last_file.dlna, sizeof(last_file.dlna), "DLNA.ORG_PN=%s", result[5]); else if( h->reqflags & FLAG_DLNA ) @@ -1935,22 +1951,16 @@ SendResp_dlnafile(struct upnphttp * h, char * object) { if( (strncmp(last_file.mime, "video", 5) == 0) || (strncmp(last_file.mime, "audio", 5) == 0) ) - { strcatf(&str, "transferMode.dlna.org: Streaming\r\n"); - } else - { strcatf(&str, "transferMode.dlna.org: Interactive\r\n"); - } } if( h->reqflags & FLAG_CAPTION ) { if( sql_get_int_field(db, "SELECT ID from CAPTIONS where ID = '%lld'", id) > 0 ) - { strcatf(&str, "CaptionInfo.sec: http://%s:%d/Captions/%lld.srt\r\n", lan_addr[h->iface].str, runtime_vars.port, id); - } } strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));