From 5fd8a1e04c725329435e3bead5f11ee3ffb9f1c1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 10 Nov 2014 22:01:23 +0100 Subject: 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. --- audio/decode/ad.h | 2 +- audio/decode/ad_lavc.c | 92 +++++++++++--------------- audio/decode/ad_mpg123.c | 19 +++--- audio/decode/ad_spdif.c | 19 +++--- audio/decode/dec_audio.c | 164 +++++++++++++---------------------------------- audio/decode/dec_audio.h | 5 +- audio/filter/af.c | 44 ++++++++++--- audio/filter/af.h | 4 +- player/audio.c | 12 ++-- player/command.c | 4 +- 10 files changed, 153 insertions(+), 212 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; diff --git a/audio/filter/af.c b/audio/filter/af.c index d396a73ce3..46e577537f 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -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. diff --git a/audio/filter/af.h b/audio/filter/af.h index 5c7a6c0e7c..682cdb93e3 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -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); diff --git a/player/audio.c b/player/audio.c index 413cbf4a32..e3dbe6577c 100644 --- a/player/audio.c +++ b/player/audio.c @@ -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); diff --git a/player/command.c b/player/command.c index 04c0c4d789..3513d99afc 100644 --- a/player/command.c +++ b/player/command.c @@ -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) { -- cgit v1.2.3