diff --git a/src/artwork.c b/src/artwork.c index b5dbf0a1..b56ae720 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -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. * * @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_h Requested height * @return ART_FMT_* on success, ART_E_ERROR on error */ 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 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); - 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) { 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) { // 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; 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); - 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); - 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 @@ -685,7 +686,7 @@ source_item_own_get(struct artwork_ctx *ctx) 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 source_item_spotify_get(struct artwork_ctx *ctx) { - AVFormatContext *src_ctx; - AVIOContext *avio; - AVInputFormat *ifmt; struct evbuffer *raw; struct evbuffer *evbuf; - int target_w; - int target_h; int ret; raw = evbuffer_new(); @@ -820,75 +816,29 @@ source_item_spotify_get(struct artwork_ctx *ctx) goto out_free_evbuf; } - // Now evbuf will be processed by ffmpeg, since it probably needs to be rescaled - src_ctx = avformat_alloc_context(); - if (!src_ctx) + // For non-file input, artwork_get() will also fail if no rescaling is required + ret = artwork_get(ctx->evbuf, NULL, evbuf, ctx->max_w, ctx->max_h); + if (ret == ART_E_ERROR) { - DPRINTF(E_LOG, L_ART, "Out of memory for source context\n"); - goto out_free_evbuf; + DPRINTF(E_DBG, L_ART, "Not rescaling Spotify image\n"); + ret = evbuffer_add_buffer(ctx->evbuf, raw); + if (ret < 0) + { + DPRINTF(E_LOG, L_ART, "Could not add or rescale image to output evbuf\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); - else - ret = artwork_rescale(ctx->evbuf, src_ctx, 0, target_w, target_h); - if (ret < 0) - { - DPRINTF(E_LOG, L_ART, "Could not add or rescale image to output evbuf\n"); - goto out_close_input; - } - - avformat_close_input(&src_ctx); - avio_evbuffer_close(avio); evbuffer_free(evbuf); evbuffer_free(raw); 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); evbuffer_free(raw); return ART_E_ERROR; - } #else static int diff --git a/src/avio_evbuffer.c b/src/avio_evbuffer.c index 47551331..454acd7a 100644 --- a/src/avio_evbuffer.c +++ b/src/avio_evbuffer.c @@ -125,6 +125,9 @@ avio_evbuffer_close(AVIOContext *s) { struct avio_evbuffer *ae; + if (!s) + return; + ae = (struct avio_evbuffer *)s->opaque; avio_flush(s); diff --git a/src/transcode.c b/src/transcode.c index 0cfb37bf..bbf59cee 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -70,6 +70,9 @@ struct settings_ctx // Output format (for the muxer) const char *format; + // Input format (for the demuxer) + const char *in_format; + // Audio settings enum AVCodecID audio_codec; const char *audio_codec_name; @@ -111,6 +114,9 @@ struct decode_ctx // Input format context AVFormatContext *ifmt_ctx; + // IO Context for non-file input + AVIOContext *avio; + // Stream and decoder data struct stream_ctx audio_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->silent = 1; settings->format = "image2"; + settings->in_format = "mjpeg"; settings->video_codec = AV_CODEC_ID_MJPEG; break; @@ -712,10 +719,11 @@ open_decoder(unsigned int *stream_index, struct decode_ctx *ctx, enum AVMediaTyp } 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; AVCodecContext *dec_ctx; + AVInputFormat *ifmt; unsigned int stream_index; int ret; @@ -735,7 +743,24 @@ open_input(struct decode_ctx *ctx, const char *path) ctx->ifmt_ctx->interrupt_callback.opaque = ctx; ctx->timestamp = av_gettime(); - ret = avformat_open_input(&ctx->ifmt_ctx, path, NULL, &options); + 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); + } if (options) av_dict_free(&options); @@ -782,6 +807,7 @@ open_input(struct decode_ctx *ctx, const char *path) return 0; out_fail: + avio_evbuffer_close(ctx->avio); avcodec_free_context(&ctx->audio_stream.codec); avcodec_free_context(&ctx->video_stream.codec); avformat_close_input(&ctx->ifmt_ctx); @@ -792,6 +818,7 @@ open_input(struct decode_ctx *ctx, const char *path) static void close_input(struct decode_ctx *ctx) { + avio_evbuffer_close(ctx->avio); avcodec_free_context(&ctx->audio_stream.codec); avcodec_free_context(&ctx->video_stream.codec); avformat_close_input(&ctx->ifmt_ctx); @@ -1075,7 +1102,7 @@ close_filters(struct encode_ctx *ctx) /* Setup */ 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; @@ -1086,7 +1113,7 @@ transcode_decode_setup(enum transcode_profile profile, enum data_kind data_kind, ctx->duration = song_length; 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; 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))); - 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) { 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; - // TODO Shouldn't we flush and let the muxer write the trailer now? - evbuffer_add_buffer(evbuf, ctx->obuf); return ret; diff --git a/src/transcode.h b/src/transcode.h index 13e7aa63..3e6cfc86 100644 --- a/src/transcode.h +++ b/src/transcode.h @@ -25,7 +25,7 @@ struct transcode_ctx; // Setting up 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 * transcode_encode_setup(enum transcode_profile profile, struct decode_ctx *src_ctx, off_t *est_size, int width, int height);