0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00

audio: make decoders output refcounted frames

This rewrites the audio decode loop to some degree. Audio filters don't
do refcounted frames yet, so af.c contains a hacky "emulation".

Remove some of the weird heuristic-heavy code in dec_audio.c. Instead of
estimating how much audio we need to filter, we always filter full
frames. Maybe this should be adjusted later: in case filtering increases
the volume of the audio data, we should try not to buffer too much
filter output by reducing the input that is fed at once.

For ad_spdif.c and ad_mpg123.c, we don't avoid extra copying yet - it
doesn't seem worth the trouble.
This commit is contained in:
wm4 2014-11-10 22:01:23 +01:00
parent 46d6fb9dc1
commit 5fd8a1e04c
10 changed files with 151 additions and 210 deletions

View File

@ -36,7 +36,7 @@ struct ad_functions {
int (*init)(struct dec_audio *da, const char *decoder);
void (*uninit)(struct dec_audio *da);
int (*control)(struct dec_audio *da, int cmd, void *arg);
int (*decode_packet)(struct dec_audio *da);
int (*decode_packet)(struct dec_audio *da, struct mp_audio **out);
};
enum ad_ctrl {

View File

@ -73,55 +73,6 @@ const struct m_sub_options ad_lavc_conf = {
},
};
static void set_data_from_avframe(struct dec_audio *da)
{
struct priv *priv = da->priv;
AVCodecContext *lavc_context = priv->avctx;
// Note: invalid parameters are rejected by dec_audio.c
int fmt = lavc_context->sample_fmt;
mp_audio_set_format(&da->decoded, af_from_avformat(fmt));
if (!da->decoded.format)
MP_FATAL(da, "unsupported lavc format %s", av_get_sample_fmt_name(fmt));
da->decoded.rate = lavc_context->sample_rate;
struct mp_chmap lavc_chmap;
mp_chmap_from_lavc(&lavc_chmap, lavc_context->channel_layout);
// No channel layout or layout disagrees with channel count
if (lavc_chmap.num != lavc_context->channels)
mp_chmap_from_channels(&lavc_chmap, lavc_context->channels);
if (priv->force_channel_map) {
struct sh_audio *sh_audio = da->header->audio;
if (lavc_chmap.num == sh_audio->channels.num)
lavc_chmap = sh_audio->channels;
}
mp_audio_set_channels(&da->decoded, &lavc_chmap);
da->decoded.samples = priv->avframe->nb_samples;
for (int n = 0; n < da->decoded.num_planes; n++)
da->decoded.planes[n] = priv->avframe->data[n];
#if HAVE_AVFRAME_SKIP_SAMPLES
AVFrameSideData *sd =
av_frame_get_side_data(priv->avframe, AV_FRAME_DATA_SKIP_SAMPLES);
if (sd && sd->size >= 10) {
char *d = sd->data;
priv->skip_samples += AV_RL32(d + 0);
uint32_t pad = AV_RL32(d + 4);
uint32_t skip = MPMIN(priv->skip_samples, da->decoded.samples);
if (skip) {
mp_audio_skip_samples(&da->decoded, skip);
da->pts_offset += skip;
priv->skip_samples -= skip;
}
if (pad <= da->decoded.samples)
da->decoded.samples -= pad;
}
#endif
}
static int init(struct dec_audio *da, const char *decoder)
{
struct MPOpts *mpopts = da->opts;
@ -222,7 +173,6 @@ static int control(struct dec_audio *da, int cmd, void *arg)
switch (cmd) {
case ADCTRL_RESET:
avcodec_flush_buffers(ctx->avctx);
mp_audio_set_null_data(&da->decoded);
talloc_free(ctx->packet);
ctx->packet = NULL;
ctx->skip_samples = 0;
@ -231,13 +181,11 @@ static int control(struct dec_audio *da, int cmd, void *arg)
return CONTROL_UNKNOWN;
}
static int decode_packet(struct dec_audio *da)
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
mp_audio_set_null_data(&da->decoded);
struct demux_packet *mpkt = priv->packet;
if (!mpkt) {
if (demux_read_packet_async(da->header, &mpkt) == 0)
@ -290,9 +238,43 @@ static int decode_packet(struct dec_audio *da)
da->pts_offset = 0;
}
set_data_from_avframe(da);
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
if (!mpframe)
return AD_ERR;
MP_DBG(da, "Decoded %d -> %d samples\n", in_len, da->decoded.samples);
struct mp_chmap lavc_chmap = mpframe->channels;
if (lavc_chmap.num != avctx->channels)
mp_chmap_from_channels(&lavc_chmap, avctx->channels);
if (priv->force_channel_map) {
struct sh_audio *sh_audio = da->header->audio;
if (lavc_chmap.num == sh_audio->channels.num)
lavc_chmap = sh_audio->channels;
}
mp_audio_set_channels(mpframe, &lavc_chmap);
#if HAVE_AVFRAME_SKIP_SAMPLES
AVFrameSideData *sd =
av_frame_get_side_data(priv->avframe, AV_FRAME_DATA_SKIP_SAMPLES);
if (sd && sd->size >= 10) {
char *d = sd->data;
priv->skip_samples += AV_RL32(d + 0);
uint32_t pad = AV_RL32(d + 4);
uint32_t skip = MPMIN(priv->skip_samples, mpframe->samples);
if (skip) {
mp_audio_skip_samples(mpframe, skip);
da->pts_offset += skip;
priv->skip_samples -= skip;
}
if (pad <= mpframe->samples)
mpframe->samples -= pad;
}
#endif
*out = mpframe;
av_frame_unref(priv->avframe);
MP_DBG(da, "Decoded %d -> %d samples\n", in_len, mpframe->samples);
return 0;
}

