summaryrefslogtreecommitdiffstats
path: root/audio/decode
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-11-10 22:01:23 +0100
committerwm4 <wm4@nowhere>2014-11-10 22:02:05 +0100
commit5fd8a1e04c725329435e3bead5f11ee3ffb9f1c1 (patch)
treea3a3ae0ac6ee87449ed780604e55da6dca2f34f2 /audio/decode
parent46d6fb9dc1a820b58dd3ffcc155195aea6bb0bd1 (diff)
downloadmpv-5fd8a1e04c725329435e3bead5f11ee3ffb9f1c1.tar.bz2
mpv-5fd8a1e04c725329435e3bead5f11ee3ffb9f1c1.tar.xz
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.
Diffstat (limited to 'audio/decode')
-rw-r--r--audio/decode/ad.h2
-rw-r--r--audio/decode/ad_lavc.c92
-rw-r--r--audio/decode/ad_mpg123.c19
-rw-r--r--audio/decode/ad_spdif.c19
-rw-r--r--audio/decode/dec_audio.c164
-rw-r--r--audio/decode/dec_audio.h5
6 files changed, 107 insertions, 194 deletions
diff --git a/audio/decode/ad.h b/audio/decode/ad.h
index e09ded2efc..852df7ccc9 100644
--- a/audio/decode/ad.h
+++ b/audio/decode/ad.h
@@ -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 {
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 31ac5f71ba..8825172123 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -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;
+
+ 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, da->decoded.samples);
+ MP_DBG(da, "Decoded %d -> %d samples\n", in_len, mpframe->samples);
return 0;
}
diff --git a/audio/decode/ad_mpg123.c b/audio/decode/ad_mpg123.c
index 30a4790746..2fbbec6032 100644
--- a/audio/decode/ad_mpg123.c
+++ b/audio/decode/ad_mpg123.c
@@ -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) {
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index bb39298dd6..a0d6d4da99 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -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;
}
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 8b38b71bc7..da541de674 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -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;
-
- 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;
+
+ res = 0;
+
+ 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 (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;
+ }
}
- /* if this iteration does not fill buffer, we must have lots
- * of buffering in filters */
- huge_filter_buffer = 1;
+ if (mpa)
+ da->waiting = NULL;
- res = filter_n_bytes(d_audio, outbuf, decsamples);
+ 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;
+ }
}
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index 08fa87e8a7..ab7ae3375a 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -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;