mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-25 06:35:57 -05:00
[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().
This commit is contained in:
parent
9dbec4b99e
commit
4a08644806
@ -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)
|
||||
|
16
src/httpd.c
16
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");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define __TRANSCODE_H__
|
||||
|
||||
#include <event2/buffer.h>
|
||||
#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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user