View File

@ -43,6 +43,7 @@ struct ad_mpg123_context {
short delay;
/* If the stream is actually VBR. */
char vbr;
struct mp_audio frame;
};
static void uninit(struct dec_audio *da)
@ -197,27 +198,25 @@ static int set_format(struct dec_audio *da)
int encoding;
ret = mpg123_getformat(con->handle, &rate, &channels, &encoding);
if (ret == MPG123_OK) {
mp_audio_set_num_channels(&da->decoded, channels);
da->decoded.rate = rate;
mp_audio_set_num_channels(&con->frame, channels);
con->frame.rate = rate;
int af = mpg123_format_to_af(encoding);
if (!af) {
/* This means we got a funny custom build of libmpg123 that only supports an unknown format. */
MP_ERR(da, "Bad encoding from mpg123: %i.\n", encoding);
return MPG123_ERR;
}
mp_audio_set_format(&da->decoded, af);
mp_audio_set_format(&con->frame, af);
con->sample_size = channels * af_fmt2bps(af);
}
return ret;
}
static int decode_packet(struct dec_audio *da)
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct ad_mpg123_context *con = da->priv;
int ret;
mp_audio_set_null_data(&da->decoded);
struct demux_packet *pkt;
if (demux_read_packet_async(da->header, &pkt) == 0)
return AD_WAIT;
@ -257,8 +256,11 @@ static int decode_packet(struct dec_audio *da)
}
int got_samples = bytes / con->sample_size;
da->decoded.planes[0] = audio;
da->decoded.samples = got_samples;
*out = mp_audio_pool_get(da->pool, &con->frame, got_samples);
if (!*out)
return AD_ERR;
memcpy((*out)->planes[0], audio, bytes);
update_info(da);
return 0;
@ -274,7 +276,6 @@ static int control(struct dec_audio *da, int cmd, void *arg)
switch (cmd) {
case ADCTRL_RESET:
mp_audio_set_null_data(&da->decoded);
mpg123_close(con->handle);
if (mpg123_open_feed(con->handle) != MPG123_OK) {

View File

@ -40,6 +40,7 @@ struct spdifContext {
int out_buffer_len;
uint8_t out_buffer[OUTBUF_SIZE];
bool need_close;
struct mp_audio fmt;
};
static int write_packet(void *p, uint8_t *buf, int buf_size)
@ -162,9 +163,9 @@ static int init(struct dec_audio *da, const char *decoder)
default:
abort();
}
mp_audio_set_num_channels(&da->decoded, num_channels);
mp_audio_set_format(&da->decoded, sample_format);
da->decoded.rate = samplerate;
mp_audio_set_num_channels(&spdif_ctx->fmt, num_channels);
mp_audio_set_format(&spdif_ctx->fmt, sample_format);
spdif_ctx->fmt.rate = samplerate;
if (avformat_write_header(lavf_ctx, &format_opts) < 0) {
MP_FATAL(da, "libavformat spdif initialization failed.\n");
@ -182,13 +183,11 @@ fail:
return 0;
}
static int decode_packet(struct dec_audio *da)
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct spdifContext *spdif_ctx = da->priv;
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
mp_audio_set_null_data(&da->decoded);
spdif_ctx->out_buffer_len = 0;
struct demux_packet *mpkt;
@ -212,8 +211,12 @@ static int decode_packet(struct dec_audio *da)
if (ret < 0)
return AD_ERR;
da->decoded.planes[0] = spdif_ctx->out_buffer;
da->decoded.samples = spdif_ctx->out_buffer_len / da->decoded.sstride;
int samples = spdif_ctx->out_buffer_len / spdif_ctx->fmt.sstride;
*out = mp_audio_pool_get(da->pool, &spdif_ctx->fmt, samples);
if (!*out)
return AD_ERR;
memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
return 0;
}

