mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-26 22:23:17 -05:00
[xcode] Add support for seekable custom I/O (evbuffer input to transcode)
This commit is contained in:
parent
57449a126a
commit
2bbc5f16c5
@ -605,6 +605,7 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *in_buf, bool is
|
||||
{
|
||||
struct decode_ctx *xcode_decode = NULL;
|
||||
struct encode_ctx *xcode_encode = NULL;
|
||||
struct transcode_evbuf_io xcode_evbuf_io = { 0 };
|
||||
struct evbuffer *xcode_buf = NULL;
|
||||
void *frame;
|
||||
int src_width;
|
||||
@ -633,9 +634,15 @@ artwork_get(struct evbuffer *evbuf, char *path, struct evbuffer *in_buf, bool is
|
||||
ret = ART_E_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
else
|
||||
{
|
||||
xcode_decode = transcode_decode_setup(XCODE_JPEG, NULL, data_kind, path, NULL, 0); // Covers XCODE_PNG too
|
||||
}
|
||||
|
||||
xcode_decode = transcode_decode_setup(XCODE_JPEG, NULL, data_kind, path, xcode_buf, 0); // Covers XCODE_PNG too
|
||||
if (!xcode_decode)
|
||||
{
|
||||
if (path)
|
||||
|
@ -46,8 +46,10 @@ struct playback_ctx
|
||||
{
|
||||
struct transcode_ctx *xcode;
|
||||
|
||||
int read_fd;
|
||||
// This buffer gets fairly large, since it reads and holds the Ogg track that
|
||||
// spotifyc downloads. It has no write limit, unlike the input buffer.
|
||||
struct evbuffer *read_buf;
|
||||
int read_fd;
|
||||
size_t read_bytes;
|
||||
|
||||
uint32_t len_ms;
|
||||
@ -286,10 +288,13 @@ static int
|
||||
playback_xcode_setup(struct playback_ctx *playback)
|
||||
{
|
||||
struct transcode_ctx *xcode;
|
||||
struct transcode_evbuf_io xcode_evbuf_io = { 0 };
|
||||
|
||||
CHECK_NULL(L_SPOTIFY, xcode = malloc(sizeof(struct transcode_ctx)));
|
||||
|
||||
xcode->decode_ctx = transcode_decode_setup(XCODE_OGG, NULL, DATA_KIND_SPOTIFY, NULL, playback->read_buf, playback->len_ms);
|
||||
xcode_evbuf_io.evbuf = playback->read_buf;
|
||||
|
||||
xcode->decode_ctx = transcode_decode_setup(XCODE_OGG, NULL, DATA_KIND_SPOTIFY, NULL, &xcode_evbuf_io, playback->len_ms);
|
||||
if (!xcode->decode_ctx)
|
||||
goto error;
|
||||
|
||||
|
@ -188,6 +188,8 @@ enum probe_type
|
||||
struct avio_evbuffer {
|
||||
struct evbuffer *evbuf;
|
||||
uint8_t *buffer;
|
||||
transcode_seekfn seekfn;
|
||||
void *seekfn_arg;
|
||||
};
|
||||
|
||||
|
||||
@ -809,8 +811,27 @@ avio_evbuffer_write(void *opaque, uint8_t *buf, int size)
|
||||
return (ret == 0) ? size : -1;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
avio_evbuffer_seek(void *opaque, int64_t offset, int whence)
|
||||
{
|
||||
struct avio_evbuffer *ae = (struct avio_evbuffer *)opaque;
|
||||
enum transcode_seek_type seek_type;
|
||||
|
||||
// Caller shouldn't need to know about ffmpeg defines
|
||||
if (whence & AVSEEK_SIZE)
|
||||
seek_type = XCODE_SEEK_SIZE;
|
||||
else if (whence == SEEK_SET)
|
||||
seek_type = XCODE_SEEK_SET;
|
||||
else if (whence == SEEK_CUR)
|
||||
seek_type = XCODE_SEEK_CUR;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return ae->seekfn(ae->seekfn_arg, offset, seek_type);
|
||||
}
|
||||
|
||||
static AVIOContext *
|
||||
avio_evbuffer_open(struct evbuffer *evbuf, int is_output)
|
||||
avio_evbuffer_open(struct transcode_evbuf_io *evbuf_io, int is_output)
|
||||
{
|
||||
struct avio_evbuffer *ae;
|
||||
AVIOContext *s;
|
||||
@ -832,12 +853,14 @@ avio_evbuffer_open(struct evbuffer *evbuf, int is_output)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ae->evbuf = evbuf;
|
||||
ae->evbuf = evbuf_io->evbuf;
|
||||
ae->seekfn = evbuf_io->seekfn;
|
||||
ae->seekfn_arg = evbuf_io->seekfn_arg;
|
||||
|
||||
if (is_output)
|
||||
s = avio_alloc_context(ae->buffer, AVIO_BUFFER_SIZE, 1, ae, NULL, avio_evbuffer_write, NULL);
|
||||
else
|
||||
s = avio_alloc_context(ae->buffer, AVIO_BUFFER_SIZE, 0, ae, avio_evbuffer_read, NULL, NULL);
|
||||
s = avio_alloc_context(ae->buffer, AVIO_BUFFER_SIZE, 0, ae, avio_evbuffer_read, NULL, (evbuf_io->seekfn ? avio_evbuffer_seek : NULL));
|
||||
|
||||
if (!s)
|
||||
{
|
||||
@ -848,21 +871,30 @@ avio_evbuffer_open(struct evbuffer *evbuf, int is_output)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 0 here does not seem to mean not seekable, because ffmpeg will still call
|
||||
// avio_evbuffer_seek. If set to AVIO_SEEKABLE_NORMAL then ffmpeg seems to
|
||||
// make random access seek requests during input_open (i.e. asking for start
|
||||
// and end of file), which are hard to fulfill when the source is something
|
||||
// that is downloaded.
|
||||
s->seekable = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static AVIOContext *
|
||||
avio_input_evbuffer_open(struct evbuffer *evbuf)
|
||||
avio_input_evbuffer_open(struct transcode_evbuf_io *evbuf_io)
|
||||
{
|
||||
return avio_evbuffer_open(evbuf, 0);
|
||||
return avio_evbuffer_open(evbuf_io, 0);
|
||||
}
|
||||
|
||||
static AVIOContext *
|
||||
avio_output_evbuffer_open(struct evbuffer *evbuf)
|
||||
{
|
||||
return avio_evbuffer_open(evbuf, 1);
|
||||
struct transcode_evbuf_io evbuf_io = { 0 };
|
||||
|
||||
evbuf_io.evbuf = evbuf;
|
||||
|
||||
return avio_evbuffer_open(&evbuf_io, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -933,7 +965,7 @@ open_decoder(AVCodecContext **dec_ctx, unsigned int *stream_index, struct decode
|
||||
}
|
||||
|
||||
static int
|
||||
open_input(struct decode_ctx *ctx, const char *path, struct evbuffer *evbuf, enum probe_type probe_type)
|
||||
open_input(struct decode_ctx *ctx, const char *path, struct transcode_evbuf_io *evbuf_io, enum probe_type probe_type)
|
||||
{
|
||||
AVDictionary *options = NULL;
|
||||
AVCodecContext *dec_ctx;
|
||||
@ -973,7 +1005,7 @@ open_input(struct decode_ctx *ctx, const char *path, struct evbuffer *evbuf, enu
|
||||
ctx->ifmt_ctx->interrupt_callback.opaque = ctx;
|
||||
ctx->timestamp = av_gettime();
|
||||
|
||||
if (evbuf)
|
||||
if (evbuf_io)
|
||||
{
|
||||
ifmt = av_find_input_format(ctx->settings.in_format);
|
||||
if (!ifmt)
|
||||
@ -982,7 +1014,7 @@ open_input(struct decode_ctx *ctx, const char *path, struct evbuffer *evbuf, enu
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
CHECK_NULL(L_XCODE, ctx->avio = avio_input_evbuffer_open(evbuf));
|
||||
CHECK_NULL(L_XCODE, ctx->avio = avio_input_evbuffer_open(evbuf_io));
|
||||
|
||||
ctx->ifmt_ctx->pb = ctx->avio;
|
||||
ret = avformat_open_input(&ctx->ifmt_ctx, NULL, ifmt, &options);
|
||||
@ -1344,7 +1376,7 @@ close_filters(struct encode_ctx *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 evbuffer *evbuf, uint32_t song_length)
|
||||
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 song_length)
|
||||
{
|
||||
struct decode_ctx *ctx;
|
||||
int ret;
|
||||
@ -1362,14 +1394,14 @@ transcode_decode_setup(enum transcode_profile profile, struct media_quality *qua
|
||||
|
||||
if (data_kind == DATA_KIND_HTTP)
|
||||
{
|
||||
ret = open_input(ctx, path, evbuf, PROBE_TYPE_QUICK);
|
||||
ret = open_input(ctx, path, evbuf_io, PROBE_TYPE_QUICK);
|
||||
|
||||
// Retry with a default, slower probe size
|
||||
if (ret == AVERROR_STREAM_NOT_FOUND)
|
||||
ret = open_input(ctx, path, evbuf, PROBE_TYPE_DEFAULT);
|
||||
ret = open_input(ctx, path, evbuf_io, PROBE_TYPE_DEFAULT);
|
||||
}
|
||||
else
|
||||
ret = open_input(ctx, path, evbuf, PROBE_TYPE_DEFAULT);
|
||||
ret = open_input(ctx, path, evbuf_io, PROBE_TYPE_DEFAULT);
|
||||
|
||||
if (ret < 0)
|
||||
goto fail_free;
|
||||
|
@ -33,6 +33,16 @@ enum transcode_profile
|
||||
XCODE_VP8,
|
||||
};
|
||||
|
||||
enum transcode_seek_type
|
||||
{
|
||||
XCODE_SEEK_SIZE,
|
||||
XCODE_SEEK_SET,
|
||||
XCODE_SEEK_CUR,
|
||||
};
|
||||
|
||||
typedef void transcode_frame;
|
||||
typedef int64_t(*transcode_seekfn)(void *arg, int64_t offset, enum transcode_seek_type seek_type);
|
||||
|
||||
struct decode_ctx;
|
||||
struct encode_ctx;
|
||||
struct transcode_ctx
|
||||
@ -41,11 +51,18 @@ struct transcode_ctx
|
||||
struct encode_ctx *encode_ctx;
|
||||
};
|
||||
|
||||
typedef void transcode_frame;
|
||||
struct transcode_evbuf_io
|
||||
{
|
||||
struct evbuffer *evbuf;
|
||||
|
||||
// Set to null if no seek support required
|
||||
transcode_seekfn seekfn;
|
||||
void *seekfn_arg;
|
||||
};
|
||||
|
||||
// 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 evbuffer *evbuf, uint32_t song_length);
|
||||
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 song_length);
|
||||
|
||||
struct encode_ctx *
|
||||
transcode_encode_setup(enum transcode_profile profile, struct media_quality *quality, struct decode_ctx *src_ctx, off_t *est_size, int width, int height);
|
||||
|
Loading…
x
Reference in New Issue
Block a user