mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-27 06:33:21 -05:00
Support for embedded artwork (items only)
This commit is contained in:
parent
a1236f4400
commit
a6b586a0ce
208
src/artwork.c
208
src/artwork.c
@ -95,6 +95,56 @@ artwork_read(char *filename, struct evbuffer *evbuf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rescale_needed(AVCodecContext *src, int max_w, int max_h, int *target_w, int *target_h)
|
||||||
|
{
|
||||||
|
int need_rescale;
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_ART, "Original image dimensions: w %d h %d\n", src->width, src->height);
|
||||||
|
|
||||||
|
need_rescale = 1;
|
||||||
|
|
||||||
|
if ((max_w <= 0) || (max_h <= 0)) /* No valid dimensions, use original */
|
||||||
|
{
|
||||||
|
need_rescale = 0;
|
||||||
|
|
||||||
|
*target_w = src->width;
|
||||||
|
*target_h = src->height;
|
||||||
|
}
|
||||||
|
else if ((src->width <= max_w) && (src->height <= max_h)) /* Smaller than target */
|
||||||
|
{
|
||||||
|
need_rescale = 0;
|
||||||
|
|
||||||
|
*target_w = src->width;
|
||||||
|
*target_h = src->height;
|
||||||
|
}
|
||||||
|
else if (src->width * max_h > src->height * max_w) /* Wider aspect ratio than target */
|
||||||
|
{
|
||||||
|
*target_w = max_w;
|
||||||
|
*target_h = (double)max_w * ((double)src->height / (double)src->width);
|
||||||
|
}
|
||||||
|
else /* Taller or equal aspect ratio */
|
||||||
|
{
|
||||||
|
*target_w = (double)max_h * ((double)src->width / (double)src->height);
|
||||||
|
*target_h = max_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_ART, "Raw destination width %d height %d\n", *target_w, *target_h);
|
||||||
|
|
||||||
|
if ((*target_h > max_h) && (max_h > 0))
|
||||||
|
*target_h = max_h;
|
||||||
|
|
||||||
|
/* PNG prefers even row count */
|
||||||
|
*target_w += *target_w % 2;
|
||||||
|
|
||||||
|
if ((*target_w > max_w) && (max_w > 0))
|
||||||
|
*target_w = max_w - (max_w % 2);
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_ART, "Destination width %d height %d\n", *target_w, *target_h);
|
||||||
|
|
||||||
|
return need_rescale;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf)
|
artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf)
|
||||||
{
|
{
|
||||||
@ -520,15 +570,13 @@ static int
|
|||||||
artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||||
{
|
{
|
||||||
AVFormatContext *src_ctx;
|
AVFormatContext *src_ctx;
|
||||||
AVCodecContext *src;
|
|
||||||
int s;
|
int s;
|
||||||
int target_w;
|
int target_w;
|
||||||
int target_h;
|
int target_h;
|
||||||
int need_rescale;
|
|
||||||
int format_ok;
|
int format_ok;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Artwork request parameters: max w = %d, max h = %d\n", max_w, max_h);
|
DPRINTF(E_DBG, L_ART, "Artwork request for %s, max w = %d, max h = %d\n", filename, max_w, max_h);
|
||||||
|
|
||||||
src_ctx = NULL;
|
src_ctx = NULL;
|
||||||
|
|
||||||
@ -588,52 +636,10 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
src = src_ctx->streams[s]->codec;
|
ret = rescale_needed(src_ctx->streams[s]->codec, max_w, max_h, &target_w, &target_h);
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Original image '%s': w %d h %d\n", filename, src->width, src->height);
|
|
||||||
|
|
||||||
need_rescale = 1;
|
|
||||||
|
|
||||||
if ((max_w <= 0) || (max_h <= 0)) /* No valid dimensions, use original */
|
|
||||||
{
|
|
||||||
need_rescale = 0;
|
|
||||||
|
|
||||||
target_w = src->width;
|
|
||||||
target_h = src->height;
|
|
||||||
}
|
|
||||||
else if ((src->width <= max_w) && (src->height <= max_h)) /* Smaller than target */
|
|
||||||
{
|
|
||||||
need_rescale = 0;
|
|
||||||
|
|
||||||
target_w = src->width;
|
|
||||||
target_h = src->height;
|
|
||||||
}
|
|
||||||
else if (src->width * max_h > src->height * max_w) /* Wider aspect ratio than target */
|
|
||||||
{
|
|
||||||
target_w = max_w;
|
|
||||||
target_h = (double)max_w * ((double)src->height / (double)src->width);
|
|
||||||
}
|
|
||||||
else /* Taller or equal aspect ratio */
|
|
||||||
{
|
|
||||||
target_w = (double)max_h * ((double)src->width / (double)src->height);
|
|
||||||
target_h = max_h;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Raw destination width %d height %d\n", target_w, target_h);
|
|
||||||
|
|
||||||
if ((target_h > max_h) && (max_h > 0))
|
|
||||||
target_h = max_h;
|
|
||||||
|
|
||||||
/* PNG prefers even row count */
|
|
||||||
target_w += target_w % 2;
|
|
||||||
|
|
||||||
if ((target_w > max_w) && (max_w > 0))
|
|
||||||
target_w = max_w - (max_w % 2);
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Destination width %d height %d\n", target_w, target_h);
|
|
||||||
|
|
||||||
/* Fastpath */
|
/* Fastpath */
|
||||||
if (!need_rescale && format_ok)
|
if (!ret && format_ok)
|
||||||
{
|
{
|
||||||
ret = artwork_read(filename, evbuf);
|
ret = artwork_read(filename, evbuf);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@ -657,6 +663,103 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
artwork_get_embedded_image(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||||
|
{
|
||||||
|
AVFormatContext *src_ctx;
|
||||||
|
AVStream *src_st;
|
||||||
|
int s;
|
||||||
|
int target_w;
|
||||||
|
int target_h;
|
||||||
|
int format_ok;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_ART, "Artwork request for %s, max w = %d, max h = %d\n", filename, max_w, max_h);
|
||||||
|
|
||||||
|
src_ctx = NULL;
|
||||||
|
|
||||||
|
ret = avformat_open_input(&src_ctx, filename, NULL, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_WARN, L_ART, "Cannot open media file '%s': %s\n", filename, strerror(AVUNERROR(ret)));
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = avformat_find_stream_info(src_ctx, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_WARN, L_ART, "Cannot get stream info: %s\n", strerror(AVUNERROR(ret)));
|
||||||
|
|
||||||
|
avformat_close_input(&src_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_ok = 0;
|
||||||
|
for (s = 0; s < src_ctx->nb_streams; s++)
|
||||||
|
{
|
||||||
|
if (src_ctx->streams[s]->disposition & AV_DISPOSITION_ATTACHED_PIC)
|
||||||
|
{
|
||||||
|
if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_PNG)
|
||||||
|
{
|
||||||
|
format_ok = (format & ART_CAN_PNG) ? ART_FMT_PNG : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_MJPEG)
|
||||||
|
{
|
||||||
|
format_ok = (format & ART_CAN_JPEG) ? ART_FMT_JPEG : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == src_ctx->nb_streams)
|
||||||
|
{
|
||||||
|
DPRINTF(E_DBG, L_ART, "Did not find embedded artwork in '%s'\n", filename);
|
||||||
|
|
||||||
|
avformat_close_input(&src_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_st = src_ctx->streams[s];
|
||||||
|
|
||||||
|
ret = rescale_needed(src_st->codec, max_w, max_h, &target_w, &target_h);
|
||||||
|
|
||||||
|
/* Fastpath */
|
||||||
|
if (!ret && format_ok)
|
||||||
|
{
|
||||||
|
DPRINTF(E_DBG, L_ART, "Artwork does not need rescale, sending original picture\n");
|
||||||
|
|
||||||
|
ret = evbuffer_expand(evbuf, src_st->attached_pic.size);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_ART, "Out of memory for artwork\n");
|
||||||
|
|
||||||
|
avformat_close_input(&src_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = evbuffer_add(evbuf, src_st->attached_pic.data, src_st->attached_pic.size);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_ART, "Could not add embedded image to event buffer\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = format_ok;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = artwork_rescale(src_ctx, s, target_w, target_h, format, evbuf);
|
||||||
|
|
||||||
|
avformat_close_input(&src_ctx);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
if (EVBUFFER_LENGTH(evbuf) > 0)
|
||||||
|
evbuffer_drain(evbuf, EVBUFFER_LENGTH(evbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||||
@ -836,7 +939,16 @@ artwork_get_item_filename(char *filename, int max_w, int max_h, int format, stru
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* FUTURE: look at embedded artwork */
|
/* If item is an internet stream don't look for artwork */
|
||||||
|
if (strncmp(filename, "http://", strlen("http://")) == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#if LIBAVFORMAT_VERSION_MAJOR >= 55 || (LIBAVFORMAT_VERSION_MAJOR == 54 && LIBAVFORMAT_VERSION_MINOR >= 20)
|
||||||
|
/* Look for embedded artwork */
|
||||||
|
ret = artwork_get_embedded_image(filename, max_w, max_h, format, evbuf);
|
||||||
|
if (ret > 0)
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Look for basename(filename).{png,jpg} */
|
/* Look for basename(filename).{png,jpg} */
|
||||||
ret = artwork_get_own_image(filename, max_w, max_h, format, evbuf);
|
ret = artwork_get_own_image(filename, max_w, max_h, format, evbuf);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user