View File

@ -56,19 +56,6 @@ static const struct ad_functions * const ad_drivers[] = {
NULL
};
// Drop audio buffer and reinit it (after format change)
// Returns whether the format was valid at all.
static bool reinit_audio_buffer(struct dec_audio *da)
{
if (!mp_audio_config_valid(&da->decoded)) {
MP_ERR(da, "Audio decoder did not specify audio "
"format, or requested an unsupported configuration!\n");
return false;
}
mp_audio_buffer_reinit(da->decode_buffer, &da->decoded);
return true;
}
static void uninit_decoder(struct dec_audio *d_audio)
{
if (d_audio->ad_driver) {
@ -89,7 +76,6 @@ static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
return 0;
}
d_audio->decode_buffer = mp_audio_buffer_create(NULL);
return 1;
}
@ -167,7 +153,6 @@ void audio_uninit(struct dec_audio *d_audio)
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
af_destroy(d_audio->afilter);
uninit_decoder(d_audio);
talloc_free(d_audio->decode_buffer);
talloc_free(d_audio);
}
@ -177,78 +162,14 @@ void audio_uninit(struct dec_audio *d_audio)
*/
int initial_audio_decode(struct dec_audio *da)
{
while (!mp_audio_config_valid(&da->decoded)) {
if (da->decoded.samples > 0)
return AD_ERR; // invalid format, rather than uninitialized
int ret = da->ad_driver->decode_packet(da);
while (!da->waiting) {
int ret = da->ad_driver->decode_packet(da, &da->waiting);
if (ret < 0)
return ret;
}
if (mp_audio_buffer_samples(da->decode_buffer) > 0) // avoid accidental flush
return AD_OK;
return reinit_audio_buffer(da) ? AD_OK : AD_ERR;
}
// Filter len bytes of input, put result into outbuf.
static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
int len)
{
bool format_change = false;
int error = 0;
assert(len > 0); // would break EOF logic below
while (mp_audio_buffer_samples(da->decode_buffer) < len) {
// Check for a format change
struct mp_audio config;
mp_audio_buffer_get_format(da->decode_buffer, &config);
format_change = !mp_audio_config_equals(&da->decoded, &config);
if (format_change) {
error = AD_EOF; // drain remaining data left in the current buffer
break;
}
if (da->decoded.samples > 0) {
int copy = MPMIN(da->decoded.samples, len);
struct mp_audio append = da->decoded;
append.samples = copy;
mp_audio_buffer_append(da->decode_buffer, &append);
mp_audio_skip_samples(&da->decoded, copy);
da->pts_offset += copy;
continue;
}
error = da->ad_driver->decode_packet(da);
if (error < 0)
break;
}
if (error == AD_WAIT)
return error;
// Filter
struct mp_audio filter_data;
mp_audio_buffer_peek(da->decode_buffer, &filter_data);
len = MPMIN(filter_data.samples, len);
filter_data.samples = len;
bool eof = error == AD_EOF && filter_data.samples == 0;
if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0)
return AD_ERR;
mp_audio_buffer_append(outbuf, &filter_data);
if (error == AD_EOF && filter_data.samples > 0)
error = 0; // don't end playback yet
// remove processed data from decoder buffer:
mp_audio_buffer_skip(da->decode_buffer, len);
// if format was changed, and all data was drained, execute the format change
if (format_change && eof) {
error = AD_NEW_FMT;
if (!reinit_audio_buffer(da))
error = AD_ERR; // switch to invalid format
}
return error;
talloc_steal(da, da->waiting);
da->decode_format = *da->waiting;
return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR;
}
/* Try to get at least minsamples decoded+filtered samples in outbuf
@ -256,52 +177,55 @@ static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
* Return 0 on success, or negative AD_* error code.
* In the former case outbuf has at least minsamples buffered on return.
* In case of EOF/error it might or might not be. */
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
int audio_decode(struct dec_audio *da, struct mp_audio_buffer *outbuf,
int minsamples)
{
if (d_audio->afilter->initialized < 1)
struct af_stream *afs = da->afilter;
if (afs->initialized < 1)
return AD_ERR;
// Indicates that a filter seems to be buffering large amounts of data
int huge_filter_buffer = 0;
MP_STATS(da, "start audio");
/* Filter output size will be about filter_multiplier times input size.
* If some filter buffers audio in big blocks this might only hold
* as average over time. */
double filter_multiplier = af_calc_filter_multiplier(d_audio->afilter);
int prev_buffered = -1;
int res = 0;
MP_STATS(d_audio, "start audio");
while (res >= 0 && minsamples >= 0) {
int buffered = mp_audio_buffer_samples(outbuf);
if (minsamples < buffered || buffered == prev_buffered)
if (minsamples < buffered)
break;
prev_buffered = buffered;
int decsamples = (minsamples - buffered) / filter_multiplier;
// + some extra for possible filter buffering, and avoid 0
decsamples += 512;
res = 0;
if (huge_filter_buffer) {
/* Some filter must be doing significant buffering if the estimated
* input length didn't produce enough output from filters.
* Feed the filters 250 samples at a time until we have enough
* output. Very small amounts could make filtering inefficient while
* large amounts can make mpv demux the file unnecessarily far ahead
* to get audio data and buffer video frames in memory while doing
* so. However the performance impact of either is probably not too
* significant as long as the value is not completely insane. */
decsamples = 250;
struct mp_audio *mpa = da->waiting;
if (!mpa)
res = da->ad_driver->decode_packet(da, &mpa);
if (res != AD_EOF) {
if (res < 0)
break;
if (!mpa )
continue;
}
/* if this iteration does not fill buffer, we must have lots
* of buffering in filters */
huge_filter_buffer = 1;
if (mpa) {
da->pts_offset += mpa->samples;
da->decode_format = *mpa;
mp_audio_set_null_data(&da->decode_format);
// On format change, make sure to drain the filter chain.
if (!mp_audio_config_equals(&afs->input, mpa)) {
res = AD_NEW_FMT;
da->waiting = talloc_steal(da, mpa);
mpa = NULL;
}
}
res = filter_n_bytes(d_audio, outbuf, decsamples);
if (mpa)
da->waiting = NULL;
if (af_filter(afs, mpa, outbuf) < 0)
return AD_ERR;
}
MP_STATS(d_audio, "end audio");
MP_STATS(da, "end audio");
return res;
}
@ -312,6 +236,8 @@ void audio_reset_decoding(struct dec_audio *d_audio)
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
d_audio->pts = MP_NOPTS_VALUE;
d_audio->pts_offset = 0;
if (d_audio->decode_buffer)
mp_audio_buffer_clear(d_audio->decode_buffer);
if (d_audio->waiting) {
talloc_free(d_audio->waiting);
d_audio->waiting = NULL;
}
}

