[pipe/artwork] Support for artwork via Shairport metadata pipes, take 3

This implementation uses a tmpfile for storage of the artwork, plus it uses
artwork_get() which means that it scales the image as requested by the client.

It also does not create a tmpfile unless we actually receive artwork.
This commit is contained in:
ejurgensen 2019-09-19 23:23:03 +02:00
parent ddb91e61ef
commit 7316c060b8
2 changed files with 51 additions and 38 deletions

View File

@ -852,10 +852,8 @@ static int
source_item_pipe_get(struct artwork_ctx *ctx)
{
struct db_queue_item *queue_item;
uint8_t header[2] = { 0 };
const char *proto = "file:";
char *path;
int ret;
DPRINTF(E_SPAM, L_ART, "Trying pipe metadata from %s.metadata\n", ctx->dbmfi->path);
@ -868,23 +866,9 @@ source_item_pipe_get(struct artwork_ctx *ctx)
path = queue_item->artwork_url + strlen(proto);
ret = artwork_read(ctx->evbuf, path);
if (ret < 0)
{
free_queue_item(queue_item, 0);
return ART_E_ERROR;
}
snprintf(ctx->path, sizeof(ctx->path), "%s", path);
free_queue_item(queue_item, 0);
evbuffer_copyout(ctx->evbuf, header, sizeof(header));
if (header[0] == 0xff && header[1] == 0xd8)
return ART_FMT_JPEG;
else if (header[0] == 0x89 && header[1] == 0x50)
return ART_FMT_PNG;
else
return ART_E_ERROR;
return artwork_get(ctx->evbuf, path, NULL, ctx->max_w, ctx->max_h, false);
}
#ifdef HAVE_SPOTIFY_H

View File

@ -75,7 +75,8 @@
// Ignore pictures with larger size than this
#define PIPE_PICTURE_SIZE_MAX 262144
// Where we store pictures for the artwork module to read
#define PIPE_TMPFILE_TEMPLATE "/tmp/forked-daapd.XXXXXX"
#define PIPE_TMPFILE_TEMPLATE "/tmp/forked-daapd.XXXXXX.ext"
#define PIPE_TMPFILE_TEMPLATE_EXTLEN 4
enum pipetype
{
@ -298,6 +299,36 @@ dmapval(const char s[4])
return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] << 0));
}
static void
pict_tmpfile_close(struct pipe_metadata *pm)
{
if (pm->pict_tmpfile_fd < 0)
return;
close(pm->pict_tmpfile_fd);
unlink(pm->pict_tmpfile_path);
pm->pict_tmpfile_fd = -1;
}
// Opens a tmpfile to store metadata artwork in. *ext is the extension to use
// for the tmpfile, eg .jpg or .png. Extension cannot be longer than
// PIPE_TMPFILE_TEMPLATE_EXTLEN.
static int
pict_tmpfile_recreate(struct pipe_metadata *pm, const char *ext)
{
int offset = strlen(PIPE_TMPFILE_TEMPLATE) - PIPE_TMPFILE_TEMPLATE_EXTLEN;
pict_tmpfile_close(pm);
strcpy(pm->pict_tmpfile_path, PIPE_TMPFILE_TEMPLATE);
strncpy(pm->pict_tmpfile_path + offset, ext, PIPE_TMPFILE_TEMPLATE_EXTLEN);
pm->pict_tmpfile_fd = mkstemps(pm->pict_tmpfile_path, PIPE_TMPFILE_TEMPLATE_EXTLEN);
return pm->pict_tmpfile_fd;
}
static void
handle_progress(struct input_metadata *m, char *progress)
{
@ -370,32 +401,39 @@ handle_volume(const char *volume)
static void
handle_picture(struct input_metadata *m, uint8_t *data, int data_len)
{
const char *ext;
ssize_t ret;
free(m->artwork_url);
m->artwork_url = NULL;
if (pipe_metadata.pict_tmpfile_fd < 0)
return;
if (data_len < 2 || data_len > PIPE_PICTURE_SIZE_MAX)
{
DPRINTF(E_WARN, L_PLAYER, "Unsupported picture size (%d) from Shairport metadata pipe\n", data_len);
return;
}
// Reset in case we previously wrote to the tmp file
lseek(pipe_metadata.pict_tmpfile_fd, 0L, SEEK_SET);
if (data[0] == 0xff && data[1] == 0xd8)
ext = ".jpg";
else if (data[0] == 0x89 && data[1] == 0x50)
ext = ".png";
pict_tmpfile_recreate(&pipe_metadata, ext);
if (pipe_metadata.pict_tmpfile_fd < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not open tmpfile for pipe artwork '%s': %s\n", pipe_metadata.pict_tmpfile_path, strerror(errno));
return;
}
ret = write(pipe_metadata.pict_tmpfile_fd, data, data_len);
if (ret < 0)
{
DPRINTF(E_WARN, L_PLAYER, "Error writing artwork from metadata pipe to '%s': %s\n", pipe_metadata.pict_tmpfile_path, strerror(errno));
DPRINTF(E_LOG, L_PLAYER, "Error writing artwork from metadata pipe to '%s': %s\n", pipe_metadata.pict_tmpfile_path, strerror(errno));
return;
}
else if (ret != data_len)
{
DPRINTF(E_WARN, L_PLAYER, "Incomplete write of artwork to '%s' (%zd/%d)\n", pipe_metadata.pict_tmpfile_path, ret, data_len);
DPRINTF(E_LOG, L_PLAYER, "Incomplete write of artwork to '%s' (%zd/%d)\n", pipe_metadata.pict_tmpfile_path, ret, data_len);
return;
}
@ -695,11 +733,7 @@ pipe_metadata_watch_del(void *arg)
pipe_free(pipe_metadata.pipe);
pipe_metadata.pipe = NULL;
if (pipe_metadata.pict_tmpfile_fd >= 0)
{
close(pipe_metadata.pict_tmpfile_fd);
unlink(pipe_metadata.pict_tmpfile_path);
}
pict_tmpfile_close(&pipe_metadata);
}
// Some metadata arrived on a pipe we watch
@ -775,13 +809,6 @@ pipe_metadata_watch_add(void *arg)
pipe_metadata.pipe = NULL;
return;
}
// Try to open a tmpfile to store metadata artwork in (the PICT tag). If we
// can't open a tmpfile we will just ignore artwork.
strcpy(pipe_metadata.pict_tmpfile_path, PIPE_TMPFILE_TEMPLATE);
pipe_metadata.pict_tmpfile_fd = mkstemp(pipe_metadata.pict_tmpfile_path);
if (pipe_metadata.pict_tmpfile_fd < 0)
DPRINTF(E_WARN, L_PLAYER, "Error opening tmpfile for metadata pipe artwork: %s\n", strerror(errno));
}
@ -999,6 +1026,8 @@ init(void)
{
CHECK_ERR(L_PLAYER, mutex_init(&pipe_metadata.lock));
pipe_metadata.pict_tmpfile_fd = -1;
pipe_autostart = cfg_getbool(cfg_getsec(cfg, "library"), "pipe_autostart");
if (pipe_autostart)
{