mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-28 08:05:56 -05:00
[artwork/transcode] Also let transcode.c handle rescaling of non-file Spotify artwork
This commit is contained in:
parent
e7f888645f
commit
441ad006a6
@ -324,13 +324,14 @@ rescale_calculate(int *target_w, int *target_h, int width, int height, int max_w
|
|||||||
/* Get an artwork file from the filesystem. Will rescale if needed.
|
/* Get an artwork file from the filesystem. Will rescale if needed.
|
||||||
*
|
*
|
||||||
* @out evbuf Image data
|
* @out evbuf Image data
|
||||||
* @in path Path to the artwork
|
* @in path Path to the artwork (alternative to inbuf)
|
||||||
|
* @in inbuf Buffer with the artwork (alternative to path)
|
||||||
* @in max_w Requested width
|
* @in max_w Requested width
|
||||||
* @in max_h Requested height
|
* @in max_h Requested height
|
||||||
* @return ART_FMT_* on success, ART_E_ERROR on error
|
* @return ART_FMT_* on success, ART_E_ERROR on error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h)
|
artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *inbuf, int max_w, int max_h)
|
||||||
{
|
{
|
||||||
struct decode_ctx *xcode_decode;
|
struct decode_ctx *xcode_decode;
|
||||||
struct encode_ctx *xcode_encode;
|
struct encode_ctx *xcode_encode;
|
||||||
@ -344,7 +345,7 @@ artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h)
|
|||||||
|
|
||||||
DPRINTF(E_SPAM, L_ART, "Getting artwork (max destination width %d height %d)\n", max_w, max_h);
|
DPRINTF(E_SPAM, L_ART, "Getting artwork (max destination width %d height %d)\n", max_w, max_h);
|
||||||
|
|
||||||
xcode_decode = transcode_decode_setup(XCODE_PNG, DATA_KIND_FILE, path, 0); // Good for XCODE_JPEG too
|
xcode_decode = transcode_decode_setup(XCODE_JPEG, DATA_KIND_FILE, path, inbuf, 0); // Covers XCODE_PNG too
|
||||||
if (!xcode_decode)
|
if (!xcode_decode)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, L_ART, "No artwork found in '%s'\n", path);
|
DPRINTF(E_DBG, L_ART, "No artwork found in '%s'\n", path);
|
||||||
@ -368,7 +369,7 @@ artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
// No rescaling required, just read the raw file into the evbuf
|
// No rescaling required, just read the raw file into the evbuf
|
||||||
if (artwork_read(evbuf, path) != 0)
|
if (!path || artwork_read(evbuf, path) != 0)
|
||||||
goto fail_free_decode;
|
goto fail_free_decode;
|
||||||
|
|
||||||
transcode_decode_cleanup(&xcode_decode);
|
transcode_decode_cleanup(&xcode_decode);
|
||||||
@ -518,7 +519,7 @@ artwork_get_dir_image(struct evbuffer *evbuf, char *dir, int max_w, int max_h, c
|
|||||||
|
|
||||||
snprintf(out_path, PATH_MAX, "%s", path);
|
snprintf(out_path, PATH_MAX, "%s", path);
|
||||||
|
|
||||||
return artwork_get(evbuf, path, max_w, max_h);
|
return artwork_get(evbuf, path, NULL, max_w, max_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -631,7 +632,7 @@ source_item_embedded_get(struct artwork_ctx *ctx)
|
|||||||
|
|
||||||
snprintf(ctx->path, sizeof(ctx->path), "%s", ctx->dbmfi->path);
|
snprintf(ctx->path, sizeof(ctx->path), "%s", ctx->dbmfi->path);
|
||||||
|
|
||||||
return artwork_get(ctx->evbuf, ctx->path, ctx->max_w, ctx->max_h);
|
return artwork_get(ctx->evbuf, ctx->path, NULL, ctx->max_w, ctx->max_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Looks for basename(in_path).{png,jpg}, so if in_path is /foo/bar.mp3 it
|
/* Looks for basename(in_path).{png,jpg}, so if in_path is /foo/bar.mp3 it
|
||||||
@ -685,7 +686,7 @@ source_item_own_get(struct artwork_ctx *ctx)
|
|||||||
|
|
||||||
snprintf(ctx->path, sizeof(ctx->path), "%s", path);
|
snprintf(ctx->path, sizeof(ctx->path), "%s", path);
|
||||||
|
|
||||||
return artwork_get(ctx->evbuf, path, ctx->max_w, ctx->max_h);
|
return artwork_get(ctx->evbuf, path, NULL, ctx->max_w, ctx->max_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -774,13 +775,8 @@ source_item_stream_get(struct artwork_ctx *ctx)
|
|||||||
static int
|
static int
|
||||||
source_item_spotify_get(struct artwork_ctx *ctx)
|
source_item_spotify_get(struct artwork_ctx *ctx)
|
||||||
{
|
{
|
||||||
AVFormatContext *src_ctx;
|
|
||||||
AVIOContext *avio;
|
|
||||||
AVInputFormat *ifmt;
|
|
||||||
struct evbuffer *raw;
|
struct evbuffer *raw;
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
int target_w;
|
|
||||||
int target_h;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
raw = evbuffer_new();
|
raw = evbuffer_new();
|
||||||
@ -820,75 +816,29 @@ source_item_spotify_get(struct artwork_ctx *ctx)
|
|||||||
goto out_free_evbuf;
|
goto out_free_evbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now evbuf will be processed by ffmpeg, since it probably needs to be rescaled
|
// For non-file input, artwork_get() will also fail if no rescaling is required
|
||||||
src_ctx = avformat_alloc_context();
|
ret = artwork_get(ctx->evbuf, NULL, evbuf, ctx->max_w, ctx->max_h);
|
||||||
if (!src_ctx)
|
if (ret == ART_E_ERROR)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_ART, "Out of memory for source context\n");
|
DPRINTF(E_DBG, L_ART, "Not rescaling Spotify image\n");
|
||||||
goto out_free_evbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
avio = avio_input_evbuffer_open(evbuf);
|
|
||||||
if (!avio)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Could not alloc input evbuffer\n");
|
|
||||||
goto out_free_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_ctx->pb = avio;
|
|
||||||
|
|
||||||
ifmt = av_find_input_format("mjpeg");
|
|
||||||
if (!ifmt)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Could not find mjpeg input format\n");
|
|
||||||
goto out_close_avio;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = avformat_open_input(&src_ctx, NULL, ifmt, NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Could not open input\n");
|
|
||||||
goto out_close_avio;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = avformat_find_stream_info(src_ctx, NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Could not find stream info\n");
|
|
||||||
goto out_close_input;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rescale_needed(src_ctx->streams[0]->codec, ctx->max_w, ctx->max_h, &target_w, &target_h);
|
|
||||||
if (!ret)
|
|
||||||
ret = evbuffer_add_buffer(ctx->evbuf, raw);
|
ret = evbuffer_add_buffer(ctx->evbuf, raw);
|
||||||
else
|
|
||||||
ret = artwork_rescale(ctx->evbuf, src_ctx, 0, target_w, target_h);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_ART, "Could not add or rescale image to output evbuf\n");
|
DPRINTF(E_LOG, L_ART, "Could not add or rescale image to output evbuf\n");
|
||||||
goto out_close_input;
|
goto out_free_evbuf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
avformat_close_input(&src_ctx);
|
|
||||||
avio_evbuffer_close(avio);
|
|
||||||
evbuffer_free(evbuf);
|
evbuffer_free(evbuf);
|
||||||
evbuffer_free(raw);
|
evbuffer_free(raw);
|
||||||
|
|
||||||
return ART_FMT_JPEG;
|
return ART_FMT_JPEG;
|
||||||
|
|
||||||
out_close_input:
|
|
||||||
avformat_close_input(&src_ctx);
|
|
||||||
out_close_avio:
|
|
||||||
avio_evbuffer_close(avio);
|
|
||||||
out_free_ctx:
|
|
||||||
if (src_ctx)
|
|
||||||
avformat_free_context(src_ctx);
|
|
||||||
out_free_evbuf:
|
out_free_evbuf:
|
||||||
evbuffer_free(evbuf);
|
evbuffer_free(evbuf);
|
||||||
evbuffer_free(raw);
|
evbuffer_free(raw);
|
||||||
|
|
||||||
return ART_E_ERROR;
|
return ART_E_ERROR;
|
||||||
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int
|
static int
|
||||||
|
@ -125,6 +125,9 @@ avio_evbuffer_close(AVIOContext *s)
|
|||||||
{
|
{
|
||||||
struct avio_evbuffer *ae;
|
struct avio_evbuffer *ae;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return;
|
||||||
|
|
||||||
ae = (struct avio_evbuffer *)s->opaque;
|
ae = (struct avio_evbuffer *)s->opaque;
|
||||||
|
|
||||||
avio_flush(s);
|
avio_flush(s);
|
||||||
|
@ -70,6 +70,9 @@ struct settings_ctx
|
|||||||
// Output format (for the muxer)
|
// Output format (for the muxer)
|
||||||
const char *format;
|
const char *format;
|
||||||
|
|
||||||
|
// Input format (for the demuxer)
|
||||||
|
const char *in_format;
|
||||||
|
|
||||||
// Audio settings
|
// Audio settings
|
||||||
enum AVCodecID audio_codec;
|
enum AVCodecID audio_codec;
|
||||||
const char *audio_codec_name;
|
const char *audio_codec_name;
|
||||||
@ -111,6 +114,9 @@ struct decode_ctx
|
|||||||
// Input format context
|
// Input format context
|
||||||
AVFormatContext *ifmt_ctx;
|
AVFormatContext *ifmt_ctx;
|
||||||
|
|
||||||
|
// IO Context for non-file input
|
||||||
|
AVIOContext *avio;
|
||||||
|
|
||||||
// Stream and decoder data
|
// Stream and decoder data
|
||||||
struct stream_ctx audio_stream;
|
struct stream_ctx audio_stream;
|
||||||
struct stream_ctx video_stream;
|
struct stream_ctx video_stream;
|
||||||
@ -219,6 +225,7 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile)
|
|||||||
settings->encode_video = 1;
|
settings->encode_video = 1;
|
||||||
settings->silent = 1;
|
settings->silent = 1;
|
||||||
settings->format = "image2";
|
settings->format = "image2";
|
||||||
|
settings->in_format = "mjpeg";
|
||||||
settings->video_codec = AV_CODEC_ID_MJPEG;
|
settings->video_codec = AV_CODEC_ID_MJPEG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -712,10 +719,11 @@ open_decoder(unsigned int *stream_index, struct decode_ctx *ctx, enum AVMediaTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
open_input(struct decode_ctx *ctx, const char *path)
|
open_input(struct decode_ctx *ctx, const char *path, struct evbuffer *evbuf)
|
||||||
{
|
{
|
||||||
AVDictionary *options = NULL;
|
AVDictionary *options = NULL;
|
||||||
AVCodecContext *dec_ctx;
|
AVCodecContext *dec_ctx;
|
||||||
|
AVInputFormat *ifmt;
|
||||||
unsigned int stream_index;
|
unsigned int stream_index;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -735,7 +743,24 @@ open_input(struct decode_ctx *ctx, const char *path)
|
|||||||
ctx->ifmt_ctx->interrupt_callback.opaque = ctx;
|
ctx->ifmt_ctx->interrupt_callback.opaque = ctx;
|
||||||
ctx->timestamp = av_gettime();
|
ctx->timestamp = av_gettime();
|
||||||
|
|
||||||
|
if (evbuf)
|
||||||
|
{
|
||||||
|
ifmt = av_find_input_format(ctx->settings.in_format);
|
||||||
|
if (!ifmt)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_XCODE, "Could not find input format: '%s'\n", ctx->settings.in_format);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_NULL(L_XCODE, ctx->avio = avio_input_evbuffer_open(evbuf));
|
||||||
|
|
||||||
|
ctx->ifmt_ctx->pb = ctx->avio;
|
||||||
|
ret = avformat_open_input(&ctx->ifmt_ctx, NULL, ifmt, &options);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ret = avformat_open_input(&ctx->ifmt_ctx, path, NULL, &options);
|
ret = avformat_open_input(&ctx->ifmt_ctx, path, NULL, &options);
|
||||||
|
}
|
||||||
|
|
||||||
if (options)
|
if (options)
|
||||||
av_dict_free(&options);
|
av_dict_free(&options);
|
||||||
@ -782,6 +807,7 @@ open_input(struct decode_ctx *ctx, const char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_fail:
|
out_fail:
|
||||||
|
avio_evbuffer_close(ctx->avio);
|
||||||
avcodec_free_context(&ctx->audio_stream.codec);
|
avcodec_free_context(&ctx->audio_stream.codec);
|
||||||
avcodec_free_context(&ctx->video_stream.codec);
|
avcodec_free_context(&ctx->video_stream.codec);
|
||||||
avformat_close_input(&ctx->ifmt_ctx);
|
avformat_close_input(&ctx->ifmt_ctx);
|
||||||
@ -792,6 +818,7 @@ open_input(struct decode_ctx *ctx, const char *path)
|
|||||||
static void
|
static void
|
||||||
close_input(struct decode_ctx *ctx)
|
close_input(struct decode_ctx *ctx)
|
||||||
{
|
{
|
||||||
|
avio_evbuffer_close(ctx->avio);
|
||||||
avcodec_free_context(&ctx->audio_stream.codec);
|
avcodec_free_context(&ctx->audio_stream.codec);
|
||||||
avcodec_free_context(&ctx->video_stream.codec);
|
avcodec_free_context(&ctx->video_stream.codec);
|
||||||
avformat_close_input(&ctx->ifmt_ctx);
|
avformat_close_input(&ctx->ifmt_ctx);
|
||||||
@ -1075,7 +1102,7 @@ close_filters(struct encode_ctx *ctx)
|
|||||||
/* Setup */
|
/* Setup */
|
||||||
|
|
||||||
struct decode_ctx *
|
struct decode_ctx *
|
||||||
transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, uint32_t song_length)
|
transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, struct evbuffer *evbuf, uint32_t song_length)
|
||||||
{
|
{
|
||||||
struct decode_ctx *ctx;
|
struct decode_ctx *ctx;
|
||||||
|
|
||||||
@ -1086,7 +1113,7 @@ transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind,
|
|||||||
ctx->duration = song_length;
|
ctx->duration = song_length;
|
||||||
ctx->data_kind = data_kind;
|
ctx->data_kind = data_kind;
|
||||||
|
|
||||||
if ((init_settings(&ctx->settings, profile) < 0) || (open_input(ctx, path) < 0))
|
if ((init_settings(&ctx->settings, profile) < 0) || (open_input(ctx, path, evbuf) < 0))
|
||||||
goto fail_free;
|
goto fail_free;
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
@ -1143,7 +1170,7 @@ transcode_setup(enum transcode_profile profile, enum data_kind data_kind, const
|
|||||||
|
|
||||||
CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct transcode_ctx)));
|
CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct transcode_ctx)));
|
||||||
|
|
||||||
ctx->decode_ctx = transcode_decode_setup(profile, data_kind, path, song_length);
|
ctx->decode_ctx = transcode_decode_setup(profile, data_kind, path, NULL, song_length);
|
||||||
if (!ctx->decode_ctx)
|
if (!ctx->decode_ctx)
|
||||||
{
|
{
|
||||||
free(ctx);
|
free(ctx);
|
||||||
@ -1403,8 +1430,6 @@ transcode_encode(struct evbuffer *evbuf, struct encode_ctx *ctx, void *frame, in
|
|||||||
|
|
||||||
ret = evbuffer_get_length(ctx->obuf) - start_length;
|
ret = evbuffer_get_length(ctx->obuf) - start_length;
|
||||||
|
|
||||||
// TODO Shouldn't we flush and let the muxer write the trailer now?
|
|
||||||
|
|
||||||
evbuffer_add_buffer(evbuf, ctx->obuf);
|
evbuffer_add_buffer(evbuf, ctx->obuf);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -25,7 +25,7 @@ struct transcode_ctx;
|
|||||||
|
|
||||||
// Setting up
|
// Setting up
|
||||||
struct decode_ctx *
|
struct decode_ctx *
|
||||||
transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, uint32_t song_length);
|
transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, const char *path, struct evbuffer *evbuf, uint32_t song_length);
|
||||||
|
|
||||||
struct encode_ctx *
|
struct encode_ctx *
|
||||||
transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ctx, off_t *est_size, int width, int height);
|
transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ctx, off_t *est_size, int width, int height);
|
||||||
|
Loading…
Reference in New Issue
Block a user