View File

@ -33,12 +33,13 @@ struct dec_audio {
struct mpv_global *global;
const struct ad_functions *ad_driver;
struct sh_stream *header;
struct mp_audio_buffer *decode_buffer;
struct af_stream *afilter;
char *decoder_desc;
int init_retries;
struct mp_audio_pool *pool;
struct mp_audio decode_format;
struct mp_audio *waiting; // used on format-change
// set by decoder
struct mp_audio decoded; // decoded audio set by last decode_packet() call
int bitrate; // input bitrate, can change with VBR sources
// last known pts value in output from decoder
double pts;

View File

@ -28,6 +28,7 @@
#include "options/m_option.h"
#include "options/m_config.h"
#include "audio/audio_buffer.h"
#include "af.h"
// Static list of filters
@ -721,24 +722,49 @@ int af_remove_by_label(struct af_stream *s, char *label)
return 1;
}
/* Filter data chunk through the filters in the list.
* On success, *data is set to the filtered data/format.
* Warning: input audio data will be overwritten.
/* Feed "data" to the chain, and write results to output. "data" needs to be
* a refcounted frame, although refcounting is not used yet.
* data==NULL means EOF.
*/
int af_filter(struct af_stream *s, struct mp_audio *data, int flags)
int af_filter(struct af_stream *s, struct mp_audio *data,
struct mp_audio_buffer *output)
{
struct af_instance *af = s->first;
assert(s->initialized > 0);
assert(mp_audio_config_equals(af->data, data));
int flags = 0;
int r = 0;
struct mp_audio tmp;
char dummy[MP_NUM_CHANNELS];
if (data) {
assert(mp_audio_config_equals(af->data, data));
r = mp_audio_make_writeable(data);
} else {
data = &tmp;
*data = *(af->data);
mp_audio_set_null_data(data);
flags = AF_FILTER_FLAG_EOF;
for (int n = 0; n < MP_NUM_CHANNELS; n++)
data->planes[n] = &dummy[n];
}
if (r < 0)
goto done;
struct mp_audio frame = *data;
for (int n = 0; n < MP_NUM_CHANNELS; n++)
frame.allocated[n] = NULL;
// Iterate through all filters
while (af) {
int r = af->filter(af, data, flags);
r = af->filter(af, &frame, flags);
if (r < 0)
return r;
assert(mp_audio_config_equals(af->data, data));
goto done;
assert(mp_audio_config_equals(af->data, &frame));
af = af->next;
}
return 0;
mp_audio_buffer_append(output, &frame);
done:
if (data != &tmp)
talloc_free(data);
return r;
}
// Calculate average ratio of filter output samples to input samples.

