[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
|
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)
|
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 decode_ctx *xcode_decode = NULL;
|
||||||
struct encode_ctx *xcode_encode = NULL;
|
struct encode_ctx *xcode_encode = NULL;
|
||||||
struct transcode_evbuf_io xcode_evbuf_io = { 0 };
|
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_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
|
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 (!xcode_decode)
|
||||||
{
|
{
|
||||||
if (path)
|
if (path)
|
||||||
|
@ -702,15 +707,19 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *in_buf, bool is
|
||||||
goto out;
|
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)
|
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)
|
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)
|
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
|
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 (!xcode_encode)
|
||||||
{
|
{
|
||||||
if (path)
|
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,
|
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)
|
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 media_quality quality = { 0 };
|
||||||
struct stream_ctx *st;
|
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);
|
st = stream_new(mfi, hreq, stream_cb);
|
||||||
if (!st)
|
if (!st)
|
||||||
{
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use source sample rate etc, but for MP3 we must set a bit rate
|
decode_args.profile = profile;
|
||||||
quality.bit_rate = cfg_getint(cfg_getsec(cfg, "streaming"), "bit_rate");
|
decode_args.is_http = (mfi->data_kind == DATA_KIND_HTTP);
|
||||||
st->xcode = transcode_setup(profile, &quality, mfi->data_kind, mfi->path, mfi->song_length);
|
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)
|
if (!st->xcode)
|
||||||
{
|
{
|
||||||
DPRINTF(E_WARN, L_HTTPD, "Transcoding setup failed, aborting streaming\n");
|
DPRINTF(E_WARN, L_HTTPD, "Transcoding setup failed, aborting streaming\n");
|
||||||
|
|
|
@ -36,9 +36,11 @@
|
||||||
static int
|
static int
|
||||||
setup(struct input_source *source)
|
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;
|
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)
|
if (!ctx)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -295,6 +295,8 @@ metadata_prepare(struct input_source *source)
|
||||||
static int
|
static int
|
||||||
setup(struct input_source *source)
|
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;
|
struct transcode_ctx *ctx;
|
||||||
char *url;
|
char *url;
|
||||||
|
|
||||||
|
@ -303,8 +305,9 @@ setup(struct input_source *source)
|
||||||
|
|
||||||
free(source->path);
|
free(source->path);
|
||||||
source->path = url;
|
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)
|
if (!ctx)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -391,21 +391,18 @@ download_seek(void *arg, int64_t offset, enum transcode_seek_type type)
|
||||||
static int
|
static int
|
||||||
download_xcode_setup(struct download_ctx *download)
|
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 };
|
struct transcode_evbuf_io xcode_evbuf_io = { 0 };
|
||||||
|
struct transcode_ctx *xcode;
|
||||||
CHECK_NULL(L_SPOTIFY, xcode = malloc(sizeof(struct transcode_ctx)));
|
|
||||||
|
|
||||||
xcode_evbuf_io.evbuf = download->read_buf;
|
xcode_evbuf_io.evbuf = download->read_buf;
|
||||||
xcode_evbuf_io.seekfn = download_seek;
|
xcode_evbuf_io.seekfn = download_seek;
|
||||||
xcode_evbuf_io.seekfn_arg = download;
|
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);
|
xcode = transcode_setup(decode_args, encode_args);
|
||||||
if (!xcode->decode_ctx)
|
if (!xcode)
|
||||||
goto error;
|
|
||||||
|
|
||||||
xcode->encode_ctx = transcode_encode_setup(XCODE_PCM16, NULL, xcode->decode_ctx, 0, 0);
|
|
||||||
if (!xcode->encode_ctx)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
download->xcode = xcode;
|
download->xcode = xcode;
|
||||||
|
|
|
@ -280,8 +280,8 @@ quality_to_xcode(struct media_quality *quality)
|
||||||
static int
|
static int
|
||||||
encoding_reset(struct media_quality *quality)
|
encoding_reset(struct media_quality *quality)
|
||||||
{
|
{
|
||||||
|
struct transcode_encode_setup_args encode_args = { 0 };
|
||||||
struct output_quality_subscription *subscription;
|
struct output_quality_subscription *subscription;
|
||||||
struct decode_ctx *decode_ctx;
|
|
||||||
enum transcode_profile profile;
|
enum transcode_profile profile;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -293,8 +293,8 @@ encoding_reset(struct media_quality *quality)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_ctx = transcode_decode_setup_raw(profile, quality);
|
encode_args.src_ctx = transcode_decode_setup_raw(profile, quality);
|
||||||
if (!decode_ctx)
|
if (!encode_args.src_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_PLAYER, "Could not create subscription decoding context (profile %d)\n", profile);
|
DPRINTF(E_LOG, L_PLAYER, "Could not create subscription decoding context (profile %d)\n", profile);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -309,15 +309,16 @@ encoding_reset(struct media_quality *quality)
|
||||||
if (quality_is_equal(quality, &subscription->quality))
|
if (quality_is_equal(quality, &subscription->quality))
|
||||||
continue; // No resampling required
|
continue; // No resampling required
|
||||||
|
|
||||||
profile = quality_to_xcode(&subscription->quality);
|
encode_args.profile = quality_to_xcode(&subscription->quality);
|
||||||
if (profile != XCODE_UNKNOWN)
|
encode_args.quality = &subscription->quality;
|
||||||
subscription->encode_ctx = transcode_encode_setup(profile, &subscription->quality, decode_ctx, 0, 0);
|
if (encode_args.profile != XCODE_UNKNOWN)
|
||||||
|
subscription->encode_ctx = transcode_encode_setup(encode_args);
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_PLAYER, "Could not setup resampling to %d/%d/%d for output\n",
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1120,7 +1120,7 @@ static struct airplay_master_session *
|
||||||
master_session_make(struct media_quality *quality)
|
master_session_make(struct media_quality *quality)
|
||||||
{
|
{
|
||||||
struct airplay_master_session *rms;
|
struct airplay_master_session *rms;
|
||||||
struct decode_ctx *decode_ctx;
|
struct transcode_encode_setup_args encode_args = { .profile = XCODE_ALAC, .quality = quality };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
// First check if we already have a suitable session
|
// First check if we already have a suitable session
|
||||||
|
@ -1146,15 +1146,15 @@ master_session_make(struct media_quality *quality)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality);
|
encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality);
|
||||||
if (!decode_ctx)
|
if (!encode_args.src_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_AIRPLAY, "Could not create decoding context\n");
|
DPRINTF(E_LOG, L_AIRPLAY, "Could not create decoding context\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rms->encode_ctx = transcode_encode_setup(XCODE_ALAC, quality, decode_ctx, 0, 0);
|
rms->encode_ctx = transcode_encode_setup(encode_args);
|
||||||
transcode_decode_cleanup(&decode_ctx);
|
transcode_decode_cleanup(&encode_args.src_ctx);
|
||||||
if (!rms->encode_ctx)
|
if (!rms->encode_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_AIRPLAY, "Will not be able to stream AirPlay 2, ffmpeg has no ALAC encoder\n");
|
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
|
static int
|
||||||
cast_init(void)
|
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 i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -2386,15 +2386,15 @@ cast_init(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, &cast_quality_default);
|
encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, &cast_quality_default);
|
||||||
if (!decode_ctx)
|
if (!encode_args.src_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_CAST, "Could not create decoding context\n");
|
DPRINTF(E_LOG, L_CAST, "Could not create decoding context\n");
|
||||||
goto out_tls_deinit;
|
goto out_tls_deinit;
|
||||||
}
|
}
|
||||||
|
|
||||||
cast_encode_ctx = transcode_encode_setup(XCODE_OPUS, &cast_quality_default, decode_ctx, 0, 0);
|
cast_encode_ctx = transcode_encode_setup(encode_args);
|
||||||
transcode_decode_cleanup(&decode_ctx);
|
transcode_decode_cleanup(&encode_args.src_ctx);
|
||||||
if (!cast_encode_ctx)
|
if (!cast_encode_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_CAST, "Will not be able to stream Chromecast, libav does not support Opus encoding\n");
|
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)
|
master_session_make(struct media_quality *quality, bool encrypt)
|
||||||
{
|
{
|
||||||
struct raop_master_session *rms;
|
struct raop_master_session *rms;
|
||||||
struct decode_ctx *decode_ctx;
|
struct transcode_encode_setup_args encode_args = { .profile = XCODE_ALAC, .quality = quality };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
// First check if we already have a suitable session
|
// First check if we already have a suitable session
|
||||||
|
@ -1883,15 +1883,15 @@ master_session_make(struct media_quality *quality, bool encrypt)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality);
|
encode_args.src_ctx = transcode_decode_setup_raw(XCODE_PCM16, quality);
|
||||||
if (!decode_ctx)
|
if (!encode_args.src_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RAOP, "Could not create decoding context\n");
|
DPRINTF(E_LOG, L_RAOP, "Could not create decoding context\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rms->encode_ctx = transcode_encode_setup(XCODE_ALAC, quality, decode_ctx, 0, 0);
|
rms->encode_ctx = transcode_encode_setup(encode_args);
|
||||||
transcode_decode_cleanup(&decode_ctx);
|
transcode_decode_cleanup(&encode_args.src_ctx);
|
||||||
if (!rms->encode_ctx)
|
if (!rms->encode_ctx)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_RAOP, "Will not be able to stream AirPlay 2, ffmpeg has no ALAC encoder\n");
|
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 *
|
static struct encode_ctx *
|
||||||
encoder_setup(enum player_format format, struct media_quality *quality)
|
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;
|
struct encode_ctx *encode_ctx = NULL;
|
||||||
|
|
||||||
if (quality->bits_per_sample == 16)
|
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)
|
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)
|
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",
|
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);
|
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)
|
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)
|
if (!encode_ctx)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +143,7 @@ encoder_setup(enum player_format format, struct media_quality *quality)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
transcode_decode_cleanup(&decode_ctx);
|
transcode_decode_cleanup(&encode_args.src_ctx);
|
||||||
return encode_ctx;
|
return encode_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "conffile.h"
|
#include "conffile.h"
|
||||||
#include "db.h"
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "transcode.h"
|
#include "transcode.h"
|
||||||
|
|
||||||
|
@ -151,8 +150,8 @@ struct decode_ctx
|
||||||
// Source duration in ms as provided by caller
|
// Source duration in ms as provided by caller
|
||||||
uint32_t len_ms;
|
uint32_t len_ms;
|
||||||
|
|
||||||
// Data kind (used to determine if ICY metadata is relevant to look for)
|
// Used to determine if ICY metadata is relevant to look for
|
||||||
enum data_kind data_kind;
|
bool is_http;
|
||||||
|
|
||||||
// Set to true if we just seeked
|
// Set to true if we just seeked
|
||||||
bool resume;
|
bool resume;
|
||||||
|
@ -1202,6 +1201,8 @@ mp4_header_trailer_from_evbuf(uint8_t **header, size_t *header_len, uint8_t **tr
|
||||||
static int
|
static int
|
||||||
make_mp4_header(struct evbuffer **mp4_header, const char *url)
|
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_ctx ctx = { 0 };
|
||||||
struct transcode_evbuf_io evbuf_io = { 0 };
|
struct transcode_evbuf_io evbuf_io = { 0 };
|
||||||
uint8_t free_tag[4] = { 'f', 'r', 'e', 'e' };
|
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 = dummy_seek;
|
||||||
evbuf_io.seekfn_arg = &ctx;
|
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)
|
if (!ctx.decode_ctx)
|
||||||
goto error;
|
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)
|
if (!ctx.encode_ctx)
|
||||||
goto error;
|
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;
|
ctx->ifmt_ctx->format_probesize = 65536;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->data_kind == DATA_KIND_HTTP)
|
if (ctx->is_http)
|
||||||
{
|
{
|
||||||
av_dict_set(&options, "icy", "1", 0);
|
av_dict_set(&options, "icy", "1", 0);
|
||||||
|
|
||||||
|
@ -1501,7 +1505,7 @@ close_output(struct encode_ctx *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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
|
#if USE_CONST_AVFORMAT
|
||||||
const AVOutputFormat *oformat;
|
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_add_buffer(ctx->obuf, header);
|
||||||
evbuffer_free(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);
|
ret = make_mp4_header(&header, src_ctx->ifmt_ctx->url);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1915,7 +1924,7 @@ open_filters(struct encode_ctx *ctx, struct decode_ctx *src_ctx)
|
||||||
/* Setup */
|
/* Setup */
|
||||||
|
|
||||||
struct decode_ctx *
|
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;
|
struct decode_ctx *ctx;
|
||||||
int ret;
|
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->decoded_frame = av_frame_alloc());
|
||||||
CHECK_NULL(L_XCODE, ctx->packet = av_packet_alloc());
|
CHECK_NULL(L_XCODE, ctx->packet = av_packet_alloc());
|
||||||
|
|
||||||
ctx->len_ms = len_ms;
|
ctx->len_ms = args.len_ms;
|
||||||
ctx->data_kind = data_kind;
|
|
||||||
|
|
||||||
ret = init_settings(&ctx->settings, profile, quality);
|
ret = init_settings(&ctx->settings, args.profile, args.quality);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail_free;
|
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
|
// Retry with a default, slower probe size
|
||||||
if (ret == AVERROR_STREAM_NOT_FOUND)
|
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
|
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)
|
if (ret < 0)
|
||||||
goto fail_free;
|
goto fail_free;
|
||||||
|
@ -1955,7 +1965,7 @@ transcode_decode_setup(enum transcode_profile profile, struct media_quality *qua
|
||||||
}
|
}
|
||||||
|
|
||||||
struct encode_ctx *
|
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;
|
struct encode_ctx *ctx;
|
||||||
int dst_bytes_per_sample;
|
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());
|
CHECK_NULL(L_XCODE, ctx->evbuf_io.evbuf = evbuffer_new());
|
||||||
|
|
||||||
// Caller didn't specify one, so use our own
|
// Caller didn't specify one, so use our own
|
||||||
if (!evbuf_io)
|
if (!args.evbuf_io)
|
||||||
evbuf_io = &ctx->evbuf_io;
|
args.evbuf_io = &ctx->evbuf_io;
|
||||||
|
|
||||||
// Initialize general settings
|
// Initialize general settings
|
||||||
if (init_settings(&ctx->settings, profile, quality) < 0)
|
if (init_settings(&ctx->settings, args.profile, args.quality) < 0)
|
||||||
goto error;
|
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;
|
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;
|
goto error;
|
||||||
|
|
||||||
dst_bytes_per_sample = av_get_bytes_per_sample(ctx->settings.sample_format);
|
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;
|
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;
|
goto error;
|
||||||
|
|
||||||
if (open_filters(ctx, src_ctx) < 0)
|
if (open_filters(ctx, args.src_ctx) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
|
@ -1998,27 +2008,22 @@ transcode_encode_setup_with_io(enum transcode_profile profile, struct media_qual
|
||||||
return NULL;
|
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 *
|
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;
|
struct transcode_ctx *ctx;
|
||||||
|
|
||||||
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, quality, data_kind, path, NULL, len_ms);
|
ctx->decode_ctx = transcode_decode_setup(decode_args);
|
||||||
if (!ctx->decode_ctx)
|
if (!ctx->decode_ctx)
|
||||||
{
|
{
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return NULL;
|
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)
|
if (!ctx->encode_ctx)
|
||||||
{
|
{
|
||||||
transcode_decode_cleanup(&ctx->decode_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);
|
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__
|
#define __TRANSCODE_H__
|
||||||
|
|
||||||
#include <event2/buffer.h>
|
#include <event2/buffer.h>
|
||||||
#include "db.h"
|
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
@ -66,6 +65,29 @@ struct transcode_evbuf_io
|
||||||
void *seekfn_arg;
|
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
|
struct transcode_metadata_string
|
||||||
{
|
{
|
||||||
char *type;
|
char *type;
|
||||||
|
@ -78,16 +100,13 @@ struct transcode_metadata_string
|
||||||
|
|
||||||
// Setting up
|
// Setting up
|
||||||
struct decode_ctx *
|
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 *
|
struct encode_ctx *
|
||||||
transcode_encode_setup(enum transcode_profile profile, struct media_quality *quality, struct decode_ctx *src_ctx, int width, int height);
|
transcode_encode_setup(struct transcode_encode_setup_args args);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
struct transcode_ctx *
|
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 *
|
struct decode_ctx *
|
||||||
transcode_decode_setup_raw(enum transcode_profile profile, struct media_quality *quality);
|
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
|
void
|
||||||
transcode_metadata_strings_set(struct transcode_metadata_string *s, enum transcode_profile profile, struct media_quality *q, uint32_t len_ms);
|
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__ */
|
#endif /* !__TRANSCODE_H__ */
|
||||||
|
|
Loading…
Reference in New Issue