From 4a08644806199b2f54c4417b16a132fa15792ce7 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Mon, 25 Dec 2023 22:29:32 +0100 Subject: [PATCH] [xcode] Change the signature of transcode_setup/transcode_en/decode_setup() Should make it easier to add/remove parameters without changing all calls to the functions throughout the code. Also adds an interface through which to call make_mp4_header(). --- src/artwork.c | 21 +++++--- src/httpd.c | 16 ++++-- src/inputs/file.c | 4 +- src/inputs/http.c | 5 +- src/inputs/spotify_librespotc.c | 15 +++--- src/outputs.c | 15 +++--- src/outputs/airplay.c | 10 ++-- src/outputs/cast.c | 10 ++-- src/outputs/raop.c | 10 ++-- src/outputs/streaming.c | 14 ++--- src/transcode.c | 92 ++++++++++++++++++++------------- src/transcode.h | 44 +++++++++++++--- 12 files changed, 165 insertions(+), 91 deletions(-) diff --git a/src/artwork.c b/src/artwork.c index 7d51986c..697228f7 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -604,6 +604,8 @@ size_calculate(int *dst_w, int *dst_h, int src_w, int src_h, int max_w, int max_ static int artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *in_buf, bool is_embedded, enum data_kind data_kind, struct artwork_req_params req_params) { + struct transcode_decode_setup_args xcode_decode_args = { .profile = XCODE_JPEG }; // Covers XCODE_PNG too + struct transcode_encode_setup_args xcode_encode_args = { 0 }; struct decode_ctx *xcode_decode = NULL; struct encode_ctx *xcode_encode = NULL; struct transcode_evbuf_io xcode_evbuf_io = { 0 }; @@ -637,13 +639,16 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *in_buf, bool is } xcode_evbuf_io.evbuf = xcode_buf; - xcode_decode = transcode_decode_setup(XCODE_JPEG, NULL, data_kind, NULL, &xcode_evbuf_io, 0); // Covers XCODE_PNG too + xcode_decode_args.evbuf_io = &xcode_evbuf_io; + xcode_decode_args.is_http = (data_kind == DATA_KIND_HTTP); } else { - xcode_decode = transcode_decode_setup(XCODE_JPEG, NULL, data_kind, path, NULL, 0); // Covers XCODE_PNG too + xcode_decode_args.path = path; + xcode_decode_args.is_http = (data_kind == DATA_KIND_HTTP); } + xcode_decode = transcode_decode_setup(xcode_decode_args); if (!xcode_decode) { if (path) @@ -702,15 +707,19 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *in_buf, bool is goto out; } + xcode_encode_args.src_ctx = xcode_decode; + xcode_encode_args.width = dst_width; + xcode_encode_args.height = dst_height; if (dst_format == ART_FMT_JPEG) - xcode_encode = transcode_encode_setup(XCODE_JPEG, NULL, xcode_decode, dst_width, dst_height); + xcode_encode_args.profile = XCODE_JPEG; else if (dst_format == ART_FMT_PNG) - xcode_encode = transcode_encode_setup(XCODE_PNG, NULL, xcode_decode, dst_width, dst_height); + xcode_encode_args.profile = XCODE_PNG; else if (dst_format == ART_FMT_VP8) - xcode_encode = transcode_encode_setup(XCODE_VP8, NULL, xcode_decode, dst_width, dst_height); + xcode_encode_args.profile = XCODE_VP8; else - xcode_encode = transcode_encode_setup(XCODE_JPEG, NULL, xcode_decode, dst_width, dst_height); + xcode_encode_args.profile = XCODE_JPEG; + xcode_encode = transcode_encode_setup(xcode_encode_args); if (!xcode_encode) { if (path) diff --git a/src/httpd.c b/src/httpd.c index 65a50720..d2f3fb96 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -673,18 +673,28 @@ static struct stream_ctx * stream_new_transcode(struct media_file_info *mfi, enum transcode_profile profile, struct httpd_request *hreq, int64_t offset, int64_t end_offset, event_callback_fn stream_cb) { + struct transcode_decode_setup_args decode_args = { 0 }; + struct transcode_encode_setup_args encode_args = { 0 }; struct media_quality quality = { 0 }; struct stream_ctx *st; + // We use source sample rate etc, but for MP3 we must set a bit rate + quality.bit_rate = 1000 * cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate"); + st = stream_new(mfi, hreq, stream_cb); if (!st) { goto error; } - // We use source sample rate etc, but for MP3 we must set a bit rate - quality.bit_rate = cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate"); - st->xcode = transcode_setup(profile, &quality, mfi->data_kind, mfi->path, mfi->song_length); + decode_args.profile = profile; + decode_args.is_http = (mfi->data_kind == DATA_KIND_HTTP); + decode_args.path = mfi->path; + decode_args.len_ms = mfi->song_length; + encode_args.profile = profile; + encode_args.quality = &quality; + + st->xcode = transcode_setup(decode_args, encode_args); if (!st->xcode) { DPRINTF(E_WARN, L_HTTPD, "Transcoding setup failed, aborting streaming\n"); diff --git a/src/inputs/file.c b/src/inputs/file.c index ee3ed56c..68fe4c30 100644 --- a/src/inputs/file.c +++ b/src/inputs/file.c @@ -36,9 +36,11 @@ static int setup(struct input_source *source) { + struct transcode_decode_setup_args decode_args = { .profile = XCODE_PCM_NATIVE, .path = source->path, .len_ms = source->len_ms }; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_PCM_NATIVE, }; struct transcode_ctx *ctx; - ctx = transcode_setup(XCODE_PCM_NATIVE, NULL, source->data_kind, source->path, source->len_ms); + ctx = transcode_setup(decode_args, encode_args); if (!ctx) return -1; diff --git a/src/inputs/http.c b/src/inputs/http.c index 75d46e8d..5a671b54 100644 --- a/src/inputs/http.c +++ b/src/inputs/http.c @@ -295,6 +295,8 @@ metadata_prepare(struct input_source *source) static int setup(struct input_source *source) { + struct transcode_decode_setup_args decode_args = { .profile = XCODE_PCM_NATIVE, .is_http = true, .len_ms = source->len_ms }; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_PCM_NATIVE, }; struct transcode_ctx *ctx; char *url; @@ -303,8 +305,9 @@ setup(struct input_source *source) free(source->path); source->path = url; + decode_args.path = url; - ctx = transcode_setup(XCODE_PCM_NATIVE, NULL, source->data_kind, source->path, source->len_ms); + ctx = transcode_setup(decode_args, encode_args); if (!ctx) return -1; diff --git a/src/inputs/spotify_librespotc.c b/src/inputs/spotify_librespotc.c index e1e2bfb4..d973bf8a 100644 --- a/src/inputs/spotify_librespotc.c +++ b/src/inputs/spotify_librespotc.c @@ -391,21 +391,18 @@ download_seek(void *arg, int64_t offset, enum transcode_seek_type type) static int download_xcode_setup(struct download_ctx *download) { - struct transcode_ctx *xcode; + struct transcode_decode_setup_args decode_args = { .profile = XCODE_OGG, .len_ms = download->len_ms }; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_PCM16, }; struct transcode_evbuf_io xcode_evbuf_io = { 0 }; - - CHECK_NULL(L_SPOTIFY, xcode = malloc(sizeof(struct transcode_ctx))); + struct transcode_ctx *xcode; xcode_evbuf_io.evbuf = download->read_buf; xcode_evbuf_io.seekfn = download_seek; xcode_evbuf_io.seekfn_arg = download; + decode_args.evbuf_io = &xcode_evbuf_io; - xcode->decode_ctx = transcode_decode_setup(XCODE_OGG, NULL, DATA_KIND_SPOTIFY, NULL, &xcode_evbuf_io, download->len_ms); - if (!xcode->decode_ctx) - goto error; - - xcode->encode_ctx = transcode_encode_setup(XCODE_PCM16, NULL, xcode->decode_ctx, 0, 0); - if (!xcode->encode_ctx) + xcode = transcode_setup(decode_args, encode_args); + if (!xcode) goto error; download->xcode = xcode; diff --git a/src/outputs.c b/src/outputs.c index d6469a4d..a4aa9425 100644 --- a/src/outputs.c +++ b/src/outputs.c @@ -280,8 +280,8 @@ quality_to_xcode(struct media_quality *quality) static int encoding_reset(struct media_quality *quality) { + struct transcode_encode_setup_args encode_args = { 0 }; struct output_quality_subscription *subscription; - struct decode_ctx *decode_ctx; enum transcode_profile profile; int i; @@ -293,8 +293,8 @@ encoding_reset(struct media_quality *quality) return -1; } - decode_ctx = transcode_decode_setup_raw(profile, quality); - if (!decode_ctx) + encode_args.src_ctx = transcode_decode_setup_raw(profile, quality); + if (!encode_args.src_ctx) { DPRINTF(E_LOG, L_PLAYER, "Could not create subscription decoding context (profile %d)\n", profile); return -1; @@ -309,15 +309,16 @@ encoding_reset(struct media_quality *quality) if (quality_is_equal(quality, &subscription->quality)) continue; // No resampling required - profile = quality_to_xcode(&subscription->quality); - if (profile != XCODE_UNKNOWN) - subscription->encode_ctx = transcode_encode_setup(profile, &subscription->quality, decode_ctx, 0, 0); + encode_args.profile = quality_to_xcode(&subscription->quality); + encode_args.quality = &subscription->quality; + if (encode_args.profile != XCODE_UNKNOWN) + subscription->encode_ctx = transcode_encode_setup(encode_args); else DPRINTF(E_LOG, L_PLAYER, "Could not setup resampling to %d/%d/%d for output\n", subscription->quality.sample_rate, subscription->quality.bits_per_sample, subscription->quality.channels); } - transcode_decode_cleanup(&decode_ctx); + transcode_decode_cleanup(&encode_args.src_ctx); return 0; } diff --git a/src/outputs/airplay.c b/src/outputs/airplay.c index afd53b50..7e6b3cf7 100644 --- a/src/outputs/airplay.c +++ b/src/outputs/airplay.c @@ -1120,7 +1120,7 @@ static struct airplay_master_session * master_session_make(struct media_quality *quality) { struct airplay_master_session *rms; - struct decode_ctx *decode_ctx; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_ALAC, .quality = quality }; int ret; // First check if we already have a suitable session @@ -1146,15 +1146,15 @@ master_session_make(struct media_quality *quality) goto error; } - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality); - if (!decode_ctx) + encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality); + if (!encode_args.src_ctx) { DPRINTF(E_LOG, L_AIRPLAY, "Could not create decoding context\n"); goto error; } - rms->encode_ctx = transcode_encode_setup(XCODE_ALAC, quality, decode_ctx, 0, 0); - transcode_decode_cleanup(&decode_ctx); + rms->encode_ctx = transcode_encode_setup(encode_args); + transcode_decode_cleanup(&encode_args.src_ctx); if (!rms->encode_ctx) { DPRINTF(E_LOG, L_AIRPLAY, "Will not be able to stream AirPlay 2, ffmpeg has no ALAC encoder\n"); diff --git a/src/outputs/cast.c b/src/outputs/cast.c index d051b1d0..b6cc5ffb 100644 --- a/src/outputs/cast.c +++ b/src/outputs/cast.c @@ -2362,7 +2362,7 @@ cast_metadata_send(struct output_metadata *metadata) static int cast_init(void) { - struct decode_ctx *decode_ctx; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_OPUS, .quality = &cast_quality_default }; int i; int ret; @@ -2386,15 +2386,15 @@ cast_init(void) return -1; } - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, &cast_quality_default); - if (!decode_ctx) + encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, &cast_quality_default); + if (!encode_args.src_ctx) { DPRINTF(E_LOG, L_CAST, "Could not create decoding context\n"); goto out_tls_deinit; } - cast_encode_ctx = transcode_encode_setup(XCODE_OPUS, &cast_quality_default, decode_ctx, 0, 0); - transcode_decode_cleanup(&decode_ctx); + cast_encode_ctx = transcode_encode_setup(encode_args); + transcode_decode_cleanup(&encode_args.src_ctx); if (!cast_encode_ctx) { DPRINTF(E_LOG, L_CAST, "Will not be able to stream Chromecast, libav does not support Opus encoding\n"); diff --git a/src/outputs/raop.c b/src/outputs/raop.c index ec0a61e6..20436aaa 100644 --- a/src/outputs/raop.c +++ b/src/outputs/raop.c @@ -1855,7 +1855,7 @@ static struct raop_master_session * master_session_make(struct media_quality *quality, bool encrypt) { struct raop_master_session *rms; - struct decode_ctx *decode_ctx; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_ALAC, .quality = quality }; int ret; // First check if we already have a suitable session @@ -1883,15 +1883,15 @@ master_session_make(struct media_quality *quality, bool encrypt) return NULL; } - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality); - if (!decode_ctx) + encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality); + if (!encode_args.src_ctx) { DPRINTF(E_LOG, L_RAOP, "Could not create decoding context\n"); goto error; } - rms->encode_ctx = transcode_encode_setup(XCODE_ALAC, quality, decode_ctx, 0, 0); - transcode_decode_cleanup(&decode_ctx); + rms->encode_ctx = transcode_encode_setup(encode_args); + transcode_decode_cleanup(&encode_args.src_ctx); if (!rms->encode_ctx) { DPRINTF(E_LOG, L_RAOP, "Will not be able to stream AirPlay 2, ffmpeg has no ALAC encoder\n"); diff --git a/src/outputs/streaming.c b/src/outputs/streaming.c index 68885210..ecb5314b 100644 --- a/src/outputs/streaming.c +++ b/src/outputs/streaming.c @@ -115,17 +115,17 @@ extern struct event_base *evbase_player; static struct encode_ctx * encoder_setup(enum player_format format, struct media_quality *quality) { - struct decode_ctx *decode_ctx = NULL; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_MP3, .quality = quality }; struct encode_ctx *encode_ctx = NULL; if (quality->bits_per_sample == 16) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality); + encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality); else if (quality->bits_per_sample == 24) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM24, quality); + encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM24, quality); else if (quality->bits_per_sample == 32) - decode_ctx = transcode_decode_setup_raw(XCODE_PCM32, quality); + encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM32, quality); - if (!decode_ctx) + if (!encode_args.src_ctx) { DPRINTF(E_LOG, L_STREAMING, "Error setting up decoder for quality sr %d, bps %d, ch %d, cannot encode\n", quality->sample_rate, quality->bits_per_sample, quality->channels); @@ -133,7 +133,7 @@ encoder_setup(enum player_format format, struct media_quality *quality) } if (format == PLAYER_FORMAT_MP3) - encode_ctx = transcode_encode_setup(XCODE_MP3, quality, decode_ctx, 0, 0); + encode_ctx = transcode_encode_setup(encode_args); if (!encode_ctx) { @@ -143,7 +143,7 @@ encoder_setup(enum player_format format, struct media_quality *quality) } out: - transcode_decode_cleanup(&decode_ctx); + transcode_decode_cleanup(&encode_args.src_ctx); return encode_ctx; } diff --git a/src/transcode.c b/src/transcode.c index 45887c2a..abcfb0d8 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -38,7 +38,6 @@ #include "logger.h" #include "conffile.h" -#include "db.h" #include "misc.h" #include "transcode.h" @@ -151,8 +150,8 @@ struct decode_ctx // Source duration in ms as provided by caller uint32_t len_ms; - // Data kind (used to determine if ICY metadata is relevant to look for) - enum data_kind data_kind; + // Used to determine if ICY metadata is relevant to look for + bool is_http; // Set to true if we just seeked bool resume; @@ -1202,6 +1201,8 @@ mp4_header_trailer_from_evbuf(uint8_t **header, size_t *header_len, uint8_t **tr static int make_mp4_header(struct evbuffer **mp4_header, const char *url) { + struct transcode_decode_setup_args decode_args = { .profile = XCODE_MP4_ALAC_HEADER }; + struct transcode_encode_setup_args encode_args = { .profile = XCODE_MP4_ALAC_HEADER }; struct transcode_ctx ctx = { 0 }; struct transcode_evbuf_io evbuf_io = { 0 }; uint8_t free_tag[4] = { 'f', 'r', 'e', 'e' }; @@ -1220,11 +1221,14 @@ make_mp4_header(struct evbuffer **mp4_header, const char *url) evbuf_io.seekfn = dummy_seek; evbuf_io.seekfn_arg = &ctx; - ctx.decode_ctx = transcode_decode_setup(XCODE_MP4_ALAC_HEADER, NULL, DATA_KIND_FILE, url, NULL, -1); + decode_args.path = url; + ctx.decode_ctx = transcode_decode_setup(decode_args); if (!ctx.decode_ctx) goto error; - ctx.encode_ctx = transcode_encode_setup_with_io(XCODE_MP4_ALAC_HEADER, NULL, &evbuf_io, ctx.decode_ctx, 0, 0); + encode_args.evbuf_io = &evbuf_io; + encode_args.src_ctx = ctx.decode_ctx; + ctx.encode_ctx = transcode_encode_setup(encode_args); if (!ctx.encode_ctx) goto error; @@ -1394,7 +1398,7 @@ open_input(struct decode_ctx *ctx, const char *path, struct transcode_evbuf_io * ctx->ifmt_ctx->format_probesize = 65536; } - if (ctx->data_kind == DATA_KIND_HTTP) + if (ctx->is_http) { av_dict_set(&options, "icy", "1", 0); @@ -1501,7 +1505,7 @@ close_output(struct encode_ctx *ctx) } static int -open_output(struct encode_ctx *ctx, struct transcode_evbuf_io *evbuf_io, struct decode_ctx *src_ctx) +open_output(struct encode_ctx *ctx, struct transcode_evbuf_io *evbuf_io, struct evbuffer *prepared_header, struct decode_ctx *src_ctx) { #if USE_CONST_AVFORMAT const AVOutputFormat *oformat; @@ -1584,7 +1588,12 @@ open_output(struct encode_ctx *ctx, struct transcode_evbuf_io *evbuf_io, struct evbuffer_add_buffer(ctx->obuf, header); evbuffer_free(header); } - if (ctx->settings.with_mp4_header) + + if (ctx->settings.with_mp4_header && prepared_header) + { + evbuffer_add_buffer(ctx->obuf, prepared_header); + } + else if (ctx->settings.with_mp4_header) { ret = make_mp4_header(&header, src_ctx->ifmt_ctx->url); if (ret < 0) @@ -1915,7 +1924,7 @@ open_filters(struct encode_ctx *ctx, struct decode_ctx *src_ctx) /* Setup */ struct decode_ctx * -transcode_decode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, struct transcode_evbuf_io *evbuf_io, uint32_t len_ms) +transcode_decode_setup(struct transcode_decode_setup_args args) { struct decode_ctx *ctx; int ret; @@ -1924,23 +1933,24 @@ transcode_decode_setup(enum transcode_profile profile, struct media_quality *qua CHECK_NULL(L_XCODE, ctx->decoded_frame = av_frame_alloc()); CHECK_NULL(L_XCODE, ctx->packet = av_packet_alloc()); - ctx->len_ms = len_ms; - ctx->data_kind = data_kind; + ctx->len_ms = args.len_ms; - ret = init_settings(&ctx->settings, profile, quality); + ret = init_settings(&ctx->settings, args.profile, args.quality); if (ret < 0) goto fail_free; - if (data_kind == DATA_KIND_HTTP) + if (args.is_http) { - ret = open_input(ctx, path, evbuf_io, PROBE_TYPE_QUICK); + ctx->is_http = true; + + ret = open_input(ctx, args.path, args.evbuf_io, PROBE_TYPE_QUICK); // Retry with a default, slower probe size if (ret == AVERROR_STREAM_NOT_FOUND) - ret = open_input(ctx, path, evbuf_io, PROBE_TYPE_DEFAULT); + ret = open_input(ctx, args.path, args.evbuf_io, PROBE_TYPE_DEFAULT); } else - ret = open_input(ctx, path, evbuf_io, PROBE_TYPE_DEFAULT); + ret = open_input(ctx, args.path, args.evbuf_io, PROBE_TYPE_DEFAULT); if (ret < 0) goto fail_free; @@ -1955,7 +1965,7 @@ transcode_decode_setup(enum transcode_profile profile, struct media_quality *qua } struct encode_ctx * -transcode_encode_setup_with_io(enum transcode_profile profile, struct media_quality *quality, struct transcode_evbuf_io *evbuf_io, struct decode_ctx *src_ctx, int width, int height) +transcode_encode_setup(struct transcode_encode_setup_args args) { struct encode_ctx *ctx; int dst_bytes_per_sample; @@ -1966,29 +1976,29 @@ transcode_encode_setup_with_io(enum transcode_profile profile, struct media_qual CHECK_NULL(L_XCODE, ctx->evbuf_io.evbuf = evbuffer_new()); // Caller didn't specify one, so use our own - if (!evbuf_io) - evbuf_io = &ctx->evbuf_io; + if (!args.evbuf_io) + args.evbuf_io = &ctx->evbuf_io; // Initialize general settings - if (init_settings(&ctx->settings, profile, quality) < 0) + if (init_settings(&ctx->settings, args.profile, args.quality) < 0) goto error; - if (ctx->settings.encode_audio && init_settings_from_audio(&ctx->settings, profile, src_ctx, quality) < 0) + if (ctx->settings.encode_audio && init_settings_from_audio(&ctx->settings, args.profile, args.src_ctx, args.quality) < 0) goto error; - if (ctx->settings.encode_video && init_settings_from_video(&ctx->settings, profile, src_ctx, width, height) < 0) + if (ctx->settings.encode_video && init_settings_from_video(&ctx->settings, args.profile, args.src_ctx, args.width, args.height) < 0) goto error; dst_bytes_per_sample = av_get_bytes_per_sample(ctx->settings.sample_format); - ctx->bytes_total = size_estimate(profile, ctx->settings.bit_rate, ctx->settings.sample_rate, dst_bytes_per_sample, ctx->settings.nb_channels, src_ctx->len_ms); + ctx->bytes_total = size_estimate(args.profile, ctx->settings.bit_rate, ctx->settings.sample_rate, dst_bytes_per_sample, ctx->settings.nb_channels, args.src_ctx->len_ms); - if (ctx->settings.with_icy && src_ctx->data_kind == DATA_KIND_HTTP) + if (ctx->settings.with_icy && args.src_ctx->is_http) ctx->icy_interval = METADATA_ICY_INTERVAL * ctx->settings.nb_channels * dst_bytes_per_sample * ctx->settings.sample_rate; - if (open_output(ctx, evbuf_io, src_ctx) < 0) + if (open_output(ctx, args.evbuf_io, args.prepared_header, args.src_ctx) < 0) goto error; - if (open_filters(ctx, src_ctx) < 0) + if (open_filters(ctx, args.src_ctx) < 0) goto error; return ctx; @@ -1998,27 +2008,22 @@ transcode_encode_setup_with_io(enum transcode_profile profile, struct media_qual return NULL; } -struct encode_ctx * -transcode_encode_setup(enum transcode_profile profile, struct media_quality *quality, struct decode_ctx *src_ctx, int width, int height) -{ - return transcode_encode_setup_with_io(profile, quality, NULL, src_ctx, width, height); -} - struct transcode_ctx * -transcode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, uint32_t len_ms) +transcode_setup(struct transcode_decode_setup_args decode_args, struct transcode_encode_setup_args encode_args) { struct transcode_ctx *ctx; CHECK_NULL(L_XCODE, ctx = calloc(1, sizeof(struct transcode_ctx))); - ctx->decode_ctx = transcode_decode_setup(profile, quality, data_kind, path, NULL, len_ms); + ctx->decode_ctx = transcode_decode_setup(decode_args); if (!ctx->decode_ctx) { free(ctx); return NULL; } - ctx->encode_ctx = transcode_encode_setup(profile, quality, ctx->decode_ctx, 0, 0); + encode_args.src_ctx = ctx->decode_ctx; + ctx->encode_ctx = transcode_encode_setup(encode_args); if (!ctx->encode_ctx) { transcode_decode_cleanup(&ctx->decode_ctx); @@ -2618,3 +2623,20 @@ transcode_metadata_strings_set(struct transcode_metadata_string *s, enum transco DPRINTF(E_WARN, L_XCODE, "transcode_metadata_strings_set() called with unknown profile %d\n", profile); } } + +int +transcode_create_header(struct evbuffer **header, enum transcode_profile profile, const char *path) +{ + int ret; + + switch (profile) + { + case XCODE_MP4_ALAC: + ret = make_mp4_header(header, path); + break; + default: + ret = -1; + } + + return ret; +} diff --git a/src/transcode.h b/src/transcode.h index f72b7a4e..c9a7f372 100644 --- a/src/transcode.h +++ b/src/transcode.h @@ -3,7 +3,6 @@ #define __TRANSCODE_H__ #include -#include "db.h" #include "http.h" #include "misc.h" @@ -66,6 +65,29 @@ struct transcode_evbuf_io void *seekfn_arg; }; +struct transcode_decode_setup_args +{ + enum transcode_profile profile; + struct media_quality *quality; + bool is_http; + uint32_t len_ms; + + // Source must be either of these + const char *path; + struct transcode_evbuf_io *evbuf_io; +}; + +struct transcode_encode_setup_args +{ + enum transcode_profile profile; + struct media_quality *quality; + struct decode_ctx *src_ctx; + struct transcode_evbuf_io *evbuf_io; + struct evbuffer *prepared_header; + int width; + int height; +}; + struct transcode_metadata_string { char *type; @@ -78,16 +100,13 @@ struct transcode_metadata_string // Setting up struct decode_ctx * -transcode_decode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, struct transcode_evbuf_io *evbuf_io, uint32_t len_ms); +transcode_decode_setup(struct transcode_decode_setup_args args); struct encode_ctx * -transcode_encode_setup(enum transcode_profile profile, struct media_quality *quality, struct decode_ctx *src_ctx, int width, int height); - -struct encode_ctx * -transcode_encode_setup_with_io(enum transcode_profile profile, struct media_quality *quality, struct transcode_evbuf_io *evbuf_io, struct decode_ctx *src_ctx, int width, int height); +transcode_encode_setup(struct transcode_encode_setup_args args); struct transcode_ctx * -transcode_setup(enum transcode_profile profile, struct media_quality *quality, enum data_kind data_kind, const char *path, uint32_t len_ms); +transcode_setup(struct transcode_decode_setup_args decode_args, struct transcode_encode_setup_args encode_args); struct decode_ctx * transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality); @@ -201,4 +220,15 @@ transcode_metadata(struct transcode_ctx *ctx, int *changed); void transcode_metadata_strings_set(struct transcode_metadata_string *s, enum transcode_profile profile, struct media_quality *q, uint32_t len_ms); +/* Creates a header for later transcoding of a source file. This header can be + * given to transcode_encode_setup which in some cases will make it faster (MP4) + * + * @out header An evbuffer with the header + * @in profile Transcoding profile + * @in path Path to the source file + * @return Negative if error, otherwise zero + */ +int +transcode_prepare_header(struct evbuffer **header, enum transcode_profile profile, const char *path); + #endif /* !__TRANSCODE_H__ */