mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-26 14:13:18 -05:00
Add support for JPEG as a valid artwork output format
Reduce CPU usage by avoiding unneeded JPEG -> PNG conversions; it appears all the clients we care about support JPEG as well as PNG.
This commit is contained in:
parent
5cf5cac9c2
commit
c7209ab699
151
src/artwork.c
151
src/artwork.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Julien BLACHE <jb@jblache.org>
|
||||
* Copyright (C) 2010-2011 Julien BLACHE <jb@jblache.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -96,7 +96,7 @@ artwork_read(char *filename, struct evbuffer *evbuf)
|
||||
}
|
||||
|
||||
static int
|
||||
artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct evbuffer *evbuf)
|
||||
artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf)
|
||||
{
|
||||
uint8_t *buf;
|
||||
uint8_t *outbuf;
|
||||
@ -109,7 +109,10 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct ev
|
||||
AVStream *dst_st;
|
||||
|
||||
AVCodec *img_decoder;
|
||||
AVCodec *png_encoder;
|
||||
AVCodec *img_encoder;
|
||||
|
||||
int64_t pix_fmt_mask;
|
||||
const enum PixelFormat *pix_fmts;
|
||||
|
||||
AVFrame *i_frame;
|
||||
AVFrame *o_frame;
|
||||
@ -156,7 +159,31 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct ev
|
||||
goto out_close_src;
|
||||
}
|
||||
|
||||
dst_fmt->video_codec = CODEC_ID_PNG;
|
||||
dst_fmt->video_codec = CODEC_ID_NONE;
|
||||
|
||||
/* Try to keep same codec if possible */
|
||||
if ((src->codec_id == CODEC_ID_PNG) && (format & ART_CAN_PNG))
|
||||
dst_fmt->video_codec = CODEC_ID_PNG;
|
||||
else if ((src->codec_id == CODEC_ID_MJPEG) && (format & ART_CAN_JPEG))
|
||||
dst_fmt->video_codec = CODEC_ID_MJPEG;
|
||||
|
||||
/* If not possible, select new codec */
|
||||
if (dst_fmt->video_codec == CODEC_ID_NONE)
|
||||
{
|
||||
if (format & ART_CAN_PNG)
|
||||
dst_fmt->video_codec = CODEC_ID_PNG;
|
||||
else if (format & ART_CAN_JPEG)
|
||||
dst_fmt->video_codec = CODEC_ID_MJPEG;
|
||||
}
|
||||
|
||||
img_encoder = avcodec_find_encoder(dst_fmt->video_codec);
|
||||
if (!img_encoder)
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "No suitable encoder found for codec ID %d\n", dst_fmt->video_codec);
|
||||
|
||||
ret = -1;
|
||||
goto out_close_src;
|
||||
}
|
||||
|
||||
dst_ctx = avformat_alloc_context();
|
||||
if (!dst_ctx)
|
||||
@ -196,7 +223,26 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct ev
|
||||
|
||||
dst->codec_id = dst_fmt->video_codec;
|
||||
dst->codec_type = CODEC_TYPE_VIDEO;
|
||||
dst->pix_fmt = PIX_FMT_RGB24;
|
||||
|
||||
pix_fmt_mask = 0;
|
||||
pix_fmts = img_encoder->pix_fmts;
|
||||
while (pix_fmts && (*pix_fmts != -1))
|
||||
{
|
||||
pix_fmt_mask |= (1 << *pix_fmts);
|
||||
pix_fmts++;
|
||||
}
|
||||
|
||||
dst->pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src->pix_fmt, 1, NULL);
|
||||
|
||||
if (dst->pix_fmt < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "Could not determine best pixel format\n");
|
||||
|
||||
goto out_free_dst;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "Selected pixel format: %d\n", dst->pix_fmt);
|
||||
|
||||
dst->time_base.num = 1;
|
||||
dst->time_base.den = 25;
|
||||
@ -214,16 +260,7 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct ev
|
||||
}
|
||||
|
||||
/* Open encoder */
|
||||
png_encoder = avcodec_find_encoder(dst_fmt->video_codec);
|
||||
if (!png_encoder)
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "No suitable encoder found for PNG\n");
|
||||
|
||||
ret = -1;
|
||||
goto out_free_dst;
|
||||
}
|
||||
|
||||
ret = avcodec_open(dst, png_encoder);
|
||||
ret = avcodec_open(dst, img_encoder);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "Could not open codec for encoding: %s\n", strerror(AVUNERROR(ret)));
|
||||
@ -379,7 +416,21 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct ev
|
||||
goto out_fclose_dst;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
switch (dst_fmt->video_codec)
|
||||
{
|
||||
case CODEC_ID_PNG:
|
||||
ret = ART_FMT_PNG;
|
||||
break;
|
||||
|
||||
case CODEC_ID_MJPEG:
|
||||
ret = ART_FMT_JPEG;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(E_LOG, L_ART, "Unhandled rescale output format\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
out_fclose_dst:
|
||||
url_fclose(dst_ctx->pb);
|
||||
@ -409,7 +460,7 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, struct ev
|
||||
}
|
||||
|
||||
static int
|
||||
artwork_get(char *filename, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||
{
|
||||
AVFormatContext *src_ctx;
|
||||
AVCodecContext *src;
|
||||
@ -417,6 +468,7 @@ artwork_get(char *filename, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
int target_w;
|
||||
int target_h;
|
||||
int need_rescale;
|
||||
int format_ok;
|
||||
int ret;
|
||||
|
||||
ret = av_open_input_file(&src_ctx, filename, NULL, 0, NULL);
|
||||
@ -436,12 +488,19 @@ artwork_get(char *filename, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
format_ok = 0;
|
||||
for (s = 0; s < src_ctx->nb_streams; s++)
|
||||
{
|
||||
if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_PNG)
|
||||
break;
|
||||
{
|
||||
format_ok = (format & ART_CAN_PNG) ? ART_FMT_PNG : 0;
|
||||
break;
|
||||
}
|
||||
else if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_MJPEG)
|
||||
break;
|
||||
{
|
||||
format_ok = (format & ART_CAN_JPEG) ? ART_FMT_JPEG : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == src_ctx->nb_streams)
|
||||
@ -495,11 +554,15 @@ artwork_get(char *filename, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "Destination width %d height %d\n", target_w, target_h);
|
||||
|
||||
/* Fastpath for PNG */
|
||||
if ((src->codec_id == CODEC_ID_PNG) && !need_rescale)
|
||||
ret = artwork_read(filename, evbuf);
|
||||
/* Fastpath */
|
||||
if (!need_rescale && format_ok)
|
||||
{
|
||||
ret = artwork_read(filename, evbuf);
|
||||
if (ret == 0)
|
||||
ret = format_ok;
|
||||
}
|
||||
else
|
||||
ret = artwork_rescale(src_ctx, s, target_w, target_h, evbuf);
|
||||
ret = artwork_rescale(src_ctx, s, target_w, target_h, format, evbuf);
|
||||
|
||||
av_close_input_file(src_ctx);
|
||||
|
||||
@ -514,7 +577,7 @@ artwork_get(char *filename, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
|
||||
|
||||
static int
|
||||
artwork_get_own_image(char *path, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||
{
|
||||
char artwork[PATH_MAX];
|
||||
char *ptr;
|
||||
@ -558,11 +621,11 @@ artwork_get_own_image(char *path, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
if (i == (sizeof(cover_extension) / sizeof(cover_extension[0])))
|
||||
return -1;
|
||||
|
||||
return artwork_get(artwork, max_w, max_h, evbuf);
|
||||
return artwork_get(artwork, max_w, max_h, format, evbuf);
|
||||
}
|
||||
|
||||
static int
|
||||
artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||
{
|
||||
char artwork[PATH_MAX];
|
||||
char *ptr;
|
||||
@ -616,12 +679,12 @@ artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, struct evbuff
|
||||
if (i == (sizeof(cover_basename) / sizeof(cover_basename[0])))
|
||||
return -1;
|
||||
|
||||
return artwork_get(artwork, max_w, max_h, evbuf);
|
||||
return artwork_get(artwork, max_w, max_h, format, evbuf);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
artwork_get_item(int id, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
artwork_get_item(int id, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||
{
|
||||
char *filename;
|
||||
int ret;
|
||||
@ -635,26 +698,24 @@ artwork_get_item(int id, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
/* FUTURE: look at embedded artwork */
|
||||
|
||||
/* Look for basename(filename).{png,jpg} */
|
||||
ret = artwork_get_own_image(filename, max_w, max_h, evbuf);
|
||||
if (ret == 0)
|
||||
ret = artwork_get_own_image(filename, max_w, max_h, format, evbuf);
|
||||
if (ret > 0)
|
||||
goto out;
|
||||
|
||||
/* Look for basedir(filename)/{artwork,cover}.{png,jpg} */
|
||||
ret = artwork_get_dir_image(filename, 0, max_w, max_h, evbuf);
|
||||
if (ret == 0)
|
||||
ret = artwork_get_dir_image(filename, 0, max_w, max_h, format, evbuf);
|
||||
if (ret > 0)
|
||||
goto out;
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "No artwork found for item id %d\n", id);
|
||||
|
||||
ret = -1;
|
||||
|
||||
out:
|
||||
free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
artwork_get_group(int id, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
artwork_get_group(int id, int max_w, int max_h, int format, struct evbuffer *evbuf)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct db_media_file_info dbmfi;
|
||||
@ -679,18 +740,18 @@ artwork_get_group(int id, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
goto files_art;
|
||||
}
|
||||
|
||||
got_art = 0;
|
||||
while ((!got_art) && ((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir))
|
||||
got_art = -1;
|
||||
while ((got_art < 0) && ((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir))
|
||||
{
|
||||
got_art = ! artwork_get_dir_image(dir, 1, max_w, max_h, evbuf);
|
||||
got_art = artwork_get_dir_image(dir, 1, max_w, max_h, format, evbuf);
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_ART, "Error fetching Q_GROUP_DIRS results\n");
|
||||
else if (got_art)
|
||||
return 0;
|
||||
else if (got_art > 0)
|
||||
return got_art;
|
||||
|
||||
|
||||
/* Then try individual files */
|
||||
@ -708,18 +769,18 @@ artwork_get_group(int id, int max_w, int max_h, struct evbuffer *evbuf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
got_art = 0;
|
||||
while ((!got_art) && ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
|
||||
got_art = -1;
|
||||
while ((got_art < 0) && ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
|
||||
{
|
||||
got_art = ! artwork_get_own_image(dbmfi.path, max_w, max_h, evbuf);
|
||||
got_art = artwork_get_own_image(dbmfi.path, max_w, max_h, format, evbuf);
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_ART, "Error fetching Q_GROUPITEMS results\n");
|
||||
else if (got_art)
|
||||
return 0;
|
||||
else if (got_art > 0)
|
||||
return got_art;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -2,10 +2,17 @@
|
||||
#ifndef __ARTWORK_H__
|
||||
#define __ARTWORK_H__
|
||||
|
||||
int
|
||||
artwork_get_item(int id, int max_w, int max_h, struct evbuffer *evbuf);
|
||||
#define ART_CAN_PNG (1 << 0)
|
||||
#define ART_CAN_JPEG (1 << 1)
|
||||
|
||||
#define ART_FMT_PNG 1
|
||||
#define ART_FMT_JPEG 2
|
||||
|
||||
|
||||
int
|
||||
artwork_get_group(int id, int max_w, int max_h, struct evbuffer *evbuf);
|
||||
artwork_get_item(int id, int max_w, int max_h, int format, struct evbuffer *evbuf);
|
||||
|
||||
int
|
||||
artwork_get_group(int id, int max_w, int max_h, int format, struct evbuffer *evbuf);
|
||||
|
||||
#endif /* !__ARTWORK_H__ */
|
||||
|
@ -2696,9 +2696,9 @@ daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char *
|
||||
}
|
||||
|
||||
if (strcmp(uri[2], "groups") == 0)
|
||||
ret = artwork_get_group(id, max_w, max_h, evbuf);
|
||||
ret = artwork_get_group(id, max_w, max_h, ART_CAN_PNG, evbuf);
|
||||
else if (strcmp(uri[2], "items") == 0)
|
||||
ret = artwork_get_item(id, max_w, max_h, evbuf);
|
||||
ret = artwork_get_item(id, max_w, max_h, ART_CAN_PNG, evbuf);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
|
@ -1269,7 +1269,7 @@ dacp_reply_nowplayingartwork(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
if (ret < 0)
|
||||
goto no_artwork;
|
||||
|
||||
ret = artwork_get_item(id, max_w, max_h, evbuf);
|
||||
ret = artwork_get_item(id, max_w, max_h, ART_CAN_PNG, evbuf);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (EVBUFFER_LENGTH(evbuf) > 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user