diff --git a/src/artwork.c b/src/artwork.c index 593a58b6..9214abbb 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -95,6 +95,56 @@ artwork_read(char *filename, struct evbuffer *evbuf) 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 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) { AVFormatContext *src_ctx; - AVCodecContext *src; int s; int target_w; int target_h; - int need_rescale; int format_ok; 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; @@ -588,52 +636,10 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e return -1; } - src = src_ctx->streams[s]->codec; - - 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); + ret = rescale_needed(src_ctx->streams[s]->codec, max_w, max_h, &target_w, &target_h); /* Fastpath */ - if (!need_rescale && format_ok) + if (!ret && format_ok) { ret = artwork_read(filename, evbuf); if (ret == 0) @@ -657,6 +663,103 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e 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 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; - /* 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} */ ret = artwork_get_own_image(filename, max_w, max_h, format, evbuf);