diff --git a/src/artwork.c b/src/artwork.c index 9e0f607c..c48fa5f3 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -472,8 +472,8 @@ artwork_rescale(struct evbuffer *evbuf, AVFormatContext *src_ctx, int s, int out av_free_packet(&pkt); /* Open output file */ - dst_ctx->pb = avio_evbuffer_open(evbuf); - if (ret < 0) + dst_ctx->pb = avio_output_evbuffer_open(evbuf); + if (!dst_ctx->pb) { DPRINTF(E_LOG, L_ART, "Could not open artwork destination buffer\n"); @@ -1105,13 +1105,98 @@ source_item_stream_get(struct artwork_ctx *ctx) static int source_item_spotify_get(struct artwork_ctx *ctx) { + AVFormatContext *src_ctx; + AVIOContext *avio; + AVInputFormat *ifmt; + struct evbuffer *evbuf; + int target_w; + int target_h; int ret; - ret = spotify_artwork_get(ctx->evbuf, ctx->dbmfi->path, ctx->max_w, ctx->max_h); - if (ret < 0) - return ART_E_NONE; + evbuf = evbuffer_new(); + if (!evbuf) + { + DPRINTF(E_LOG, L_ART, "Out of memory for Spotify evbuf\n"); + return ART_E_ERROR; + } + ret = spotify_artwork_get(evbuf, ctx->dbmfi->path, ctx->max_w, ctx->max_h); + if (ret < 0) + { + DPRINTF(E_WARN, L_ART, "No artwork from Spotify for %s\n", ctx->dbmfi->path); + evbuffer_free(evbuf); + return ART_E_NONE; + } + + // Now we take it by ffmpeg, since it probably needs to be rescaled + src_ctx = avformat_alloc_context(); + if (!src_ctx) + { + DPRINTF(E_LOG, L_ART, "Out of memory for source context\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) + { + evbuffer_free(ctx->evbuf); + ctx->evbuf = evbuf; + } + else + { + ret = artwork_rescale(ctx->evbuf, src_ctx, 0, target_w, target_h); + if (ret < 0) + goto out_close_input; + + evbuffer_free(evbuf); + } + + avformat_close_input(&src_ctx); + avio_evbuffer_close(avio); 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: + evbuffer_free(evbuf); + + return ART_E_ERROR; + } #else static int diff --git a/src/avio_evbuffer.c b/src/avio_evbuffer.c index e2e24a6d..47551331 100644 --- a/src/avio_evbuffer.c +++ b/src/avio_evbuffer.c @@ -38,6 +38,18 @@ struct avio_evbuffer { uint8_t *buffer; }; +static int +avio_evbuffer_read(void *opaque, uint8_t *buf, int size) +{ + struct avio_evbuffer *ae; + int ret; + + ae = (struct avio_evbuffer *)opaque; + + ret = evbuffer_remove(ae->evbuf, buf, size); + + return ret; +} static int avio_evbuffer_write(void *opaque, uint8_t *buf, int size) @@ -52,8 +64,8 @@ avio_evbuffer_write(void *opaque, uint8_t *buf, int size) return (ret == 0) ? size : -1; } -AVIOContext * -avio_evbuffer_open(struct evbuffer *evbuf) +static AVIOContext * +avio_evbuffer_open(struct evbuffer *evbuf, int is_output) { struct avio_evbuffer *ae; AVIOContext *s; @@ -77,7 +89,11 @@ avio_evbuffer_open(struct evbuffer *evbuf) ae->evbuf = evbuf; - s = avio_alloc_context(ae->buffer, BUFFER_SIZE, 1, ae, NULL, avio_evbuffer_write, NULL); + if (is_output) + s = avio_alloc_context(ae->buffer, BUFFER_SIZE, 1, ae, NULL, avio_evbuffer_write, NULL); + else + s = avio_alloc_context(ae->buffer, BUFFER_SIZE, 0, ae, avio_evbuffer_read, NULL, NULL); + if (!s) { DPRINTF(E_LOG, L_FFMPEG, "Could not allocate AVIOContext\n"); @@ -92,6 +108,18 @@ avio_evbuffer_open(struct evbuffer *evbuf) return s; } +AVIOContext * +avio_input_evbuffer_open(struct evbuffer *evbuf) +{ + return avio_evbuffer_open(evbuf, 0); +} + +AVIOContext * +avio_output_evbuffer_open(struct evbuffer *evbuf) +{ + return avio_evbuffer_open(evbuf, 1); +} + void avio_evbuffer_close(AVIOContext *s) { @@ -101,7 +129,7 @@ avio_evbuffer_close(AVIOContext *s) avio_flush(s); - av_free(ae->buffer); + av_free(s->buffer); free(ae); av_free(s); diff --git a/src/avio_evbuffer.h b/src/avio_evbuffer.h index 866e1ed7..93dc1234 100644 --- a/src/avio_evbuffer.h +++ b/src/avio_evbuffer.h @@ -5,7 +5,10 @@ #include AVIOContext * -avio_evbuffer_open(struct evbuffer *evbuf); +avio_input_evbuffer_open(struct evbuffer *evbuf); + +AVIOContext * +avio_output_evbuffer_open(struct evbuffer *evbuf); void avio_evbuffer_close(AVIOContext *s); diff --git a/src/transcode.c b/src/transcode.c index d37d46da..e810d18d 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -725,7 +725,7 @@ open_output(struct encode_ctx *ctx, struct decode_ctx *src_ctx) goto out_fail_evbuf; } - ctx->ofmt_ctx->pb = avio_evbuffer_open(ctx->obuf); + ctx->ofmt_ctx->pb = avio_output_evbuffer_open(ctx->obuf); if (!ctx->ofmt_ctx->pb) { DPRINTF(E_LOG, L_XCODE, "Could not create output avio pb\n");