* Many changes for TiVo support. It actually [kinda] works. :)

This commit is contained in:
Justin Maggard
2009-03-13 08:39:37 +00:00
parent 3ae378cdc9
commit 7a2e3ae67a
17 changed files with 713 additions and 543 deletions

View File

@ -34,12 +34,10 @@
#include "upnpglobalvars.h"
#include "utils.h"
#include "log.h"
#include <sqlite3.h>
#include "sql.h"
#include <libexif/exif-loader.h>
#if 0 //JPEG_RESIZE
#include <gd.h>
#endif
#ifdef ENABLE_TIVO
#ifdef TIVO_SUPPORT
#include "tivo_utils.h"
#include "tivo_commands.h"
#endif
@ -480,7 +478,7 @@ static void
ProcessHttpQuery_upnphttp(struct upnphttp * h)
{
char HttpCommand[16];
char HttpUrl[256];
char HttpUrl[512];
char * HttpVer;
char * p;
int i;
@ -498,7 +496,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
while(*p!='/')
p++;
}
for(i = 0; i<255 && *p != ' ' && *p != '\r'; i++)
for(i = 0; i<511 && *p != ' ' && *p != '\r'; i++)
HttpUrl[i] = *(p++);
HttpUrl[i] = '\0';
while(*p==' ')
@ -507,9 +505,9 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
for(i = 0; i<15 && *p != '\r'; i++)
HttpVer[i] = *(p++);
HttpVer[i] = '\0';
DPRINTF(E_INFO, L_HTTP, "HTTP REQUEST : %s %s (%s)\n",
HttpCommand, HttpUrl, HttpVer);
DPRINTF(E_DEBUG, L_HTTP, "HTTP REQUEST:\n%.*s\n", h->req_buflen, h->req_buf);
/*DPRINTF(E_INFO, L_HTTP, "HTTP REQUEST : %s %s (%s)\n",
HttpCommand, HttpUrl, HttpVer);*/
DPRINTF(E_DEBUG, L_HTTP, "HTTP REQUEST: %.*s\n", h->req_buflen, h->req_buf);
ParseHttpHeaders(h);
/* see if we need to wait for remaining data */
@ -589,32 +587,33 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
SendResp_albumArt(h, HttpUrl+10);
CloseSocket_upnphttp(h);
}
#ifdef ENABLE_TIVO
#ifdef TIVO_SUPPORT
else if(strncmp(HttpUrl, "/TiVoConnect", 12) == 0)
{
if( *(HttpUrl+12) == '?' )
if( GETFLAG(TIVOMASK) )
{
ProcessTiVoCommand(h, HttpUrl+13);
}
else if( *(HttpUrl+12) == '/' )
{
printf("TiVo request: %c\n", *(HttpUrl+12));
Send404(h);
if( *(HttpUrl+12) == '?' )
{
ProcessTiVoCommand(h, HttpUrl+13);
}
else
{
printf("Invalid TiVo request! %s\n", HttpUrl+12);
Send404(h);
}
}
else
{
printf("Invalid TiVo request! %s\n", HttpUrl+12);
printf("TiVo request with out TiVo support enabled! %s\n", HttpUrl+12);
Send404(h);
}
}
#endif
#if 0 //JPEG_RESIZE
else if(strncmp(HttpUrl, "/Resized/", 9) == 0)
{
SendResp_resizedimg(h, HttpUrl+9);
CloseSocket_upnphttp(h);
}
#endif
else if(strncmp(HttpUrl, "/icons/", 7) == 0)
{
SendResp_icon(h, HttpUrl+7);
@ -829,7 +828,7 @@ void
SendResp_upnphttp(struct upnphttp * h)
{
int n;
DPRINTF(E_DEBUG, L_HTTP, "HTTP RESPONSE:\n%.*s\n", h->res_buflen, h->res_buf);
DPRINTF(E_DEBUG, L_HTTP, "HTTP RESPONSE: %.*s\n", h->res_buflen, h->res_buf);
n = send(h->socket, h->res_buf, h->res_buflen, 0);
if(n<0)
{
@ -1106,7 +1105,6 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
sqlite3_free_table(result);
}
#if 0 //JPEG_RESIZE
void
SendResp_resizedimg(struct upnphttp * h, char * object)
{
@ -1115,14 +1113,54 @@ SendResp_resizedimg(struct upnphttp * h, char * object)
char **result;
char date[30];
time_t curtime = time(NULL);
int n;
FILE *imgfile;
gdImagePtr imsrc = 0, imdst = 0;
int dstw, dsth, srcw, srch, size;
int width=640, height=480, dstw, dsth, rotation, size;
char * data;
char *path, *file_path;
char *resolution, *tn;
char *key, *val;
char *saveptr, *item;
char *pixelshape = NULL;
int rows=0, ret;
gdImagePtr imsrc = 0, imdst = 0;
ExifData *ed;
ExifLoader *l;
memset(header, 0, 1500);
path = strdup(object);
if( strtok_r(path, "?", &saveptr) )
{
item = strtok_r(NULL, "&", &saveptr);
//continue;
}
while( item != NULL )
{
#ifdef TIVO_SUPPORT
decodeString(item, 1);
#endif
val = item;
key = strsep(&val, "=");
DPRINTF(E_DEBUG, L_GENERAL, "%s: %s\n", key, val);
if( strcasecmp(key, "width") == 0 )
{
width = atoi(val);
}
else if( strcasecmp(key, "height") == 0 )
{
height = atoi(val);
}
else if( strcasecmp(key, "rotation") == 0 )
{
rotation = atoi(val);
}
else if( strcasecmp(key, "pixelshape") == 0 )
{
pixelshape = val;
}
item = strtok_r(NULL, "&", &saveptr);
}
strip_ext(path);
if( h->reqflags & FLAG_XFERSTREAMING || h->reqflags & FLAG_RANGE )
{
DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Streaming with a resized image!\n");
@ -1130,90 +1168,107 @@ SendResp_resizedimg(struct upnphttp * h, char * object)
return;
}
sprintf(sql_buf, "SELECT d.PATH, d.WIDTH, d.HEIGHT from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where OBJECT_ID = '%s'", object);
sqlite3_get_table(db, sql_buf, &result, 0, 0, 0);
DPRINTF(E_INFO, L_HTTP, "Serving up resized image for ObjectId: %s [%s]\n", object, result[1]);
if( access(result[3], F_OK) == 0 )
sprintf(sql_buf, "SELECT PATH, RESOLUTION, THUMBNAIL from DETAILS where ID = '%s'", path);
ret = sql_get_table(db, sql_buf, &result, &rows, NULL);
if( (ret != SQLITE_OK) || !rows || (access(result[3], F_OK) != 0) )
{
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
free(path);
DPRINTF(E_ERROR, L_HTTP, "Didn't find valid file for %s!\n", path);
return;
}
file_path = result[3];
resolution = result[4];
tn = result[5];
DPRINTF(E_INFO, L_HTTP, "Serving resized image for ObjectId: %s [%s]\n", path, file_path);
free(path);
imgfile = fopen(result[3], "r");
imsrc = gdImageCreateFromJpeg(imgfile);
imdst = gdImageCreateTrueColor(dstw, dsth);
srcw = atoi(result[4]);
srch = atoi(result[5]);
dstw = 640;
dsth = ((((640<<10)/srcw)*srch)>>10);
/* Resizing from a thumbnail is much faster than from a large image */
if( width <= 160 && height <= 120 && atoi(tn) )
{
l = exif_loader_new();
exif_loader_write_file(l, file_path);
ed = exif_loader_get_data(l);
exif_loader_unref(l);
if( !imsrc )
if( !ed || !ed->size )
{
if( ed )
exif_data_unref(ed);
Send404(h);
sqlite3_free_table(result);
return;
}
imsrc = gdImageCreateFromJpegPtr(ed->size, ed->data);
exif_data_unref(ed);
}
else
{
imgfile = fopen(file_path, "r");
if( !imgfile )
{
Send404(h);
goto error;
sqlite3_free_table(result);
return;
}
if( dsth > 480 )
{
dsth = 480;
dstw = (((480<<10)/srch) * srcw>>10);
}
gdImageCopyResized(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, srcw, srch);
data = (char *)gdImageJpegPtr(imdst, &size, -1);
sprintf(header, "%s 200 OK\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"Date: %s\r\n"
"EXT:\r\n"
"contentFeatures.dlna.org: DLNA.ORG_PN=JPEG_TN\r\n"
"Server: RAIDiator/4.1, UPnP/1.0, MiniDLNA_TN/1.0\r\n",
h->HttpVer, size, date);
if( h->reqflags & FLAG_XFERINTERACTIVE )
{
strcat(header, "transferMode.dlna.org: Interactive\r\n");
}
else if( h->reqflags & FLAG_XFERBACKGROUND )
{
strcat(header, "transferMode.dlna.org: Background\r\n");
}
strcat(header, "\r\n");
n = send(h->socket, header, strlen(header), 0);
if(n<0)
{
DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %s", strerror(errno));
}
else if(n < h->res_buflen)
{
/* TODO : handle correctly this case */
DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %d bytes sent (out of %d)\n",
n, h->res_buflen);
}
if( h->req_command == EHead )
{
goto error;
}
n = send(h->socket, data, size, 0);
if(n<0)
{
DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %s", strerror(errno));
}
else if(n < h->res_buflen)
{
/* TODO : handle correctly this case */
DPRINTF(E_ERROR, L_HTTP, "send(res_buf): %d bytes sent (out of %d)\n",
n, h->res_buflen);
}
gdFree(data);
imsrc = gdImageCreateFromJpeg(imgfile);
fclose(imgfile);
}
error:
if( !imsrc )
{
Send404(h);
sqlite3_free_table(result);
return;
}
/* Figure out the best destination resolution we can use */
dstw = width;
dsth = ((((width<<10)/imsrc->sx)*imsrc->sy)>>10);
if( dsth > height )
{
dsth = height;
dstw = (((height<<10)/imsrc->sy) * imsrc->sx>>10);
}
imdst = gdImageCreateTrueColor(dstw, dsth);
#if 0 // Use box filter resizer
#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
#endif
boxfilter_resize(imdst, imsrc, 0, 0, 0, 0, dstw, dsth, imsrc->sx, imsrc->sy);
data = (char *)gdImageJpegPtr(imdst, &size, 99);
DPRINTF(E_INFO, L_HTTP, "size: %d\n", size);
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
snprintf(header, sizeof(header)-50, "%s 200 OK\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"Date: %s\r\n"
"EXT:\r\n"
"contentFeatures.dlna.org: DLNA.ORG_PN=JPEG_TN\r\n"
"Server: RAIDiator/4.1, UPnP/1.0, MiniDLNA_TN/1.0\r\n",
h->HttpVer, size, date);
if( h->reqflags & FLAG_XFERINTERACTIVE )
{
strcat(header, "transferMode.dlna.org: Interactive\r\n");
}
else if( h->reqflags & FLAG_XFERBACKGROUND )
{
strcat(header, "transferMode.dlna.org: Background\r\n");
}
strcat(header, "\r\n");
if( (send_data(h, header, strlen(header)) == 0) && (h->req_command != EHead) )
{
send_data(h, data, size);
}
gdFree(data);
gdImageDestroy(imsrc);
gdImageDestroy(imdst);
DPRINTF(E_INFO, L_HTTP, "Done serving %s\n", file_path);
sqlite3_free_table(result);
}
#endif
void
SendResp_dlnafile(struct upnphttp * h, char * object)