View File

@ -136,7 +136,9 @@ void af_uninit(struct af_stream *s);
struct af_instance *af_add(struct af_stream *s, char *name, char **args);
int af_remove_by_label(struct af_stream *s, char *label);
struct af_instance *af_find_by_label(struct af_stream *s, char *label);
int af_filter(struct af_stream *s, struct mp_audio *data, int flags);
struct mp_audio_buffer;
int af_filter(struct af_stream *s, struct mp_audio *data,
struct mp_audio_buffer *output);
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
void af_control_all(struct af_stream *s, int cmd, void *arg);

View File

@ -192,6 +192,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
mpctx->d_audio->global = mpctx->global;
mpctx->d_audio->opts = opts;
mpctx->d_audio->header = sh;
mpctx->d_audio->pool = mp_audio_pool_create(mpctx->d_audio);
mpctx->d_audio->afilter = af_new(mpctx->global);
mpctx->d_audio->afilter->replaygain_data = sh->audio->replaygain_data;
mpctx->ao_buffer = mp_audio_buffer_create(NULL);
@ -207,8 +208,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
}
assert(mpctx->d_audio);
struct mp_audio in_format;
mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &in_format);
struct mp_audio in_format = mpctx->d_audio->decode_format;
if (!mp_audio_config_valid(&in_format)) {
// We don't know the audio format yet - so configure it later as we're
@ -238,7 +238,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
}
// filter input format: same as codec's output format:
mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &afs->input);
afs->input = in_format;
// Determine what the filter chain outputs. recreate_audio_filters() also
// needs this for testing whether playback speed is changed by resampling
@ -304,8 +304,7 @@ double written_audio_pts(struct MPContext *mpctx)
if (!d_audio)
return MP_NOPTS_VALUE;
struct mp_audio in_format;
mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format);
struct mp_audio in_format = d_audio->decode_format;
if (!mp_audio_config_valid(&in_format) || d_audio->afilter->initialized < 1)
return MP_NOPTS_VALUE;
@ -324,7 +323,8 @@ double written_audio_pts(struct MPContext *mpctx)
// Subtract data in buffers between decoder and audio out.
// Decoded but not filtered
a_pts -= mp_audio_buffer_seconds(d_audio->decode_buffer);
if (d_audio->waiting)
a_pts -= d_audio->waiting->samples / (double)in_format.rate;
// Data buffered in audio filters, measured in seconds of "missing" output
double buffered_output = af_calc_delay(d_audio->afilter);

View File

@ -1550,7 +1550,7 @@ static int mp_property_samplerate(void *ctx, struct m_property *prop,
MPContext *mpctx = ctx;
struct mp_audio fmt = {0};
if (mpctx->d_audio)
mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &fmt);
fmt = mpctx->d_audio->decode_format;
if (!fmt.rate)
return M_PROPERTY_UNAVAILABLE;
if (action == M_PROPERTY_PRINT) {
@ -1567,7 +1567,7 @@ static int mp_property_channels(void *ctx, struct m_property *prop,
MPContext *mpctx = ctx;
struct mp_audio fmt = {0};
if (mpctx->d_audio)
mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &fmt);
fmt = mpctx->d_audio->decode_format;
if (!fmt.channels.num)
return M_PROPERTY_UNAVAILABLE;
switch (action) {