diff options
author | wm4 <wm4@nowhere> | 2013-11-12 23:42:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-11-12 23:42:04 +0100 |
commit | e4bbb1d348dafbb32722f413648006a7bd9d0897 (patch) | |
tree | 7165ed9f86a77b751187600d0a9de8b35416f380 | |
parent | e4f2fcc0ecd31322df65141edf0ddbff9c075f5d (diff) | |
parent | 22b3f522cacfbdba76d311c86efd6091512eb089 (diff) |
Merge branch 'planar_audio'
Conflicts:
audio/out/ao_lavc.c
65 files changed, 1549 insertions, 1489 deletions
@@ -139,6 +139,7 @@ endif SOURCES-$(DLOPEN) += video/filter/vf_dlopen.c SOURCES = audio/audio.c \ + audio/audio_buffer.c \ audio/chmap.c \ audio/chmap_sel.c \ audio/fmt-conversion.c \ diff --git a/audio/audio.c b/audio/audio.c index 9d41928436..2a67e22e5e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -17,42 +17,60 @@ #include <assert.h> +#include <libavutil/mem.h> + +#include "mpvcore/mp_common.h" #include "mpvcore/mp_talloc.h" #include "audio.h" +static void update_redundant_info(struct mp_audio *mpa) +{ + assert(mp_chmap_is_empty(&mpa->channels) || + mp_chmap_is_valid(&mpa->channels)); + mpa->nch = mpa->channels.num; + mpa->bps = af_fmt2bits(mpa->format) / 8; + if (af_fmt_is_planar(mpa->format)) { + mpa->spf = 1; + mpa->num_planes = mpa->nch; + mpa->sstride = mpa->bps; + } else { + mpa->spf = mpa->nch; + mpa->num_planes = 1; + mpa->sstride = mpa->bps * mpa->nch; + } +} + void mp_audio_set_format(struct mp_audio *mpa, int format) { mpa->format = format; - mpa->bps = af_fmt2bits(format) / 8; + update_redundant_info(mpa); } void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels) { - struct mp_chmap map; - mp_chmap_from_channels(&map, num_channels); - mp_audio_set_channels(mpa, &map); + mp_chmap_from_channels(&mpa->channels, num_channels); + update_redundant_info(mpa); } // Use old MPlayer/ALSA channel layout. void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels) { - struct mp_chmap map; - mp_chmap_from_channels_alsa(&map, num_channels); - mp_audio_set_channels(mpa, &map); + mp_chmap_from_channels_alsa(&mpa->channels, num_channels); + update_redundant_info(mpa); } void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap) { - assert(mp_chmap_is_empty(chmap) || mp_chmap_is_valid(chmap)); mpa->channels = *chmap; - mpa->nch = mpa->channels.num; + update_redundant_info(mpa); } void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src) { - mp_audio_set_format(dst, src->format); - mp_audio_set_channels(dst, &src->channels); + dst->format = src->format; + dst->channels = src->channels; dst->rate = src->rate; + update_redundant_info(dst); } bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b) @@ -74,3 +92,135 @@ char *mp_audio_config_to_str(struct mp_audio *mpa) { return mp_audio_fmt_to_str(mpa->rate, &mpa->channels, mpa->format); } + +void mp_audio_force_interleaved_format(struct mp_audio *mpa) +{ + if (af_fmt_is_planar(mpa->format)) + mp_audio_set_format(mpa, af_fmt_from_planar(mpa->format)); +} + +// Return used size of a plane. (The size is the same for all planes.) +int mp_audio_psize(struct mp_audio *mpa) +{ + return mpa->samples * mpa->sstride; +} + +void mp_audio_set_null_data(struct mp_audio *mpa) +{ + for (int n = 0; n < MP_NUM_CHANNELS; n++) + mpa->planes[n] = NULL; + mpa->samples = 0; +} + +static void mp_audio_destructor(void *ptr) +{ + struct mp_audio *mpa = ptr; + for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) { + // Note: don't free if not allocated by mp_audio_realloc + if (mpa->allocated[n]) + av_free(mpa->planes[n]); + } +} + +/* Reallocate the data stored in mpa->planes[n] so that enough samples are + * available on every plane. The previous data is kept (for the smallest + * common number of samples before/after resize). + * + * mpa->samples is not set or used. + * + * This function is flexible enough to handle format and channel layout + * changes. In these cases, all planes are reallocated as needed. Unused + * planes are freed. + * + * mp_audio_realloc(mpa, 0) will still yield non-NULL for mpa->data[n]. + * + * Allocated data is implicitly freed on talloc_free(mpa). + */ +void mp_audio_realloc(struct mp_audio *mpa, int samples) +{ + assert(samples >= 0); + int size = MPMAX(samples * mpa->sstride, 1); + for (int n = 0; n < mpa->num_planes; n++) { + if (size != mpa->allocated[n]) { + // Note: av_realloc() can't be used (see libavutil doxygen) + void *new = av_malloc(size); + if (!new) + abort(); + if (mpa->allocated[n]) + memcpy(new, mpa->planes[n], MPMIN(mpa->allocated[n], size)); + av_free(mpa->planes[n]); + mpa->planes[n] = new; + mpa->allocated[n] = size; + } + } + for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) { + av_free(mpa->planes[n]); + mpa->planes[n] = NULL; + mpa->allocated[n] = 0; + } + talloc_set_destructor(mpa, mp_audio_destructor); +} + +// Like mp_audio_realloc(), but only reallocate if the audio grows in size. +void mp_audio_realloc_min(struct mp_audio *mpa, int samples) +{ + if (samples > mp_audio_get_allocated_size(mpa)) + mp_audio_realloc(mpa, samples); +} + +/* Get the size allocated for the data, in number of samples. If the allocated + * size isn't on sample boundaries (e.g. after format changes), the returned + * sample number is a rounded down value. + * + * Note that this only works in situations where mp_audio_realloc() also works! + */ +int mp_audio_get_allocated_size(struct mp_audio *mpa) +{ + int size = 0; + for (int n = 0; n < mpa->num_planes; n++) { + int s = mpa->allocated[n] / mpa->sstride; + size = n == 0 ? s : MPMIN(size, s); + } + return size; +} + +// Clear the samples [start, start + length) with silence. +void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length) +{ + assert(start >= 0 && length >= 0 && start + length <= mpa->samples); + int offset = start * mpa->sstride; + int size = length * mpa->sstride; + for (int n = 0; n < mpa->num_planes; n++) { + if (n > 0 && mpa->planes[n] == mpa->planes[0]) + continue; // silly optimization for special cases + af_fill_silence((char *)mpa->planes[n] + offset, size, mpa->format); + } +} + +// All integer parameters are in samples. +// dst and src can overlap. +void mp_audio_copy(struct mp_audio *dst, int dst_offset, + struct mp_audio *src, int src_offset, int length) +{ + assert(mp_audio_config_equals(dst, src)); + assert(length >= 0); + assert(dst_offset >= 0 && dst_offset + length <= dst->samples); + assert(src_offset >= 0 && src_offset + length <= src->samples); + + for (int n = 0; n < dst->num_planes; n++) { + memmove((char *)dst->planes[n] + dst_offset * dst->sstride, + (char *)src->planes[n] + src_offset * src->sstride, + length * dst->sstride); + } +} + +// Set data to the audio after the given number of samples (i.e. slice it). +void mp_audio_skip_samples(struct mp_audio *data, int samples) +{ + assert(samples >= 0 && samples <= data->samples); + + for (int n = 0; n < data->num_planes; n++) + data->planes[n] = (uint8_t *)data->planes[n] + samples * data->sstride; + + data->samples -= samples; +} diff --git a/audio/audio.h b/audio/audio.h index de35e697c8..54ac2d5aac 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -23,14 +23,22 @@ // Audio data chunk struct mp_audio { - void *audio; // data buffer - int len; // buffer length (in bytes) - int rate; // sample rate + int samples; // number of samples in data (per channel) + void *planes[MP_NUM_CHANNELS]; // data buffer (one per plane) + int rate; // sample rate struct mp_chmap channels; // channel layout, use mp_audio_set_*() to set int format; // format (AF_FORMAT_...), use mp_audio_set_format() to set // Redundant fields, for convenience - int nch; // number of channels (redundant with chmap) - int bps; // bytes per sample (redundant with format) + int sstride; // distance between 2 samples in bytes on a plane + // interleaved: bps * nch + // planar: bps + int nch; // number of channels (redundant with chmap) + int spf; // sub-samples per sample on each plane + int num_planes; // number of planes + int bps; // size of sub-samples (af_fmt2bits(format) / 8) + + // private + int allocated[MP_NUM_CHANNELS]; // use mp_audio_get_allocated_size() }; void mp_audio_set_format(struct mp_audio *mpa, int format); @@ -43,4 +51,20 @@ bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b); char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format); char *mp_audio_config_to_str(struct mp_audio *mpa); +void mp_audio_force_interleaved_format(struct mp_audio *mpa); + +int mp_audio_psize(struct mp_audio *mpa); + +void mp_audio_set_null_data(struct mp_audio *mpa); + +void mp_audio_realloc(struct mp_audio *mpa, int samples); +void mp_audio_realloc_min(struct mp_audio *mpa, int samples); +int mp_audio_get_allocated_size(struct mp_audio *mpa); + +void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length); + +void mp_audio_copy(struct mp_audio *dst, int dst_offset, + struct mp_audio *src, int src_offset, int length); +void mp_audio_skip_samples(struct mp_audio *data, int samples); + #endif diff --git a/audio/audio_buffer.c b/audio/audio_buffer.c new file mode 100644 index 0000000000..53563f90c6 --- /dev/null +++ b/audio/audio_buffer.c @@ -0,0 +1,152 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stddef.h> +#include <limits.h> +#include <assert.h> + +#include "mpvcore/mp_common.h" + +#include "audio_buffer.h" +#include "audio.h" +#include "format.h" + +struct mp_audio_buffer { + struct mp_audio *buffer; +}; + +struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx) +{ + struct mp_audio_buffer *ab = talloc(talloc_ctx, struct mp_audio_buffer); + *ab = (struct mp_audio_buffer) { + .buffer = talloc_zero(ab, struct mp_audio), + }; + return ab; +} + +// Reinitialize the buffer, set a new format, drop old data. +// The audio data in fmt is not used, only the format. +void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt) +{ + mp_audio_copy_config(ab->buffer, fmt); + mp_audio_realloc(ab->buffer, 1); + ab->buffer->samples = 0; +} + +void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format, + const struct mp_chmap *channels, int srate) +{ + struct mp_audio mpa = {0}; + mp_audio_set_format(&mpa, format); + mp_audio_set_channels(&mpa, channels); + mpa.rate = srate; + mp_audio_buffer_reinit(ab, &mpa); +} + +void mp_audio_buffer_get_format(struct mp_audio_buffer *ab, + struct mp_audio *out_fmt) +{ + *out_fmt = (struct mp_audio){0}; + mp_audio_copy_config(out_fmt, ab->buffer); +} + +// Make the total size of the internal buffer at least this number of samples. +void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples) +{ + mp_audio_realloc_min(ab->buffer, samples); +} + +// Get number of samples that can be written without forcing a resize of the +// internal buffer. +int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab) +{ + return mp_audio_get_allocated_size(ab->buffer) - ab->buffer->samples; +} + +// Get a pointer to the end of the buffer (where writing would append). If the +// internal buffer is too small for the given number of samples, it's resized. +// After writing to the buffer, mp_audio_buffer_finish_write() has to be used +// to make the written data part of the readable buffer. +void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int samples, + struct mp_audio *out_buffer) +{ + assert(samples >= 0); + mp_audio_realloc_min(ab->buffer, ab->buffer->samples + samples); + *out_buffer = *ab->buffer; + out_buffer->samples = ab->buffer->samples + samples; + mp_audio_skip_samples(out_buffer, ab->buffer->samples); +} + +void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples) +{ + assert(samples >= 0 && samples <= mp_audio_buffer_get_write_available(ab)); + ab->buffer->samples += samples; +} + +// Append data to the end of the buffer. +// If the buffer is not large enough, it is transparently resized. +// For now always copies the data. +void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa) +{ + int offset = ab->buffer->samples; + ab->buffer->samples += mpa->samples; + mp_audio_realloc_min(ab->buffer, ab->buffer->samples); + mp_audio_copy(ab->buffer, offset, mpa, 0, mpa->samples); +} + +// Prepend silence to the start of the buffer. +void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples) +{ + assert(samples >= 0); + int oldlen = ab->buffer->samples; + ab->buffer->samples += samples; + mp_audio_realloc_min(ab->buffer, ab->buffer->samples); + mp_audio_copy(ab->buffer, samples, ab->buffer, 0, oldlen); + mp_audio_fill_silence(ab->buffer, 0, samples); +} + +// Get the start of the current readable buffer. +void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa) +{ + *out_mpa = *ab->buffer; +} + +// Skip leading samples. (Used with mp_audio_buffer_peek() to read data.) +void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples) +{ + assert(samples >= 0 && samples <= ab->buffer->samples); + mp_audio_copy(ab->buffer, 0, ab->buffer, samples, + ab->buffer->samples - samples); + ab->buffer->samples -= samples; +} + +void mp_audio_buffer_clear(struct mp_audio_buffer *ab) +{ + ab->buffer->samples = 0; +} + +// Return number of buffered audio samples +int mp_audio_buffer_samples(struct mp_audio_buffer *ab) +{ + return ab->buffer->samples; +} + +// Return amount of buffered audio in seconds. +double mp_audio_buffer_seconds(struct mp_audio_buffer *ab) +{ + return ab->buffer->samples / (double)ab->buffer->rate; +} diff --git a/audio/audio_buffer.h b/audio/audio_buffer.h new file mode 100644 index 0000000000..8cd0df30d0 --- /dev/null +++ b/audio/audio_buffer.h @@ -0,0 +1,44 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MP_AUDIO_BUFFER_H +#define MP_AUDIO_BUFFER_H + +struct mp_audio_buffer; +struct mp_audio; +struct mp_chmap; + +struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx); +void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt); +void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format, + const struct mp_chmap *channels, int srate); +void mp_audio_buffer_get_format(struct mp_audio_buffer *ab, + struct mp_audio *out_fmt); +void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples); +int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab); +void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples, + struct mp_audio *out_buffer); +void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples); +void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa); +void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples); +void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa); +void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples); +void mp_audio_buffer_clear(struct mp_audio_buffer *ab); +int mp_audio_buffer_samples(struct mp_audio_buffer *ab); +double mp_audio_buffer_seconds(struct mp_audio_buffer *ab); + +#endif diff --git a/audio/decode/ad.h b/audio/decode/ad.h index 30e739d135..6c76e8dfd0 100644 --- a/audio/decode/ad.h +++ b/audio/decode/ad.h @@ -24,6 +24,7 @@ #include "demux/demux.h" #include "audio/format.h" +#include "audio/audio.h" struct mp_decoder_list; @@ -35,8 +36,7 @@ struct ad_functions { int (*init)(sh_audio_t *sh, const char *decoder); void (*uninit)(sh_audio_t *sh); int (*control)(sh_audio_t *sh, int cmd, void *arg); - int (*decode_audio)(sh_audio_t *sh, unsigned char *buffer, int minlen, - int maxlen); + int (*decode_audio)(sh_audio_t *sh, struct mp_audio *buffer, int maxlen); }; enum ad_ctrl { diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 72bb51e00c..2e0cade8c5 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -36,25 +36,20 @@ #include "mpvcore/av_opts.h" #include "ad.h" -#include "audio/reorder_ch.h" #include "audio/fmt-conversion.h" -#include "compat/mpbswap.h" #include "compat/libav.h" struct priv { AVCodecContext *avctx; AVFrame *avframe; - uint8_t *output; - uint8_t *output_packed; // used by deplanarize to store packed audio samples - int output_left; - int unitsize; + struct mp_audio frame; bool force_channel_map; struct demux_packet *packet; }; static void uninit(sh_audio_t *sh); -static int decode_audio(sh_audio_t *sh,unsigned char *buffer,int minlen,int maxlen); +static int decode_new_packet(struct sh_audio *sh); #define OPT_BASE_STRUCT struct MPOpts @@ -138,22 +133,21 @@ static int preinit(sh_audio_t *sh) return 1; } -/* Prefer playing audio with the samplerate given in container data - * if available, but take number the number of channels and sample format - * from the codec, since if the codec isn't using the correct values for - * those everything breaks anyway. - */ -static int setup_format(sh_audio_t *sh_audio, - const AVCodecContext *lavc_context) +static int setup_format(sh_audio_t *sh_audio) { struct priv *priv = sh_audio->context; - int sample_format = - af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt)); - int samplerate = lavc_context->sample_rate; - // If not set, try container samplerate + AVCodecContext *lavc_context = priv->avctx; + + int sample_format = af_from_avformat(lavc_context->sample_fmt); + if (!sample_format) + return -1; + + int samplerate = lavc_context->sample_rate; if (!samplerate && sh_audio->wf) { + // If not set, try container samplerate. + // (Maybe this can't happen, and it's an artifact from the past.) samplerate = sh_audio->wf->nSamplesPerSec; - mp_tmsg(MSGT_DECAUDIO, MSGL_V, "ad_lavc: using container rate.\n"); + mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "ad_lavc: using container rate.\n"); } struct mp_chmap lavc_chmap; @@ -166,14 +160,9 @@ static int setup_format(sh_audio_t *sh_audio, lavc_chmap = sh_audio->channels; } - if (!mp_chmap_equals(&lavc_chmap, &sh_audio->channels) || - samplerate != sh_audio->samplerate || - sample_format != sh_audio->sample_format) { - sh_audio->channels = lavc_chmap; - sh_audio->samplerate = samplerate; - sh_audio->sample_format = sample_format; - return 1; - } + sh_audio->channels = lavc_chmap; + sh_audio->samplerate = samplerate; + sh_audio->sample_format = sample_format; return 0; } @@ -273,15 +262,12 @@ static int init(sh_audio_t *sh_audio, const char *decoder) mp_msg(MSGT_DECAUDIO, MSGL_V, "INFO: libavcodec \"%s\" init OK!\n", lavc_codec->name); - // Decode at least 1 byte: (to get header filled) - for (int tries = 0;;) { - int x = decode_audio(sh_audio, sh_audio->a_buffer, 1, - sh_audio->a_buffer_size); - if (x > 0) { - sh_audio->a_buffer_len = x; + // Decode at least 1 sample: (to get header filled) + for (int tries = 1; ; tries++) { + int x = decode_new_packet(sh_audio); + if (x >= 0 && ctx->frame.samples > 0) break; - } - if (++tries >= 5) { + if (tries >= 5) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "ad_lavc: initial decode failed\n"); uninit(sh_audio); @@ -293,12 +279,6 @@ static int init(sh_audio_t *sh_audio, const char *decoder) if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec) sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec; - int af_sample_fmt = - af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt)); - if (af_sample_fmt == AF_FORMAT_UNKNOWN) { - uninit(sh_audio); - return 0; - } return 1; } @@ -326,7 +306,7 @@ static int control(sh_audio_t *sh, int cmd, void *arg) switch (cmd) { case ADCTRL_RESYNC_STREAM: avcodec_flush_buffers(ctx->avctx); - ctx->output_left = 0; + ctx->frame.samples = 0; talloc_free(ctx->packet); ctx->packet = NULL; return CONTROL_TRUE; @@ -334,29 +314,13 @@ static int control(sh_audio_t *sh, int cmd, void *arg) return CONTROL_UNKNOWN; } -static av_always_inline void deplanarize(struct sh_audio *sh) -{ - struct priv *priv = sh->context; - - uint8_t **planes = priv->avframe->extended_data; - size_t bps = av_get_bytes_per_sample(priv->avctx->sample_fmt); - size_t nb_samples = priv->avframe->nb_samples; - size_t channels = priv->avctx->channels; - size_t size = bps * nb_samples * channels; - - if (talloc_get_size(priv->output_packed) != size) - priv->output_packed = - talloc_realloc_size(priv, priv->output_packed, size); - - reorder_to_packed(priv->output_packed, planes, bps, channels, nb_samples); - - priv->output = priv->output_packed; -} - static int decode_new_packet(struct sh_audio *sh) { struct priv *priv = sh->context; AVCodecContext *avctx = priv->avctx; + + priv->frame.samples = 0; + struct demux_packet *mpkt = priv->packet; if (!mpkt) mpkt = demux_read_packet(sh->gsh); @@ -372,7 +336,7 @@ static int decode_new_packet(struct sh_audio *sh) if (mpkt->pts != MP_NOPTS_VALUE) { sh->pts = mpkt->pts; - sh->pts_bytes = 0; + sh->pts_offset = 0; } int got_frame = 0; int ret = avcodec_decode_audio4(avctx, priv->avframe, &got_frame, &pkt); @@ -397,58 +361,39 @@ static int decode_new_packet(struct sh_audio *sh) } if (!got_frame) return 0; - uint64_t unitsize = (uint64_t)av_get_bytes_per_sample(avctx->sample_fmt) * - avctx->channels; - if (unitsize > 100000) - abort(); - priv->unitsize = unitsize; - uint64_t output_left = unitsize * priv->avframe->nb_samples; - if (output_left > 500000000) - abort(); - priv->output_left = output_left; - if (av_sample_fmt_is_planar(avctx->sample_fmt) && avctx->channels > 1) { - deplanarize(sh); - } else { - priv->output = priv->avframe->data[0]; - } - mp_dbg(MSGT_DECAUDIO, MSGL_DBG2, "Decoded %d -> %d \n", in_len, - priv->output_left); + + if (setup_format(sh) < 0) + return -1; + + priv->frame.samples = priv->avframe->nb_samples; + mp_audio_set_format(&priv->frame, sh->sample_format); + mp_audio_set_channels(&priv->frame, &sh->channels); + priv->frame.rate = sh->samplerate; + for (int n = 0; n < priv->frame.num_planes; n++) + priv->frame.planes[n] = priv->avframe->data[n]; + + mp_dbg(MSGT_DECAUDIO, MSGL_DBG2, "Decoded %d -> %d samples\n", in_len, + priv->frame.samples); return 0; } - -static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen, - int maxlen) +static int decode_audio(sh_audio_t *sh, struct mp_audio *buffer, int maxlen) { - struct priv *priv = sh_audio->context; - AVCodecContext *avctx = priv->avctx; + struct priv *priv = sh->context; - int len = -1; - while (len < minlen) { - if (!priv->output_left) { - if (decode_new_packet(sh_audio) < 0) - break; - continue; - } - if (setup_format(sh_audio, avctx)) - return len; - int size = (minlen - len + priv->unitsize - 1); - size -= size % priv->unitsize; - size = FFMIN(size, priv->output_left); - if (size > maxlen) - abort(); - memcpy(buf, priv->output, size); - priv->output += size; - priv->output_left -= size; - if (len < 0) - len = size; - else - len += size; - buf += size; - maxlen -= size; - sh_audio->pts_bytes += size; + if (!priv->frame.samples) { + if (decode_new_packet(sh) < 0) + return -1; } - return len; + + if (!mp_audio_config_equals(buffer, &priv->frame)) + return 0; + + buffer->samples = MPMIN(priv->frame.samples, maxlen); + mp_audio_copy(buffer, 0, &priv->frame, 0, buffer->samples); + mp_audio_skip_samples(&priv->frame, buffer->samples); + sh->pts_offset += buffer->samples; + return 0; } static void add_decoders(struct mp_decoder_list *list) diff --git a/audio/decode/ad_mpg123.c b/audio/decode/ad_mpg123.c index 47cb5d2039..322f45826f 100644 --- a/audio/decode/ad_mpg123.c +++ b/audio/decode/ad_mpg123.c @@ -27,38 +27,37 @@ #include "ad.h" #include "mpvcore/mp_msg.h" -/* Reducing the ifdeffery to two main variants: - * 1. most compatible to any libmpg123 version - * 2. fastest variant with recent libmpg123 (>=1.14) - * Running variant 2 on older libmpg123 versions may work in - * principle, but is not supported. - * So, please leave the check for MPG123_API_VERSION there, m-kay? - */ #include <mpg123.h> -/* Enable faster mode of operation with newer libmpg123, avoiding - * unnecessary memcpy() calls. */ -#if (defined MPG123_API_VERSION) && (MPG123_API_VERSION >= 33) -#define AD_MPG123_FRAMEWISE +#if (defined MPG123_API_VERSION) && (MPG123_API_VERSION < 33) +#error "This should not happen" #endif -/* Switch for updating bitrate info of VBR files. Not essential. */ -#define AD_MPG123_MEAN_BITRATE - struct ad_mpg123_context { mpg123_handle *handle; - char new_format; -#ifdef AD_MPG123_MEAN_BITRATE + bool new_format; + int sample_size; + bool need_data; /* Running mean for bit rate, stream length estimation. */ float mean_rate; unsigned int mean_count; /* Time delay for updates. */ short delay; -#endif /* If the stream is actually VBR. */ char vbr; }; +static void uninit(sh_audio_t *sh) +{ + struct ad_mpg123_context *con = (struct ad_mpg123_context*) sh->context; + + mpg123_close(con->handle); + mpg123_delete(con->handle); + talloc_free(sh->context); + sh->context = NULL; + mpg123_exit(); +} + /* This initializes libmpg123 and prepares the handle, including funky * parameters. */ static int preinit(sh_audio_t *sh) @@ -72,7 +71,7 @@ static int preinit(sh_audio_t *sh) if (mpg123_init() != MPG123_OK) return 0; - sh->context = malloc(sizeof(struct ad_mpg123_context)); + sh->context = talloc_zero(NULL, struct ad_mpg123_context); con = sh->context; /* Auto-choice of optimized decoder (first argument NULL). */ con->handle = mpg123_new(NULL, &err); @@ -104,17 +103,15 @@ static int preinit(sh_audio_t *sh) /* Example for RVA choice (available since libmpg123 1.0.0): mpg123_param(con->handle, MPG123_RVA, MPG123_RVA_MIX, 0.0) */ -#ifdef AD_MPG123_FRAMEWISE /* Prevent funky automatic resampling. * This way, we can be sure that one frame will never produce - * more than 1152 stereo samples. */ + * more than 1152 stereo samples. + * Background: + * Going to decode directly to the output buffer. It is important to have + * MPG123_AUTO_RESAMPLE disabled for the buffer size being an all-time + * limit. + * We need at least 1152 samples. dec_audio.c normally guarantees this. */ mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.); -#else - /* Older mpg123 is vulnerable to concatenated streams when gapless cutting - * is enabled (will only play the jingle of a badly constructed radio - * stream). The versions using framewise decoding are fine with that. */ - mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0.); -#endif return 1; @@ -126,77 +123,21 @@ static int preinit(sh_audio_t *sh) mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 preinit error: %s\n", mpg123_strerror(con->handle)); - if (con->handle) - mpg123_delete(con->handle); - mpg123_exit(); - free(sh->context); - sh->context = NULL; + uninit(sh); return 0; } -/* Compute bitrate from frame size. */ -static int compute_bitrate(struct mpg123_frameinfo *i) -{ - static const int samples_per_frame[4][4] = { - {-1, 384, 1152, 1152}, /* MPEG 1 */ - {-1, 384, 1152, 576}, /* MPEG 2 */ - {-1, 384, 1152, 576}, /* MPEG 2.5 */ - {-1, -1, -1, -1}, /* Unknown */ - }; - return (int) ((i->framesize + 4) * 8 * i->rate * 0.001 / - samples_per_frame[i->version][i->layer] + 0.5); -} - -/* Opted against the header printout from old mp3lib, too much - * irrelevant info. This is modelled after the mpg123 app's - * standard output line. - * If more verbosity is demanded, one can add more detail and - * also throw in ID3v2 info which libmpg123 collects anyway. */ -static void print_header_compact(struct mpg123_frameinfo *i) -{ - static const char *smodes[5] = { - "stereo", "joint-stereo", "dual-channel", "mono", "invalid" - }; - static const char *layers[4] = { - "Unknown", "I", "II", "III" - }; - static const char *versions[4] = { - "1.0", "2.0", "2.5", "x.x" - }; - - mp_msg(MSGT_DECAUDIO, MSGL_V, "MPEG %s layer %s, ", - versions[i->version], layers[i->layer]); - switch (i->vbr) { - case MPG123_CBR: - if (i->bitrate) - mp_msg(MSGT_DECAUDIO, MSGL_V, "%d kbit/s", i->bitrate); - else - mp_msg(MSGT_DECAUDIO, MSGL_V, "%d kbit/s (free format)", - compute_bitrate(i)); - break; - case MPG123_VBR: - mp_msg(MSGT_DECAUDIO, MSGL_V, "VBR"); - break; - case MPG123_ABR: - mp_msg(MSGT_DECAUDIO, MSGL_V, "%d kbit/s ABR", i->abr_rate); - break; - default: - mp_msg(MSGT_DECAUDIO, MSGL_V, "???"); - } - mp_msg(MSGT_DECAUDIO, MSGL_V, ", %ld Hz %s\n", i->rate, - smodes[i->mode]); -} - /* libmpg123 has a new format ready; query and store, return return value of mpg123_getformat() */ -static int set_format(sh_audio_t *sh, struct ad_mpg123_context *con) +static int set_format(sh_audio_t *sh) { + struct ad_mpg123_context *con = sh->context; int ret; long rate; int channels; int encoding; ret = mpg123_getformat(con->handle, &rate, &channels, &encoding); - if(ret == MPG123_OK) { + if (ret == MPG123_OK) { mp_chmap_from_channels(&sh->channels, channels); sh->samplerate = rate; /* Without external force, mpg123 will always choose signed encoding, @@ -210,13 +151,10 @@ static int set_format(sh_audio_t *sh, struct ad_mpg123_context *con) case MPG123_ENC_SIGNED_16: sh->sample_format = AF_FORMAT_S16_NE; break; - /* To stay compatible with the oldest libmpg123 headers, do not rely - * on float and 32 bit encoding symbols being defined. - * Those formats came later */ - case 0x1180: /* MPG123_ENC_SIGNED_32 */ + case MPG123_ENC_SIGNED_32: sh->sample_format = AF_FORMAT_S32_NE; break; - case 0x200: /* MPG123_ENC_FLOAT_32 */ + case MPG123_ENC_FLOAT_32: sh->sample_format = AF_FORMAT_FLOAT_NE; break; default: @@ -225,151 +163,38 @@ static int set_format(sh_audio_t *sh, struct ad_mpg123_context *con) "Bad encoding from mpg123: %i.\n", encoding); return MPG123_ERR; } -#ifdef AD_MPG123_FRAMEWISE - /* Going to decode directly to MPlayer's memory. It is important - * to have MPG123_AUTO_RESAMPLE disabled for the buffer size - * being an all-time limit. */ - sh->audio_out_minsize = 1152 * 2 * (af_fmt2bits(sh->sample_format) / 8); -#endif + con->sample_size = channels * (af_fmt2bits(sh->sample_format) / 8); con->new_format = 0; } return ret; } -/* This tries to extract a requested amount of decoded data. - * Even when you request 0 bytes, it will feed enough input so that - * the decoder _could_ have delivered something. - * Returns byte count >= 0, -1 on error. - * - * Thoughts on exact pts keeping: - * We have to assume that MPEG frames are cut in pieces by packet boundaries. - * Also, it might be possible that the first packet does not contain enough - * data to ensure initial stream sync... or re-sync on erroneous streams. - * So we need something robust to relate the decoded byte count to the correct - * time stamp. This is tricky, though. From the outside, you cannot tell if, - * after having fed two packets until the first output arrives, one should - * start counting from the first packet's pts or the second packet's. - * So, let's just count from the last fed package's pts. If the packets are - * exactly cut to MPEG frames, this will cause one frame mismatch in the - * beginning (when mpg123 peeks ahead for the following header), but will - * be corrected with the third frame already. One might add special code to - * not increment the base pts past the first packet's after a resync before - * the first decoded bytes arrived. */ -static int decode_a_bit(sh_audio_t *sh, unsigned char *buf, int count) +static int feed_new_packet(sh_audio_t *sh) { - int ret = MPG123_OK; - int got = 0; struct ad_mpg123_context *con = sh->context; + int ret; - /* There will be one MPG123_NEW_FORMAT message on first open. - * This will be handled in init(). */ - do { - size_t got_now = 0; - /* Fetch new format now, after old data has been used. */ - if(con->new_format) - ret = set_format(sh, con); - - /* Feed the decoder. This will only fire from the second round on. */ - if (ret == MPG123_NEED_MORE) { - /* Feed more input data. */ - struct demux_packet *pkt = demux_read_packet(sh->gsh); - if (!pkt) - break; /* Apparently that's it. EOF. */ - - /* Next bytes from that presentation time. */ - if (pkt->pts != MP_NOPTS_VALUE) { - sh->pts = pkt->pts; - sh->pts_bytes = 0; - } - -#ifdef AD_MPG123_FRAMEWISE - /* Have to use mpg123_feed() to avoid decoding here. */ - ret = mpg123_feed(con->handle, pkt->buffer, pkt->len); -#else - /* Do not use mpg123_feed(), added in later libmpg123 versions. */ - ret = mpg123_decode(con->handle, pkt->buffer, pkt->len, NULL, 0, NULL); -#endif - talloc_free(pkt); - if (ret == MPG123_ERR) - break; - - /* Indication of format change is possible here (from mpg123_decode()). */ - if(ret == MPG123_NEW_FORMAT) { - con->new_format = 1; - if(got) - break; /* Do not switch format during a chunk. */ - - ret = set_format(sh, con); - } - } - /* Theoretically, mpg123 could return MPG123_DONE, so be prepared. - * Should not happen in our usage, but it is a valid return code. */ - else if (ret == MPG123_ERR || ret == MPG123_DONE) - break; - - /* Try to decode a bit. This is the return value that counts - * for the loop condition. */ -#ifdef AD_MPG123_FRAMEWISE - if (!buf) { /* fake call just for feeding to get format */ - ret = set_format(sh, con); - } else { /* This is the decoding. One frame at a time. */ - ret = mpg123_replace_buffer(con->handle, buf, count); - if (ret == MPG123_OK) - ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now); - } -#else - ret = mpg123_decode(con->handle, NULL, 0, buf + got, count - got, - &got_now); -#endif - - got += got_now; - sh->pts_bytes += got_now; - - /* Indication of format change should happen here. */ - if(ret == MPG123_NEW_FORMAT) { - con->new_format = 1; - if(got) - break; /* Do not switch format during a chunk. */ - - ret = set_format(sh, con); - } - -#ifdef AD_MPG123_FRAMEWISE - } while (ret == MPG123_NEED_MORE || (got == 0 && count != 0)); -#else - } while (ret == MPG123_NEED_MORE || got < count); -#endif + struct demux_packet *pkt = demux_read_packet(sh->gsh); + if (!pkt) + return -1; /* EOF. */ - if (ret == MPG123_ERR) { - mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 decoding failed: %s\n", - mpg123_strerror(con->handle)); + /* Next bytes from that presentation time. */ + if (pkt->pts != MP_NOPTS_VALUE) { + sh->pts = pkt->pts; + sh->pts_offset = 0; } - return got; -} + /* Have to use mpg123_feed() to avoid decoding here. */ + ret = mpg123_feed(con->handle, pkt->buffer, pkt->len); + talloc_free(pkt); -/* Close, reopen stream. Feed data until we know the format of the stream. - * 1 on success, 0 on error */ -static int reopen_stream(sh_audio_t *sh) -{ - struct ad_mpg123_context *con = (struct ad_mpg123_context*) sh->context; + if (ret == MPG123_ERR) + return -1; - mpg123_close(con->handle); - /* No resetting of the context: - * We do not want to loose the mean bitrate data. */ - - /* Open and make sure we have fed enough data to get stream properties. */ - if (MPG123_OK == mpg123_open_feed(con->handle) && - /* Feed data until mpg123 is ready (has found stream beginning). */ - !decode_a_bit(sh, NULL, 0) && - set_format(sh, con) == MPG123_OK) { /* format setting again just for return value */ - return 1; - } else { - mp_msg(MSGT_DECAUDIO, MSGL_ERR, - "mpg123 failed to reopen stream: %s\n", - mpg123_strerror(con->handle)); - return 0; - } + if (ret == MPG123_NEW_FORMAT) + con->new_format = 1; + + return 0; } /* Now we really start accessing some data and determining file format. @@ -378,62 +203,72 @@ static int reopen_stream(sh_audio_t *sh) * erros in other places simply cannot occur. */ static int init(sh_audio_t *sh, const char *decoder) { - mpg123_id3v2 *v2; - struct mpg123_frameinfo finfo; struct ad_mpg123_context *con = sh->context; + int ret; - con->new_format = 0; - if (reopen_stream(sh) && - /* Get MPEG header info. */ - MPG123_OK == mpg123_info(con->handle, &finfo) && - /* Since we queried format, mpg123 should have read past ID3v2 tags. - * We need to decide if printing of UTF-8 encoded text info is wanted. */ - MPG123_OK == mpg123_id3(con->handle, NULL, &v2)) { - /* If we are here, we passed all hurdles. Yay! Extract the info. */ - print_header_compact(&finfo); - /* Do we want to print out the UTF-8 Id3v2 info? - if (v2) - print_id3v2(v2); */ - - /* Have kb/s, want B/s - * For VBR, the first frame will be a bad estimate. */ - sh->i_bps = (finfo.bitrate ? finfo.bitrate : compute_bitrate(&finfo)) - * 1000 / 8; -#ifdef AD_MPG123_MEAN_BITRATE - con->delay = 1; - con->mean_rate = 0.; - con->mean_count = 0; -#endif - con->vbr = (finfo.vbr != MPG123_CBR); + ret = mpg123_open_feed(con->handle); + if (ret != MPG123_OK) + goto fail; + + for (int n = 0; ; n++) { + if (feed_new_packet(sh) < 0) { + ret = MPG123_NEED_MORE; + goto fail; + } + size_t got_now = 0; + ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now); + if (ret == MPG123_OK || ret == MPG123_NEW_FORMAT) { + ret = set_format(sh); + if (ret == MPG123_OK) + break; + } + if (ret != MPG123_NEED_MORE) + goto fail; + // max. 16 retries (randomly chosen number) + if (n > 16) { + ret = MPG123_NEED_MORE; + goto fail; + } + } - return 1; + return 1; + +fail: + if (ret == MPG123_NEED_MORE) { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Could not find mp3 stream.\n"); } else { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 init error: %s\n", mpg123_strerror(con->handle)); - return 0; } + + uninit(sh); + return 0; } -static void uninit(sh_audio_t *sh) +/* Compute bitrate from frame size. */ +static int compute_bitrate(struct mpg123_frameinfo *i) { - struct ad_mpg123_context *con = (struct ad_mpg123_context*) sh->context; - - mpg123_close(con->handle); - mpg123_delete(con->handle); - free(sh->context); - sh->context = NULL; - mpg123_exit(); + static const int samples_per_frame[4][4] = { + {-1, 384, 1152, 1152}, /* MPEG 1 */ + {-1, 384, 1152, 576}, /* MPEG 2 */ + {-1, 384, 1152, 576}, /* MPEG 2.5 */ + {-1, -1, -1, -1}, /* Unknown */ + }; + return (int) ((i->framesize + 4) * 8 * i->rate * 0.001 / + samples_per_frame[i->version][i->layer] + 0.5); } -#ifdef AD_MPG123_MEAN_BITRATE /* Update mean bitrate. This could be dropped if accurate time display * on audio file playback is not desired. */ static void update_info(sh_audio_t *sh) { struct ad_mpg123_context *con = sh->context; - if (con->vbr && --con->delay < 1) { - struct mpg123_frameinfo finfo; - if (MPG123_OK == mpg123_info(con->handle, &finfo)) { + struct mpg123_frameinfo finfo; + if (mpg123_info(con->handle, &finfo) != MPG123_OK) + return; + + if (finfo.vbr != MPG123_CBR) { + if (--con->delay < 1) { if (++con->mean_count > ((unsigned int) -1) / 2) con->mean_count = ((unsigned int) -1) / 4; @@ -444,47 +279,80 @@ static void update_info(sh_audio_t *sh) con->delay = 10; } + } else { + sh->i_bps = (finfo.bitrate ? finfo.bitrate : compute_bitrate(&finfo)) + * 1000 / 8; + con->delay = 1; + con->mean_rate = 0.; + con->mean_count = 0; } } -#endif -static int decode_audio(sh_audio_t *sh, unsigned char *buf, int minlen, - int maxlen) +static int decode_audio(sh_audio_t *sh, struct mp_audio *buffer, int maxlen) { - int bytes; + struct ad_mpg123_context *con = sh->context; + void *buf = buffer->planes[0]; + int ret; + + if (con->new_format) { + ret = set_format(sh); + if (ret == MPG123_OK) { + return 0; // let caller handle format change + } else if (ret == MPG123_NEED_MORE) { + con->need_data = true; + } else { + goto mpg123_fail; + } + } + + if (con->need_data) { + if (feed_new_packet(sh) < 0) + return -1; + } - bytes = decode_a_bit(sh, buf, maxlen); - /* This EOF is ignored, apparently, until input data is exhausted. */ - if (bytes == 0) - return -1; /* EOF */ + size_t got_now = 0; + ret = mpg123_replace_buffer(con->handle, buf, maxlen * con->sample_size); + if (ret != MPG123_OK) + goto mpg123_fail; + + ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now); + + int got_samples = got_now / con->sample_size; + buffer->samples += got_samples; + sh->pts_offset += got_samples; + + if (ret == MPG123_NEW_FORMAT) { + con->new_format = true; + } else if (ret == MPG123_NEED_MORE) { + con->need_data = true; + } else if (ret != MPG123_OK && ret != MPG123_DONE) { + goto mpg123_fail; + } -#ifdef AD_MPG123_MEAN_BITRATE update_info(sh); -#endif - return bytes; + return 0; + +mpg123_fail: + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 decoding error: %s\n", + mpg123_strerror(con->handle)); + return -1; } static int control(sh_audio_t *sh, int cmd, void *arg) { + struct ad_mpg123_context *con = sh->context; + switch (cmd) { case ADCTRL_RESYNC_STREAM: - /* Close/reopen the stream for mpg123 to make sure it doesn't - * think that it still knows the exact stream position. - * Otherwise, we would have funny effects from the gapless code. - * Oh, and it helps to minimize artifacts from jumping in the stream. */ - if (reopen_stream(sh)) { -#ifdef AD_MPG123_MEAN_BITRATE - update_info(sh); -#endif - return CONTROL_TRUE; - } else { - /* MPlayer ignores this case! It just keeps on decoding. - * So we have to make sure resync never fails ... */ + mpg123_close(con->handle); + + if (mpg123_open_feed(con->handle) != MPG123_OK) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, - "mpg123 cannot reopen stream for resync.\n"); + "mpg123 failed to reopen stream: %s\n", + mpg123_strerror(con->handle)); return CONTROL_FALSE; } - break; + return CONTROL_TRUE; } return CONTROL_UNKNOWN; } diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index f03041d6a6..a233286c19 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -19,6 +19,7 @@ */ #include <string.h> +#include <assert.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> @@ -184,37 +185,43 @@ fail: return 0; } -static int decode_audio(sh_audio_t *sh, unsigned char *buf, - int minlen, int maxlen) +static int decode_audio(sh_audio_t *sh, struct mp_audio *buffer, int maxlen) { struct spdifContext *spdif_ctx = sh->context; AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx; + int sstride = 2 * sh->channels.num; + assert(sstride == buffer->sstride); + + if (maxlen < spdif_ctx->iec61937_packet_size) + return 0; + spdif_ctx->out_buffer_len = 0; spdif_ctx->out_buffer_size = maxlen; - spdif_ctx->out_buffer = buf; - while (spdif_ctx->out_buffer_len + spdif_ctx->iec61937_packet_size < maxlen - && spdif_ctx->out_buffer_len < minlen) { - struct demux_packet *mpkt = demux_read_packet(sh->gsh); - if (!mpkt) - break; - AVPacket pkt; - mp_set_av_packet(&pkt, mpkt); - pkt.pts = pkt.dts = 0; - mp_msg(MSGT_DECAUDIO, MSGL_V, "spdif packet, size=%d\n", pkt.size); - if (mpkt->pts != MP_NOPTS_VALUE) { - sh->pts = mpkt->pts; - sh->pts_bytes = 0; - } - int out_len = spdif_ctx->out_buffer_len; - int ret = av_write_frame(lavf_ctx, &pkt); - avio_flush(lavf_ctx->pb); - sh->pts_bytes += spdif_ctx->out_buffer_len - out_len; - talloc_free(mpkt); - if (ret < 0) - break; + spdif_ctx->out_buffer = buffer->planes[0]; + + struct demux_packet *mpkt = demux_read_packet(sh->gsh); + if (!mpkt) + return 0; + + AVPacket pkt; + mp_set_av_packet(&pkt, mpkt); + pkt.pts = pkt.dts = 0; + mp_msg(MSGT_DECAUDIO, MSGL_V, "spdif packet, size=%d\n", pkt.size); + if (mpkt->pts != MP_NOPTS_VALUE) { + sh->pts = mpkt->pts; + sh->pts_offset = 0; } - return spdif_ctx->out_buffer_len; + int out_len = spdif_ctx->out_buffer_len; + int ret = av_write_frame(lavf_ctx, &pkt); + avio_flush(lavf_ctx->pb); + sh->pts_offset += (spdif_ctx->out_buffer_len - out_len) / sstride; + talloc_free(mpkt); + if (ret < 0) + return -1; + + buffer->samples = spdif_ctx->out_buffer_len / sstride; + return 0; } static int control(sh_audio_t *sh, int cmd, void *arg) diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index e381a12a3c..19b5d8bdeb 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -38,6 +38,8 @@ #include "dec_audio.h" #include "ad.h" #include "audio/format.h" +#include "audio/audio.h" +#include "audio/audio_buffer.h" #include "audio/filter/af.h" @@ -54,31 +56,29 @@ static const struct ad_functions * const ad_drivers[] = { NULL }; +// At least ad_mpg123 needs to be able to decode this many samples at once +#define DECODE_MAX_UNIT 1152 + +// At least 8192 samples, plus hack for ad_mpg123 +#define DECODE_BUFFER_SAMPLES (8192 + DECODE_MAX_UNIT) + +// Drop audio buffer and reinit it (after format change) +static void reinit_audio_buffer(sh_audio_t *sh) +{ + mp_audio_buffer_reinit_fmt(sh->decode_buffer, sh->sample_format, + &sh->channels, sh->samplerate); + mp_audio_buffer_preallocate_min(sh->decode_buffer, DECODE_BUFFER_SAMPLES); +} + static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder) { assert(!sh_audio->initialized); resync_audio_stream(sh_audio); - sh_audio->sample_format = AF_FORMAT_FLOAT_NE; - sh_audio->audio_out_minsize = 8192; // default, preinit() may change it if (!sh_audio->ad_driver->preinit(sh_audio)) { mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder preinit failed.\n"); return 0; } - const int base_size = 65536; - // At least 64 KiB plus rounding up to next decodable unit size - sh_audio->a_buffer_size = base_size + sh_audio->audio_out_minsize; - - mp_tmsg(MSGT_DECAUDIO, MSGL_V, - "dec_audio: Allocating %d + %d = %d bytes for output buffer.\n", - sh_audio->audio_out_minsize, base_size, - sh_audio->a_buffer_size); - - sh_audio->a_buffer = av_mallocz(sh_audio->a_buffer_size); - if (!sh_audio->a_buffer) - abort(); - sh_audio->a_buffer_len = 0; - if (!sh_audio->ad_driver->init(sh_audio, decoder)) { mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Audio decoder init failed.\n"); uninit_audio(sh_audio); // free buffers @@ -87,13 +87,18 @@ static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder) sh_audio->initialized = 1; - if (mp_chmap_is_empty(&sh_audio->channels) || !sh_audio->samplerate) { + if (mp_chmap_is_empty(&sh_audio->channels) || !sh_audio->samplerate || + !sh_audio->sample_format) + { mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify " "audio format!\n"); uninit_audio(sh_audio); // free buffers return 0; } + sh_audio->decode_buffer = mp_audio_buffer_create(NULL); + reinit_audio_buffer(sh_audio); + return 1; } @@ -187,7 +192,8 @@ void uninit_audio(sh_audio_t *sh_audio) } talloc_free(sh_audio->gsh->decoder_desc); sh_audio->gsh->decoder_desc = NULL; - av_freep(&sh_audio->a_buffer); + talloc_free(sh_audio->decode_buffer); + sh_audio->decode_buffer = NULL; } @@ -230,102 +236,91 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate, return 1; } -static void set_min_out_buffer_size(struct bstr *outbuf, int len) -{ - size_t oldlen = talloc_get_size(outbuf->start); - if (oldlen < len) { - assert(outbuf->start); // talloc context should be already set - mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size " - "from %zd to %d\n", oldlen, len); - outbuf->start = talloc_realloc_size(NULL, outbuf->start, len); - } -} - -static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) +// Filter len bytes of input, put result into outbuf. +static int filter_n_bytes(sh_audio_t *sh, struct mp_audio_buffer *outbuf, + int len) { - assert(len - 1 + sh->audio_out_minsize <= sh->a_buffer_size); - int error = 0; - // Decode more bytes if needed - int old_samplerate = sh->samplerate; - struct mp_chmap old_channels = sh->channels; - int old_sample_format = sh->sample_format; - while (sh->a_buffer_len < len) { - unsigned char *buf = sh->a_buffer + sh->a_buffer_len; - int minlen = len - sh->a_buffer_len; - int maxlen = sh->a_buffer_size - sh->a_buffer_len; - int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen); - int format_change = sh->samplerate != old_samplerate - || !mp_chmap_equals(&sh->channels, &old_channels) - || sh->sample_format != old_sample_format; - if (ret <= 0 || format_change) { - error = format_change ? -2 : -1; - // samples from format-changing call get discarded too - len = sh->a_buffer_len; + struct mp_audio config; + mp_audio_buffer_get_format(sh->decode_buffer, &config); + + while (mp_audio_buffer_samples(sh->decode_buffer) < len) { + int maxlen = mp_audio_buffer_get_write_available(sh->decode_buffer); + if (maxlen < DECODE_MAX_UNIT) + break; + struct mp_audio buffer; + mp_audio_buffer_get_write_buffer(sh->decode_buffer, maxlen, &buffer); + buffer.samples = 0; + error = sh->ad_driver->decode_audio(sh, &buffer, maxlen); + if (error < 0) + break; + // Commit the data just read as valid data + mp_audio_buffer_finish_write(sh->decode_buffer, buffer.samples); + // Format change + if (sh->samplerate != config.rate || + !mp_chmap_equals(&sh->channels, &config.channels) || + sh->sample_format != config.format) + { + // If there are still samples left in the buffer, let them drain + // first, and don't signal a format change to the caller yet. + if (mp_audio_buffer_samples(sh->decode_buffer) > 0) + break; + reinit_audio_buffer(sh); + error = -2; break; } - sh->a_buffer_len += ret; } // Filter - struct mp_audio filter_input = { - .audio = sh->a_buffer, - .len = len, - .rate = sh->samplerate, - }; - mp_audio_set_format(&filter_input, sh->sample_format); - mp_audio_set_channels(&filter_input, &sh->channels); + struct mp_audio filter_input; + mp_audio_buffer_peek(sh->decode_buffer, &filter_input); + filter_input.rate = sh->afilter->input.rate; // due to playback speed change + len = MPMIN(filter_input.samples, len); + filter_input.samples = len; struct mp_audio *filter_output = af_play(sh->afilter, &filter_input); if (!filter_output) return -1; - set_min_out_buffer_size(outbuf, outbuf->len + filter_output->len); - memcpy(outbuf->start + outbuf->len, filter_output->audio, - filter_output->len); - outbuf->len += filter_output->len; + mp_audio_buffer_append(outbuf, filter_output); // remove processed data from decoder buffer: - sh->a_buffer_len -= len; - memmove(sh->a_buffer, sh->a_buffer + len, sh->a_buffer_len); + mp_audio_buffer_skip(sh->decode_buffer, len); return error; } -/* Try to get at least minlen decoded+filtered bytes in outbuf +/* Try to get at least minsamples decoded+filtered samples in outbuf * (total length including possible existing data). * Return 0 on success, -1 on error/EOF (not distinguished). - * In the former case outbuf->len is always >= minlen on return. - * In case of EOF/error it might or might not be. - * Outbuf.start must be talloc-allocated, and will be reallocated - * if needed to fit all filter output. */ -int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen) + * In the former case outbuf has at least minsamples buffered on return. + * In case of EOF/error it might or might not be. */ +int decode_audio(sh_audio_t *sh_audio, struct mp_audio_buffer *outbuf, + int minsamples) { // Indicates that a filter seems to be buffering large amounts of data int huge_filter_buffer = 0; - // Decoded audio must be cut at boundaries of this many bytes - int bps = af_fmt2bits(sh_audio->sample_format) / 8; - int unitsize = sh_audio->channels.num * bps * 16; + // Decoded audio must be cut at boundaries of this many samples + // (Note: the reason for this is unknown, possibly a refactoring artifact) + int unitsize = 16; /* 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(sh_audio->afilter); - /* If the decoder set audio_out_minsize then it can do the equivalent of - * "while (output_len < target_len) output_len += audio_out_minsize;", - * so we must guarantee there is at least audio_out_minsize-1 bytes - * more space in the output buffer than the minimum length we try to - * decode. */ - int max_decode_len = sh_audio->a_buffer_size - sh_audio->audio_out_minsize; - if (!unitsize) - return -1; - max_decode_len -= max_decode_len % unitsize; + int prev_buffered = -1; + while (minsamples >= 0) { + int buffered = mp_audio_buffer_samples(outbuf); + if (minsamples < buffered || buffered == prev_buffered) + break; + prev_buffered = buffered; - while (minlen >= 0 && outbuf->len < minlen) { + int decsamples = (minsamples - buffered) / filter_multiplier; // + some extra for possible filter buffering - int declen = (minlen - outbuf->len) / filter_multiplier + (unitsize << 5); - if (huge_filter_buffer) + decsamples += 1 << unitsize; + + 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 2k bytes at a time until we have enough output. @@ -334,33 +329,24 @@ int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen) * 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. */ - declen = 2000; - declen -= declen % unitsize; - if (declen > max_decode_len) - declen = max_decode_len; - else - /* if this iteration does not fill buffer, we must have lots - * of buffering in filters */ - huge_filter_buffer = 1; - int res = filter_n_bytes(sh_audio, outbuf, declen); + decsamples = 2000; + } + + /* if this iteration does not fill buffer, we must have lots + * of buffering in filters */ + huge_filter_buffer = 1; + + int res = filter_n_bytes(sh_audio, outbuf, decsamples); if (res < 0) return res; } return 0; } -void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte) -{ - set_min_out_buffer_size(outbuf, outbuf->len + count); - memmove(outbuf->start + count, outbuf->start, outbuf->len); - memset(outbuf->start, byte, count); - outbuf->len += count; -} - - void resync_audio_stream(sh_audio_t *sh_audio) { sh_audio->pts = MP_NOPTS_VALUE; + sh_audio->pts_offset = 0; if (!sh_audio->initialized) return; sh_audio->ad_driver->control(sh_audio, ADCTRL_RESYNC_STREAM, NULL); diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h index b46f4282fb..3ec5954471 100644 --- a/audio/decode/dec_audio.h +++ b/audio/decode/dec_audio.h @@ -22,15 +22,14 @@ #include "audio/chmap.h" #include "demux/stheader.h" -struct bstr; +struct mp_audio_buffer; struct mp_decoder_list; struct mp_decoder_list *mp_audio_decoder_list(void); int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders); -int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen); -void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte); +int decode_audio(sh_audio_t *sh_audio, struct mp_audio_buffer *outbuf, + int minsamples); void resync_audio_stream(sh_audio_t *sh_audio); -void skip_audio_frame(sh_audio_t *sh_audio); void uninit_audio(sh_audio_t *sh_audio); int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate, diff --git a/audio/filter/af.c b/audio/filter/af.c index edee4bef65..63013e81d9 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -201,6 +201,7 @@ static struct af_instance *af_create(struct af_stream *s, char *name, *af = (struct af_instance) { .info = info, .mul = 1, + .data = talloc_zero(af, struct mp_audio), }; struct m_config *config = m_config_from_obj_desc(af, &desc); if (m_config_initialize_obj(config, &desc, &af->priv, &args) < 0) @@ -523,8 +524,7 @@ static int af_reinit(struct af_stream *s) // Check if this is the first filter struct mp_audio in = *af->prev->data; // Reset just in case... - in.audio = NULL; - in.len = 0; + mp_audio_set_null_data(&in); int rv = af->control(af, AF_CONTROL_REINIT, &in); if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data)) @@ -640,8 +640,8 @@ int af_init(struct af_stream *s) return -1; // Precaution in case caller is misbehaving - s->input.audio = s->output.audio = NULL; - s->input.len = s->output.len = 0; + mp_audio_set_null_data(&s->input); + mp_audio_set_null_data(&s->output); // Check if this is the first call if (s->first->next == s->last) { @@ -703,12 +703,12 @@ struct mp_audio *af_play(struct af_stream *s, struct mp_audio *data) return data; } -// Calculate average ratio of filter output size to input size +// Calculate average ratio of filter output samples to input samples. +// e.g: num_output_samples = mul * num_input_samples double af_calc_filter_multiplier(struct af_stream *s) { struct af_instance *af = s->first; double mul = 1; - // Iterate through all filters and calculate total multiplication factor do { mul *= af->mul; af = af->next; @@ -721,49 +721,14 @@ double af_calc_filter_multiplier(struct af_stream *s) double af_calc_delay(struct af_stream *s) { struct af_instance *af = s->first; - register double delay = 0.0; - // Iterate through all filters + double delay = 0.0; while (af) { delay += af->delay; - delay *= af->mul; af = af->next; } return delay; } -/* Calculate the minimum output buffer size for given input data d - * when using the af_resize_local_buffer function. The +t+1 part ensures the - * value is >= len*mul rounded upwards to whole samples even if the - * double 'mul' is inexact. */ -static int af_lencalc(double mul, struct mp_audio *d) -{ - int t = d->bps * d->nch; - return d->len * mul + t + 1; -} - -/* I a local buffer is used (i.e. if the filter doesn't operate on the incoming - * buffer), this macro must be called to ensure the buffer is big enough. */ -int af_resize_local_buffer(struct af_instance *af, struct mp_audio *data) -{ - if (af->data->len >= af_lencalc(af->mul, data)) - return AF_OK; - - // Calculate new length - register int len = af_lencalc(af->mul, data); - mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, " - "old len = %i, new len = %i\n", af->info->name, af->data->len, len); - // If there is a buffer free it - free(af->data->audio); - // Create new buffer and check that it is OK - af->data->audio = malloc(len); - if (!af->data->audio) { - mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n"); - return AF_ERROR; - } - af->data->len = len; - return AF_OK; -} - // documentation in af.h struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg) { diff --git a/audio/filter/af.h b/audio/filter/af.h index 3cfdee85dd..7852fa09a6 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -61,13 +61,14 @@ struct af_instance { struct mp_audio * (*play)(struct af_instance *af, struct mp_audio *data); void *setup; // old field for priv structs void *priv; - struct mp_audio *data; // configuration for outgoing data stream + struct mp_audio *data; // configuration and buffer for outgoing data stream struct af_instance *next; struct af_instance *prev; - double delay; /* Delay caused by the filter, in units of bytes read without - * corresponding output */ + double delay; /* Delay caused by the filter, in seconds of audio consumed + * without corresponding output */ double mul; /* length multiplier: how much does this instance change - the length of the buffer. */ + * the number of samples passed though. (Ratio of input + * and output, e.g. mul=4 => 1 sample becomes 4 samples) .*/ bool auto_inserted; // inserted by af.c, such as conversion filters }; @@ -182,10 +183,6 @@ double af_calc_delay(struct af_stream *s); * \{ */ -int af_resize_local_buffer(struct af_instance *af, struct mp_audio *data); - -#define RESIZE_LOCAL_BUFFER af_resize_local_buffer - /** * \brief convert dB to gain value * \param n number of values to convert diff --git a/audio/filter/af_bs2b.c b/audio/filter/af_bs2b.c index 0e77b3e4eb..769a2b4577 100644 --- a/audio/filter/af_bs2b.c +++ b/audio/filter/af_bs2b.c @@ -42,7 +42,7 @@ static struct mp_audio *play_##name(struct af_instance *af, struct mp_audio *dat { \ /* filter is called for all pairs of samples available in the buffer */ \ bs2b_cross_feed_##name(((struct af_bs2b*)(af->priv))->filter, \ - (type*)(data->audio), data->len/data->bps/2); \ + (type*)(data->planes[0]), data->samples); \ \ return data; \ } @@ -161,7 +161,6 @@ static int control(struct af_instance *af, int cmd, void *arg) static void uninit(struct af_instance *af) { struct af_bs2b *s = af->priv; - free(af->data); if (s->filter) bs2b_close(s->filter); } @@ -172,13 +171,9 @@ static int af_open(struct af_instance *af) struct af_bs2b *s = af->priv; af->control = control; af->uninit = uninit; - af->mul = 1; - if (!(af->data = calloc(1, sizeof(struct mp_audio)))) - return AF_ERROR; // NULL means failed initialization if (!(s->filter = bs2b_open())) { - free(af->data); return AF_ERROR; } diff --git a/audio/filter/af_center.c b/audio/filter/af_center.c index 0cfdbc3b0e..ed482c7a6b 100644 --- a/audio/filter/af_center.c +++ b/audio/filter/af_center.c @@ -78,7 +78,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } @@ -87,9 +86,9 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) { struct mp_audio* c = data; // Current working data af_center_t* s = af->setup; // Setup for this instance - float* a = c->audio; // Audio data - int len = c->len/4; // Number of samples in current audio block + float* a = c->planes[0]; // Audio data int nch = c->nch; // Number of channels + int len = c->samples*c->nch; // Number of samples in current audio block int ch = s->ch; // Channel in which to insert the center audio register int i; @@ -108,10 +107,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=s=calloc(1,sizeof(af_center_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; // Set default values s->ch = 1; // Channel nr 2 diff --git a/audio/filter/af_channels.c b/audio/filter/af_channels.c index 27445aafe2..f77807a1af 100644 --- a/audio/filter/af_channels.c +++ b/audio/filter/af_channels.c @@ -168,7 +168,10 @@ static int control(struct af_instance* af, int cmd, void* arg) af->data->rate = ((struct mp_audio*)arg)->rate; mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format); - af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch; + mp_audio_force_interleaved_format(af->data); + int r = af_test_output(af,(struct mp_audio*)arg); + if (r != AF_OK) + return r; return check_routes(s,((struct mp_audio*)arg)->nch,af->data->nch); case AF_CONTROL_COMMAND_LINE:{ int nch = 0; @@ -218,9 +221,6 @@ static int control(struct af_instance* af, int cmd, void* arg) static void uninit(struct af_instance* af) { free(af->setup); - if (af->data) - free(af->data->audio); - free(af->data); } // Filter data through filter @@ -231,20 +231,19 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) af_channels_t* s = af->setup; int i; - if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) - return NULL; + mp_audio_realloc_min(af->data, data->samples); // Reset unused channels - memset(l->audio,0,c->len / c->nch * l->nch); + memset(l->planes[0],0,mp_audio_psize(c) / c->nch * l->nch); if(AF_OK == check_routes(s,c->nch,l->nch)) for(i=0;i<s->nr;i++) - copy(c->audio,l->audio,c->nch,s->route[i][FR], - l->nch,s->route[i][TO],c->len,c->bps); + copy(c->planes[0],l->planes[0],c->nch,s->route[i][FR], + l->nch,s->route[i][TO],mp_audio_psize(c),c->bps); // Set output data - c->audio = l->audio; - c->len = c->len / c->nch * l->nch; + c->planes[0] = l->planes[0]; + c->samples = c->samples / c->nch * l->nch; mp_audio_set_channels(c, &l->channels); return c; @@ -255,10 +254,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_channels_t)); - if((af->data == NULL) || (af->setup == NULL)) + if(af->setup == NULL) return AF_ERROR; return AF_OK; } diff --git a/audio/filter/af_convert24.c b/audio/filter/af_convert24.c index 18ce156467..ee8aff5afc 100644 --- a/audio/filter/af_convert24.c +++ b/audio/filter/af_convert24.c @@ -53,8 +53,6 @@ static int control(struct af_instance *af, int cmd, void *arg) assert(test_conversion(in->format, out->format)); - af->mul = (double)out->bps / in->bps; - return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; } case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET: { @@ -74,16 +72,15 @@ static int control(struct af_instance *af, int cmd, void *arg) static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) { - if (RESIZE_LOCAL_BUFFER(af, data) != AF_OK) - return NULL; + mp_audio_realloc_min(af->data, data->samples); struct mp_audio *out = af->data; - size_t len = data->len / data->bps; + size_t len = mp_audio_psize(data) / data->bps; if (data->bps == 4) { for (int s = 0; s < len; s++) { - uint32_t val = *((uint32_t *)data->audio + s); - uint8_t *ptr = (uint8_t *)out->audio + s * 3; + uint32_t val = *((uint32_t *)data->planes[0] + s); + uint8_t *ptr = (uint8_t *)out->planes[0] + s * 3; ptr[0] = val >> SHIFT(0); ptr[1] = val >> SHIFT(1); ptr[2] = val >> SHIFT(2); @@ -91,32 +88,23 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) mp_audio_set_format(data, af_fmt_change_bits(data->format, 24)); } else { for (int s = 0; s < len; s++) { - uint8_t *ptr = (uint8_t *)data->audio + s * 3; + uint8_t *ptr = (uint8_t *)data->planes[0] + s * 3; uint32_t val = ptr[0] << SHIFT(0) | ptr[1] << SHIFT(1) | ptr[2] << SHIFT(2); - *((uint32_t *)out->audio + s) = val; + *((uint32_t *)out->planes[0] + s) = val; } mp_audio_set_format(data, af_fmt_change_bits(data->format, 32)); } - data->audio = out->audio; - data->len = len * data->bps; + data->planes[0] = out->planes[0]; return data; } -static void uninit(struct af_instance* af) -{ - if (af->data) - free(af->data->audio); -} - static int af_open(struct af_instance *af) { af->control = control; af->play = play; - af->uninit = uninit; - af->data = talloc_zero(af, struct mp_audio); return AF_OK; } diff --git a/audio/filter/af_convertsignendian.c b/audio/filter/af_convertsignendian.c index bfea004bb2..65fffdf487 100644 --- a/audio/filter/af_convertsignendian.c +++ b/audio/filter/af_convertsignendian.c @@ -24,6 +24,9 @@ static bool test_conversion(int src_format, int dst_format) { + if ((src_format & AF_FORMAT_PLANAR) || + (dst_format & AF_FORMAT_PLANAR)) + return false; int src_noend = src_format & ~AF_FORMAT_END_MASK; int dst_noend = dst_format & ~AF_FORMAT_END_MASK; // We can swap endian for all formats, but sign only for integer formats. @@ -100,13 +103,13 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) { int infmt = data->format; int outfmt = af->data->format; - size_t len = data->len / data->bps; + size_t len = data->samples * data->nch; if ((infmt & AF_FORMAT_END_MASK) != (outfmt & AF_FORMAT_END_MASK)) - endian(data->audio, len, data->bps); + endian(data->planes[0], len, data->bps); if ((infmt & AF_FORMAT_SIGN_MASK) != (outfmt & AF_FORMAT_SIGN_MASK)) - si2us(data->audio, len, data->bps, + si2us(data->planes[0], len, data->bps, (outfmt & AF_FORMAT_END_MASK) == AF_FORMAT_LE); mp_audio_set_format(data, outfmt); @@ -117,8 +120,6 @@ static int af_open(struct af_instance *af) { af->control = control; af->play = play; - af->mul = 1; - af->data = talloc_zero(af, struct mp_audio); return AF_OK; } diff --git a/audio/filter/af_delay.c b/audio/filter/af_delay.c index a6515f84cf..e2ef57221d 100644 --- a/audio/filter/af_delay.c +++ b/audio/filter/af_delay.c @@ -56,6 +56,7 @@ static int control(struct af_instance* af, int cmd, void* arg) free(s->q[i]); mp_audio_copy_config(af->data, (struct mp_audio*)arg); + mp_audio_force_interleaved_format(af->data); // Allocate new delay queues for(i=0;i<af->data->nch;i++){ @@ -111,7 +112,6 @@ static void uninit(struct af_instance* af) { int i; - free(af->data); for(i=0;i<AF_NCH;i++) free(((af_delay_t*)(af->setup))->q[i]); free(af->setup); @@ -123,13 +123,13 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) struct mp_audio* c = data; // Current working data af_delay_t* s = af->setup; // Setup for this instance int nch = c->nch; // Number of channels - int len = c->len/c->bps; // Number of sample in data chunk + int len = mp_audio_psize(c)/c->bps; // Number of sample in data chunk int ri = 0; int ch,i; for(ch=0;ch<nch;ch++){ switch(c->bps){ case 1:{ - int8_t* a = c->audio; + int8_t* a = c->planes[0]; int8_t* q = s->q[ch]; int wi = s->wi[ch]; ri = s->ri; @@ -143,7 +143,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) break; } case 2:{ - int16_t* a = c->audio; + int16_t* a = c->planes[0]; int16_t* q = s->q[ch]; int wi = s->wi[ch]; ri = s->ri; @@ -157,7 +157,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) break; } case 4:{ - int32_t* a = c->audio; + int32_t* a = c->planes[0]; int32_t* q = s->q[ch]; int wi = s->wi[ch]; ri = s->ri; @@ -181,10 +181,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_delay_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; return AF_OK; } diff --git a/audio/filter/af_drc.c b/audio/filter/af_drc.c index 9bbbde4831..17c4a12a95 100644 --- a/audio/filter/af_drc.c +++ b/audio/filter/af_drc.c @@ -88,6 +88,7 @@ static int control(struct af_instance* af, int cmd, void* arg) // Sanity check if(!arg) return AF_ERROR; + mp_audio_force_interleaved_format((struct mp_audio*)arg); mp_audio_copy_config(af->data, (struct mp_audio*)arg); if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16_NE)){ @@ -112,15 +113,14 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } static void method1_int16(af_drc_t *s, struct mp_audio *c) { register int i = 0; - int16_t *data = (int16_t*)c->audio; // Audio data - int len = c->len/2; // Number of samples + int16_t *data = (int16_t*)c->planes[0]; // Audio data + int len = c->samples*c->nch; // Number of samples float curavg = 0.0, newavg, neededmul; int tmp; @@ -161,8 +161,8 @@ static void method1_int16(af_drc_t *s, struct mp_audio *c) static void method1_float(af_drc_t *s, struct mp_audio *c) { register int i = 0; - float *data = (float*)c->audio; // Audio data - int len = c->len/4; // Number of samples + float *data = (float*)c->planes[0]; // Audio data + int len = c->samples*c->nch; // Number of samples float curavg = 0.0, newavg, neededmul, tmp; for (i = 0; i < len; i++) @@ -198,8 +198,8 @@ static void method1_float(af_drc_t *s, struct mp_audio *c) static void method2_int16(af_drc_t *s, struct mp_audio *c) { register int i = 0; - int16_t *data = (int16_t*)c->audio; // Audio data - int len = c->len/2; // Number of samples + int16_t *data = (int16_t*)c->planes[0]; // Audio data + int len = c->samples*c->nch; // Number of samples float curavg = 0.0, newavg, avg = 0.0; int tmp, totallen = 0; @@ -248,8 +248,8 @@ static void method2_int16(af_drc_t *s, struct mp_audio *c) static void method2_float(af_drc_t *s, struct mp_audio *c) { register int i = 0; - float *data = (float*)c->audio; // Audio data - int len = c->len/4; // Number of samples + float *data = (float*)c->planes[0]; // Audio data + int len = c->samples*c->nch; // Number of samples float curavg = 0.0, newavg, avg = 0.0, tmp; int totallen = 0; @@ -319,10 +319,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_drc_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; ((af_drc_t*)af->setup)->mul = MUL_INIT; diff --git a/audio/filter/af_dummy.c b/audio/filter/af_dummy.c index ab601ba9bb..d1cb054413 100644 --- a/audio/filter/af_dummy.c +++ b/audio/filter/af_dummy.c @@ -40,12 +40,6 @@ static int control(struct af_instance* af, int cmd, void* arg) return AF_UNKNOWN; } -// Deallocate memory -static void uninit(struct af_instance* af) -{ - free(af->data); -} - // Filter data through filter static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) { @@ -58,12 +52,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) // Allocate memory and set function pointers static int af_open(struct af_instance* af){ af->control=control; - af->uninit=uninit; af->play=play; - af->mul=1; - af->data=malloc(sizeof(struct mp_audio)); - if(af->data == NULL) - return AF_ERROR; return AF_OK; } diff --git a/audio/filter/af_equalizer.c b/audio/filter/af_equalizer.c index cbdcd3f84a..75a489d867 100644 --- a/audio/filter/af_equalizer.c +++ b/audio/filter/af_equalizer.c @@ -114,7 +114,7 @@ static int control(struct af_instance* af, int cmd, void* arg) bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q); // Calculate how much this plugin adds to the overall time delay - af->delay = 2 * af->data->nch * af->data->bps; + af->delay = 2.0 / (double)af->data->rate; // Calculate gain factor to prevent clipping at output for(k=0;k<AF_NCH;k++) @@ -156,7 +156,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } @@ -170,9 +169,9 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) while(ci--){ float* g = s->g[ci]; // Gain factor - float* in = ((float*)c->audio)+ci; - float* out = ((float*)c->audio)+ci; - float* end = in + c->len/4; // Block loop end + float* in = ((float*)c->planes[0])+ci; + float* out = ((float*)c->planes[0])+ci; + float* end = in + c->samples*c->nch; // Block loop end while(in < end){ register int k = 0; // Frequency band index @@ -204,10 +203,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_equalizer_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; return AF_OK; } diff --git a/audio/filter/af_export.c b/audio/filter/af_export.c index 45143075a1..5e1096f85a 100644 --- a/audio/filter/af_export.c +++ b/audio/filter/af_export.c @@ -183,9 +183,6 @@ static int control(struct af_instance* af, int cmd, void* arg) */ static void uninit( struct af_instance* af ) { - free(af->data); - af->data = NULL; - if(af->setup){ af_export_t* s = af->setup; if (s->buf) @@ -213,9 +210,9 @@ static struct mp_audio* play( struct af_instance* af, struct mp_audio* data ) { struct mp_audio* c = data; // Current working data af_export_t* s = af->setup; // Setup for this instance - int16_t* a = c->audio; // Incomming sound + int16_t* a = c->planes[0]; // Incomming sound int nch = c->nch; // Number of channels - int len = c->len/c->bps; // Number of sample in data chunk + int len = c->samples*c->nch; // Number of sample in data chunk int sz = s->sz; // buffer size (in samples) int flag = 0; // Set to 1 if buffer is filled @@ -259,10 +256,8 @@ static int af_open( struct af_instance* af ) af->control = control; af->uninit = uninit; af->play = play; - af->mul=1; - af->data = calloc(1, sizeof(struct mp_audio)); af->setup = calloc(1, sizeof(af_export_t)); - if((af->data == NULL) || (af->setup == NULL)) + if(af->setup == NULL) return AF_ERROR; ((af_export_t *)af->setup)->filename = mp_find_user_config_file(SHARED_FILE); diff --git a/audio/filter/af_extrastereo.c b/audio/filter/af_extrastereo.c index 4cf27f2724..4561b60690 100644 --- a/audio/filter/af_extrastereo.c +++ b/audio/filter/af_extrastereo.c @@ -49,6 +49,7 @@ static int control(struct af_instance* af, int cmd, void* arg) if(!arg) return AF_ERROR; mp_audio_copy_config(af->data, (struct mp_audio*)arg); + mp_audio_force_interleaved_format(af->data); mp_audio_set_num_channels(af->data, 2); if (af->data->format == AF_FORMAT_FLOAT_NE) { @@ -74,7 +75,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } @@ -83,8 +83,8 @@ static struct mp_audio* play_s16(struct af_instance* af, struct mp_audio* data) { af_extrastereo_t *s = af->setup; register int i = 0; - int16_t *a = (int16_t*)data->audio; // Audio data - int len = data->len/2; // Number of samples + int16_t *a = (int16_t*)data->planes[0]; // Audio data + int len = data->samples*data->nch; // Number of samples int avg, l, r; for (i = 0; i < len; i+=2) @@ -105,8 +105,8 @@ static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data { af_extrastereo_t *s = af->setup; register int i = 0; - float *a = (float*)data->audio; // Audio data - int len = data->len/4; // Number of samples + float *a = (float*)data->planes[0]; // Audio data + int len = data->samples * data->nch; // Number of samples float avg, l, r; for (i = 0; i < len; i+=2) @@ -128,10 +128,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play_s16; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_extrastereo_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; ((af_extrastereo_t*)af->setup)->mul = 2.5; diff --git a/audio/filter/af_format.c b/audio/filter/af_format.c index 642ef927bb..5b941951cb 100644 --- a/audio/filter/af_format.c +++ b/audio/filter/af_format.c @@ -35,9 +35,6 @@ struct priv { struct mp_chmap out_channels; int fail; - - struct mp_audio data; - struct mp_audio temp; }; static void force_in_params(struct af_instance *af, struct mp_audio *in) @@ -101,23 +98,14 @@ static int control(struct af_instance *af, int cmd, void *arg) static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) { - struct priv *priv = af->priv; - struct mp_audio *r = &priv->temp; - - *r = *af->data; - r->audio = data->audio; - r->len = data->len; - - return r; + mp_audio_copy_config(data, af->data); + return data; } static int af_open(struct af_instance *af) { af->control = control; af->play = play; - af->mul = 1; - struct priv *priv = af->priv; - af->data = &priv->data; force_in_params(af, af->data); force_out_params(af, af->data); diff --git a/audio/filter/af_hrtf.c b/audio/filter/af_hrtf.c index 5b80bf0eec..ed51351750 100644 --- a/audio/filter/af_hrtf.c +++ b/audio/filter/af_hrtf.c @@ -313,7 +313,6 @@ static int control(struct af_instance *af, int cmd, void* arg) mp_audio_set_channels_old(af->data, 5); mp_audio_set_format(af->data, AF_FORMAT_S16_NE); test_output_res = af_test_output(af, (struct mp_audio*)arg); - af->mul = 2.0 / af->data->nch; // after testing input set the real output format mp_audio_set_num_channels(af->data, 2); s->print_flag = 1; @@ -366,9 +365,6 @@ static void uninit(struct af_instance *af) free(s->fwrbuf_rr); free(af->setup); } - if(af->data) - free(af->data->audio); - free(af->data); } /* Filter data through filter @@ -385,14 +381,13 @@ damped (without any real 3D acoustical image, however). static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) { af_hrtf_t *s = af->setup; - short *in = data->audio; // Input audio data + short *in = data->planes[0]; // Input audio data short *out = NULL; // Output audio data - short *end = in + data->len / sizeof(short); // Loop end + short *end = in + data->samples * data->nch; // Loop end float common, left, right, diff, left_b, right_b; const int dblen = s->dlbuflen, hlen = s->hrflen, blen = s->basslen; - if(AF_OK != RESIZE_LOCAL_BUFFER(af, data)) - return NULL; + mp_audio_realloc_min(af->data, data->samples); if(s->print_flag) { s->print_flag = 0; @@ -425,7 +420,7 @@ static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) "channel\n"); } - out = af->data->audio; + out = af->data->planes[0]; /* MPlayer's 5 channel layout (notation for the variable): * @@ -565,8 +560,7 @@ static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) } /* Set output data */ - data->audio = af->data->audio; - data->len = data->len / data->nch * 2; + data->planes[0] = af->data->planes[0]; mp_audio_set_num_channels(data, 2); return data; @@ -603,10 +597,8 @@ static int af_open(struct af_instance* af) af->control = control; af->uninit = uninit; af->play = play; - af->mul = 1; - af->data = calloc(1, sizeof(struct mp_audio)); af->setup = calloc(1, sizeof(af_hrtf_t)); - if((af->data == NULL) || (af->setup == NULL)) + if(af->setup == NULL) return AF_ERROR; s = af->setup; diff --git a/audio/filter/af_karaoke.c b/audio/filter/af_karaoke.c index b24ba0d877..8c633b136c 100644 --- a/audio/filter/af_karaoke.c +++ b/audio/filter/af_karaoke.c @@ -41,19 +41,13 @@ static int control(struct af_instance* af, int cmd, void* arg) return AF_UNKNOWN; } -// Deallocate memory -static void uninit(struct af_instance* af) -{ - free(af->data); -} - // Filter data through filter static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) { struct mp_audio* c = data; // Current working data - float* a = c->audio; // Audio data - int len = c->len/4; // Number of samples in current audio block + float* a = c->planes[0]; // Audio data int nch = c->nch; // Number of channels + int len = c->samples*nch; // Number of samples in current audio block register int i; /* @@ -74,14 +68,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) // Allocate memory and set function pointers static int af_open(struct af_instance* af){ af->control = control; - af->uninit = uninit; af->play = play; - af->mul = 1; - af->data = calloc(1,sizeof(struct mp_audio)); - - if(af->data == NULL) - return AF_ERROR; - return AF_OK; } diff --git a/audio/filter/af_ladspa.c b/audio/filter/af_ladspa.c index 73b7430201..df88c06ab2 100644 --- a/audio/filter/af_ladspa.c +++ b/audio/filter/af_ladspa.c @@ -497,10 +497,6 @@ static int control(struct af_instance *af, int cmd, void *arg) { mp_audio_copy_config(af->data, (struct mp_audio*)arg); mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE); - /* arg->len is not set here yet, so init of buffers and connecting the - * filter, has to be done in play() :-/ - */ - return af_test_output(af, (struct mp_audio*)arg); case AF_CONTROL_COMMAND_LINE: { char *buf; @@ -650,7 +646,6 @@ static int control(struct af_instance *af, int cmd, void *arg) { */ static void uninit(struct af_instance *af) { - free(af->data); if (af->setup) { af_ladspa_t *setup = (af_ladspa_t*) af->setup; const LADSPA_Descriptor *pdes = setup->plugin_descriptor; @@ -710,8 +705,8 @@ static void uninit(struct af_instance *af) { static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) { af_ladspa_t *setup = af->setup; const LADSPA_Descriptor *pdes = setup->plugin_descriptor; - float *audio = (float*)data->audio; - int nsamples = data->len/4; /* /4 because it's 32-bit float */ + float *audio = (float*)data->planes[0]; + int nsamples = data->samples*data->nch; int nch = data->nch; int rate = data->rate; int i, p; @@ -723,10 +718,6 @@ static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) { * plugin, connect ports and activate plugin */ - /* 2004-12-07: Also check if the buffersize has to be changed! - * data->len is not constant per se! re-init buffers. - */ - if ( (setup->bufsize != nsamples/nch) || (setup->nch != nch) ) { /* if setup->nch==0, it's the first call, if not, something has @@ -884,16 +875,9 @@ static int af_open(struct af_instance *af) { af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - - af->data = calloc(1, sizeof(struct mp_audio)); - if (af->data == NULL) - return af_ladspa_malloc_failed((char*)af_info_ladspa.name); af->setup = calloc(1, sizeof(af_ladspa_t)); if (af->setup == NULL) { - free(af->data); - af->data=NULL; return af_ladspa_malloc_failed((char*)af_info_ladspa.name); } diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c index 9ca193017a..dc2aeb5045 100644 --- a/audio/filter/af_lavcac3enc.c +++ b/audio/filter/af_lavcac3enc.c @@ -34,7 +34,8 @@ #include "config.h" #include "af.h" -#include "audio/reorder_ch.h" +#include "audio/audio_buffer.h" +#include "audio/fmt-conversion.h" #define AC3_MAX_CHANNELS 6 @@ -53,10 +54,9 @@ typedef struct af_ac3enc_s { bool planarize; int add_iec61937_header; int bit_rate; - int pending_data_size; - char *pending_data; - int pending_len; - int expect_len; + struct mp_audio_buffer *pending; + int in_samples; // samples of input per AC3 frame + int out_samples; // upper bound on encoded output per AC3 frame int min_channel_num; int in_sampleformat; } af_ac3enc_t; @@ -65,51 +65,59 @@ typedef struct af_ac3enc_s { static int control(struct af_instance *af, int cmd, void *arg) { af_ac3enc_t *s = af->setup; - struct mp_audio *data = arg; - int i, bit_rate, test_output_res; + int i, bit_rate; static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \ {0, 96000, 192000, 256000, 384000, 448000, 448000}; switch (cmd){ - case AF_CONTROL_REINIT: - if (AF_FORMAT_IS_AC3(data->format) || data->nch < s->min_channel_num) + case AF_CONTROL_REINIT: { + struct mp_audio *in = arg; + struct mp_audio orig_in = *in; + + if (AF_FORMAT_IS_AC3(in->format) || in->nch < s->min_channel_num) return AF_DETACH; - mp_audio_set_format(af->data, s->in_sampleformat); - if (data->rate == 48000 || data->rate == 44100 || data->rate == 32000) - af->data->rate = data->rate; - else - af->data->rate = 48000; - if (data->nch > AC3_MAX_CHANNELS) - mp_audio_set_num_channels(af->data, AC3_MAX_CHANNELS); - else - mp_audio_set_channels(af->data, &data->channels); - mp_chmap_reorder_to_lavc(&af->data->channels); - test_output_res = af_test_output(af, data); - - s->pending_len = 0; - s->expect_len = AC3_FRAME_SIZE * data->nch * af->data->bps; - assert(s->expect_len <= s->pending_data_size); - if (s->add_iec61937_header) - af->mul = (double)AC3_FRAME_SIZE * 2 * 2 / s->expect_len; - else - af->mul = (double)AC3_MAX_CODED_FRAME_SIZE / s->expect_len; + mp_audio_set_format(in, s->in_sampleformat); - mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc reinit: %d, %d, %f, %d.\n", - data->nch, data->rate, af->mul, s->expect_len); + if (in->rate != 48000 && in->rate != 44100 && in->rate != 32000) + in->rate = 48000; + af->data->rate = in->rate; + + mp_chmap_reorder_to_lavc(&in->channels); + if (in->nch > AC3_MAX_CHANNELS) + mp_audio_set_num_channels(in, AC3_MAX_CHANNELS); + + mp_audio_set_format(af->data, AF_FORMAT_AC3_BE); + mp_audio_set_num_channels(af->data, 2); + + if (!mp_audio_config_equals(in, &orig_in)) + return AF_FALSE; - bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[af->data->nch]; + s->in_samples = AC3_FRAME_SIZE; + if (s->add_iec61937_header) { + s->out_samples = AC3_FRAME_SIZE; + } else { + s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride; + } + af->mul = s->out_samples / (double)s->in_samples; - if (s->lavc_actx->channels != af->data->nch || - s->lavc_actx->sample_rate != af->data->rate || - s->lavc_actx->bit_rate != bit_rate) { + mp_audio_buffer_reinit(s->pending, in); + mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc reinit: %d, %d, %f, %d.\n", + in->nch, in->rate, af->mul, s->in_samples); + + bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch]; + + if (s->lavc_actx->channels != in->nch || + s->lavc_actx->sample_rate != in->rate || + s->lavc_actx->bit_rate != bit_rate) + { avcodec_close(s->lavc_actx); // Put sample parameters - s->lavc_actx->channels = af->data->nch; - s->lavc_actx->channel_layout = mp_chmap_to_lavc(&af->data->channels); - s->lavc_actx->sample_rate = af->data->rate; + s->lavc_actx->channels = in->nch; + s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels); + s->lavc_actx->sample_rate = in->rate; s->lavc_actx->bit_rate = bit_rate; if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) { @@ -122,9 +130,8 @@ static int control(struct af_instance *af, int cmd, void *arg) "encoder frame size %d\n", s->lavc_actx->frame_size); return AF_ERROR; } - mp_audio_set_format(af->data, AF_FORMAT_AC3_BE); - mp_audio_set_num_channels(af->data, 2); - return test_output_res; + return AF_OK; + } case AF_CONTROL_COMMAND_LINE: mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc cmdline: %s.\n", (char*)arg); s->bit_rate = 0; @@ -160,102 +167,62 @@ static void uninit(struct af_instance* af) { af_ac3enc_t *s = af->setup; - if (af->data) - free(af->data->audio); - free(af->data); if (s) { av_free_packet(&s->pkt); if(s->lavc_actx) { avcodec_close(s->lavc_actx); av_free(s->lavc_actx); } - free(s->pending_data); - free(s); } } // Filter data through filter static struct mp_audio* play(struct af_instance* af, struct mp_audio* audio) { + struct mp_audio *out = af->data; af_ac3enc_t *s = af->setup; - struct mp_audio *c = audio; // Current working data - struct mp_audio *l; - int left, outsize = 0; - char *buf, *src; - int max_output_len; - int frame_num = (audio->len + s->pending_len) / s->expect_len; - int samplesize = af_fmt2bits(s->in_sampleformat) / 8; - - if (s->add_iec61937_header) - max_output_len = AC3_FRAME_SIZE * 2 * 2 * frame_num; - else - max_output_len = AC3_MAX_CODED_FRAME_SIZE * frame_num; - - if (af->data->len < max_output_len) { - mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, " - "old len = %i, new len = %i\n", af->info->name, af->data->len, - max_output_len); - free(af->data->audio); - af->data->audio = malloc(max_output_len); - if (!af->data->audio) { - mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n"); - return NULL; - } - af->data->len = max_output_len; - } + int num_frames = (audio->samples + mp_audio_buffer_samples(s->pending)) + / s->in_samples; - l = af->data; // Local data - buf = l->audio; - src = c->audio; - left = c->len; + int max_out_samples = s->out_samples * num_frames; + mp_audio_realloc_min(out, max_out_samples); + out->samples = 0; - - while (left > 0) { + while (audio->samples > 0) { int ret; - if (left + s->pending_len < s->expect_len) { - memcpy(s->pending_data + s->pending_len, src, left); - src += left; - s->pending_len += left; - left = 0; - break; - } - - char *src2 = src; - - if (s->pending_len) { - int needs = s->expect_len - s->pending_len; - if (needs > 0) { - memcpy(s->pending_data + s->pending_len, src, needs); - src += needs; - left -= needs; + int consumed_pending = 0; + struct mp_audio in_frame; + int pending = mp_audio_buffer_samples(s->pending); + if (pending == 0 && audio->samples >= s->in_samples) { + in_frame = *audio; + mp_audio_skip_samples(audio, s->in_samples); + } else { + if (pending > 0 && pending < s->in_samples) { + struct mp_audio tmp = *audio; + tmp.samples = MPMIN(tmp.samples, s->in_samples); + mp_audio_buffer_append(s->pending, &tmp); + mp_audio_skip_samples(audio, tmp.samples); } - src2= s->pending_data; - } - - void *data = (void *) src2; - if (s->planarize) { - void *data2 = malloc(s->expect_len); - reorder_to_planar(data2, data, samplesize, - c->nch, s->expect_len / samplesize / c->nch); - data = data2; + mp_audio_buffer_peek(s->pending, &in_frame); + if (in_frame.samples < s->in_samples) + break; + consumed_pending = s->in_samples; } + in_frame.samples = s->in_samples; AVFrame *frame = avcodec_alloc_frame(); if (!frame) { mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n"); return NULL; } - frame->nb_samples = AC3_FRAME_SIZE; + frame->nb_samples = s->in_samples; frame->format = s->lavc_actx->sample_fmt; frame->channel_layout = s->lavc_actx->channel_layout; - - ret = avcodec_fill_audio_frame(frame, c->nch, s->lavc_actx->sample_fmt, - (const uint8_t*)data, s->expect_len, 0); - if (ret < 0) { - mp_msg(MSGT_AFILTER, MSGL_FATAL, "[lavac3enc] Frame setup failed.\n"); - return NULL; - } + assert(in_frame.num_planes <= AV_NUM_DATA_POINTERS); + for (int n = 0; n < in_frame.num_planes; n++) + frame->data[n] = in_frame.planes[n]; + frame->linesize[0] = s->in_samples * audio->sstride; int ok; ret = avcodec_encode_audio2(s->lavc_actx, &s->pkt, frame, &ok); @@ -264,63 +231,55 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* audio) return NULL; } - if (s->planarize) - free(data); - avcodec_free_frame(&frame); - if (s->pending_len) { - s->pending_len = 0; - } else { - src += s->expect_len; - left -= s->expect_len; - } + mp_audio_buffer_skip(s->pending, consumed_pending); mp_msg(MSGT_AFILTER, MSGL_DBG2, "avcodec_encode_audio got %d, pending %d.\n", - s->pkt.size, s->pending_len); + s->pkt.size, mp_audio_buffer_samples(s->pending)); - int len = s->pkt.size; + int frame_size = s->pkt.size; int header_len = 0; - if (s->add_iec61937_header) { - assert(s->pkt.size > 5); - int bsmod = s->pkt.data[5] & 0x7; + char hdr[8]; - AV_WB16(buf, 0xF872); // iec 61937 syncword 1 - AV_WB16(buf + 2, 0x4E1F); // iec 61937 syncword 2 - buf[4] = bsmod; // bsmod - buf[5] = 0x01; // data-type ac3 - AV_WB16(buf + 6, len << 3); // number of bits in payload + if (s->add_iec61937_header && s->pkt.size > 5) { + int bsmod = s->pkt.data[5] & 0x7; + int len = frame_size; - memset(buf + 8 + len, 0, AC3_FRAME_SIZE * 2 * 2 - 8 - len); + frame_size = AC3_FRAME_SIZE * 2 * 2; header_len = 8; - len = AC3_FRAME_SIZE * 2 * 2; + + AV_WB16(hdr, 0xF872); // iec 61937 syncword 1 + AV_WB16(hdr + 2, 0x4E1F); // iec 61937 syncword 2 + hdr[4] = bsmod; // bsmod + hdr[5] = 0x01; // data-type ac3 + AV_WB16(hdr + 6, len << 3); // number of bits in payload } - assert(buf + len <= (char *)af->data->audio + af->data->len); - assert(s->pkt.size <= len - header_len); + size_t max_size = (max_out_samples - out->samples) * out->sstride; + if (frame_size > max_size) + abort(); + char *buf = (char *)out->planes[0] + out->samples * out->sstride; + memcpy(buf, hdr, header_len); memcpy(buf + header_len, s->pkt.data, s->pkt.size); - - outsize += len; - buf += len; + memset(buf + header_len + s->pkt.size, 0, + frame_size - (header_len + s->pkt.size)); + out->samples += frame_size / out->sstride; } - c->audio = l->audio; - mp_audio_set_num_channels(c, 2); - mp_audio_set_format(c, af->data->format); - c->len = outsize; - mp_msg(MSGT_AFILTER, MSGL_DBG2, "play return size %d, pending %d\n", - outsize, s->pending_len); - return c; + + mp_audio_buffer_append(s->pending, audio); + + *audio = *out; + return audio; } static int af_open(struct af_instance* af){ - af_ac3enc_t *s = calloc(1,sizeof(af_ac3enc_t)); + af_ac3enc_t *s = talloc_zero(af, af_ac3enc_t); af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=s; s->lavc_acodec = avcodec_find_encoder_by_name("ac3"); @@ -335,45 +294,25 @@ static int af_open(struct af_instance* af){ return AF_ERROR; } const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts; - for (int i = 0; ; i++) { - if (fmts[i] == AV_SAMPLE_FMT_NONE) { - mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't " - "support expected sample formats!\n"); - return AF_ERROR; - } else if (fmts[i] == AV_SAMPLE_FMT_S16) { - s->in_sampleformat = AF_FORMAT_S16_NE; - s->lavc_actx->sample_fmt = fmts[i]; - s->planarize = 0; - break; - } else if (fmts[i] == AV_SAMPLE_FMT_FLT) { - s->in_sampleformat = AF_FORMAT_FLOAT_NE; - s->lavc_actx->sample_fmt = fmts[i]; - s->planarize = 0; - break; - } else if (fmts[i] == AV_SAMPLE_FMT_S16P) { - s->in_sampleformat = AF_FORMAT_S16_NE; + for (int i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++) { + s->in_sampleformat = af_from_avformat(fmts[i]); + if (s->in_sampleformat) { s->lavc_actx->sample_fmt = fmts[i]; - s->planarize = 1; - break; - } else if (fmts[i] == AV_SAMPLE_FMT_FLTP) { - s->in_sampleformat = AF_FORMAT_FLOAT_NE; - s->lavc_actx->sample_fmt = fmts[i]; - s->planarize = 1; break; } } + if (!s->in_sampleformat) { + mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't " + "support expected sample formats!\n"); + return AF_ERROR; + } mp_msg(MSGT_AFILTER, MSGL_V, "[af_lavcac3enc]: in sample format: %s\n", af_fmt_to_str(s->in_sampleformat)); - s->pending_data_size = AF_NCH * AC3_FRAME_SIZE * - af_fmt2bits(s->in_sampleformat) / 8; - s->pending_data = malloc(s->pending_data_size); - - if (s->planarize) - mp_msg(MSGT_AFILTER, MSGL_WARN, - "[af_lavcac3enc]: need to planarize audio data\n"); av_init_packet(&s->pkt); + s->pending = mp_audio_buffer_create(af); + return AF_OK; } diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c index 3c6d981f1d..24ff8c5985 100644 --- a/audio/filter/af_lavfi.c +++ b/audio/filter/af_lavfi.c @@ -58,14 +58,7 @@ struct priv { AVFilterContext *in; AVFilterContext *out; - // Guarantee that the data stays valid until next filter call - char *out_buffer; - - struct mp_audio data; - struct mp_audio temp; - - int64_t bytes_in; - int64_t bytes_out; + int64_t samples_in; AVRational timebase_out; @@ -129,6 +122,8 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config) static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }; r = av_opt_set_int_list(out, "sample_fmts", sample_fmts, @@ -202,7 +197,8 @@ static int control(struct af_instance *af, int cmd, void *arg) p->timebase_out = l_out->time_base; - af->mul = (double) (out->rate * out->nch) / (in->rate * in->nch); + // Blatantly incorrect; we don't know what the filters do. + af->mul = out->rate / (double)in->rate; return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; } @@ -218,28 +214,25 @@ static int control(struct af_instance *af, int cmd, void *arg) static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) { struct priv *p = af->priv; + struct mp_audio *r = af->data; AVFilterLink *l_in = p->in->outputs[0]; - struct mp_audio *r = &p->temp; - *r = *af->data; - - int in_frame_size = data->bps * data->channels.num; - int out_frame_size = r->bps * r->channels.num; - AVFrame *frame = av_frame_alloc(); - frame->nb_samples = data->len / in_frame_size; + frame->nb_samples = data->samples; frame->format = l_in->format; // Timebase is 1/sample_rate - frame->pts = p->bytes_in / in_frame_size; + frame->pts = p->samples_in; av_frame_set_channels(frame, l_in->channels); av_frame_set_channel_layout(frame, l_in->channel_layout); av_frame_set_sample_rate(frame, l_in->sample_rate); - frame->data[0] = data->audio; frame->extended_data = frame->data; + for (int n = 0; n < data->num_planes; n++) + frame->data[n] = data->planes[n]; + frame->linesize[0] = frame->nb_samples * data->sstride; if (av_buffersrc_add_frame(p->in, frame) < 0) { av_frame_free(&frame); @@ -248,7 +241,7 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) av_frame_free(&frame); int64_t out_pts = AV_NOPTS_VALUE; - size_t out_len = 0; + r->samples = 0; for (;;) { frame = av_frame_alloc(); if (av_buffersink_get_frame(p->out, frame) < 0) { @@ -257,36 +250,32 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) break; } - size_t new_len = out_len + frame->nb_samples * out_frame_size; - if (new_len > talloc_get_size(p->out_buffer)) - p->out_buffer = talloc_realloc(p, p->out_buffer, char, new_len); - memcpy(p->out_buffer + out_len, frame->data[0], new_len - out_len); - out_len = new_len; + mp_audio_realloc_min(r, r->samples + frame->nb_samples); + for (int n = 0; n < r->num_planes; n++) { + memcpy((char *)r->planes[n] + r->samples * r->sstride, + frame->extended_data[n], frame->nb_samples * r->sstride); + } + r->samples += frame->nb_samples; + if (out_pts == AV_NOPTS_VALUE) out_pts = frame->pts; av_frame_free(&frame); } - r->audio = p->out_buffer; - r->len = out_len; - - p->bytes_in += data->len; - p->bytes_out += r->len; + p->samples_in += data->samples; if (out_pts != AV_NOPTS_VALUE) { - int64_t num_in_frames = p->bytes_in / in_frame_size; - double in_time = num_in_frames / (double)data->rate; - + double in_time = p->samples_in / (double)data->rate; double out_time = out_pts * av_q2d(p->timebase_out); // Need pts past the last output sample. - int out_frames = r->len / out_frame_size; - out_time += out_frames / (double)r->rate; + out_time += r->samples / (double)r->rate; - af->delay = (in_time - out_time) * r->rate * out_frame_size; + af->delay = in_time - out_time; } - return r; + *data = *r; + return data; } static void uninit(struct af_instance *af) @@ -298,9 +287,10 @@ static int af_open(struct af_instance *af) af->control = control; af->uninit = uninit; af->play = play; - af->mul = 1; struct priv *priv = af->priv; - af->data = &priv->data; + af->data = talloc_zero(priv, struct mp_audio), + // Removing this requires fixing AVFrame.data vs. AVFrame.extended_data + assert(MP_NUM_CHANNELS <= AV_NUM_DATA_POINTERS); return AF_OK; } diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index 860e5a52d3..2e298a3f39 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -24,6 +24,8 @@ #include <stdlib.h> #include <string.h> #include <inttypes.h> +#include <assert.h> + #include <libavutil/opt.h> #include <libavutil/audioconvert.h> #include <libavutil/common.h> @@ -247,8 +249,7 @@ static int control(struct af_instance *af, int cmd, void *arg) if (af_to_avformat(out->format) == AV_SAMPLE_FMT_NONE) mp_audio_set_format(out, in->format); - af->mul = (double) (out->rate * out->nch) / (in->rate * in->nch); - af->delay = out->nch * s->opts.filter_size / FFMIN(af->mul, 1); + af->mul = out->rate / (double)in->rate; int r = ((in->format == orig_in.format) && mp_chmap_equals(&in->channels, &orig_in.channels)) @@ -299,36 +300,49 @@ static bool needs_reorder(int *reorder, int num_ch) return false; } +static void reorder_planes(struct mp_audio *mpa, int *reorder) +{ + struct mp_audio prev = *mpa; + for (int n = 0; n < mpa->num_planes; n++) { + assert(reorder[n] >= 0 && reorder[n] < mpa->num_planes); + mpa->planes[n] = prev.planes[reorder[n]]; + } +} + +#if !USE_SET_CHANNEL_MAPPING +static void do_reorder(struct mp_audio *mpa, int *reorder) +{ + if (af_fmt_is_planar(mpa->format)) { + reorder_planes(mpa, reorder); + } else { + reorder_channels(mpa->planes[0], reorder, mpa->bps, mpa->nch, mpa->samples); + } +} +#endif + static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) { struct af_resample *s = af->priv; struct mp_audio *in = data; struct mp_audio *out = af->data; - - int in_size = data->len; - int in_samples = in_size / (data->bps * data->nch); - int out_samples = avresample_available(s->avrctx) + - av_rescale_rnd(get_delay(s) + in_samples, + out->samples = avresample_available(s->avrctx) + + av_rescale_rnd(get_delay(s) + in->samples, s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP); - int out_size = out->bps * out_samples * out->nch; - if (talloc_get_size(out->audio) < out_size) - out->audio = talloc_realloc_size(out, out->audio, out_size); + mp_audio_realloc_min(out, out->samples); - af->delay = out->bps * av_rescale_rnd(get_delay(s), - s->ctx.out_rate, s->ctx.in_rate, - AV_ROUND_UP); + af->delay = get_delay(s) / (double)s->ctx.in_rate; #if !USE_SET_CHANNEL_MAPPING - reorder_channels(data->audio, s->reorder_in, data->bps, data->nch, in_samples); + do_reorder(in, s->reorder_in); #endif - if (out_samples) { - out_samples = avresample_convert(s->avrctx, - (uint8_t **) &out->audio, out_size, out_samples, - (uint8_t **) &in->audio, in_size, in_samples); - if (out_samples < 0) + if (out->samples) { + out->samples = avresample_convert(s->avrctx, + (uint8_t **) out->planes, out->samples * out->sstride, out->samples, + (uint8_t **) in->planes, in->samples * in->sstride, in->samples); + if (out->samples < 0) return NULL; // error } @@ -336,18 +350,23 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) #if USE_SET_CHANNEL_MAPPING if (needs_reorder(s->reorder_out, out->nch)) { - if (talloc_get_size(s->reorder_buffer) < out_size) - s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size); - data->audio = s->reorder_buffer; - out_samples = avresample_convert(s->avrctx_out, - (uint8_t **) &data->audio, out_size, out_samples, - (uint8_t **) &out->audio, out_size, out_samples); + if (af_fmt_is_planar(out->format)) { + reorder_planes(data, s->reorder_out); + } else { + int out_size = out->samples * out->sstride; + if (talloc_get_size(s->reorder_buffer) < out_size) + s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size); + data->planes[0] = s->reorder_buffer; + int out_samples = avresample_convert(s->avrctx_out, + (uint8_t **) data->planes, out_size, out->samples, + (uint8_t **) out->planes, out_size, out->samples); + assert(out_samples == data->samples); + } } #else - reorder_channels(data->audio, s->reorder_out, out->bps, out->nch, out_samples); + do_reorder(data, s->reorder_out); #endif - data->len = out->bps * out_samples * out->nch; return data; } @@ -358,10 +377,6 @@ static int af_open(struct af_instance *af) af->control = control; af->uninit = uninit; af->play = play; - af->mul = 1; - af->data = talloc_zero(s, struct mp_audio); - - af->data->rate = 0; if (s->opts.cutoff <= 0.0) s->opts.cutoff = af_resample_default_cutoff(s->opts.filter_size); diff --git a/audio/filter/af_pan.c b/audio/filter/af_pan.c index b3e31dab98..3d8c6045d0 100644 --- a/audio/filter/af_pan.c +++ b/audio/filter/af_pan.c @@ -57,7 +57,6 @@ static int control(struct af_instance* af, int cmd, void* arg) af->data->rate = ((struct mp_audio*)arg)->rate; mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE); set_channels(af->data, s->nch ? s->nch: ((struct mp_audio*)arg)->nch); - af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch; if((af->data->format != ((struct mp_audio*)arg)->format) || (af->data->bps != ((struct mp_audio*)arg)->bps)){ @@ -146,9 +145,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - if(af->data) - free(af->data->audio); - free(af->data); free(af->setup); } @@ -158,17 +154,16 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) struct mp_audio* c = data; // Current working data struct mp_audio* l = af->data; // Local data af_pan_t* s = af->setup; // Setup for this instance - float* in = c->audio; // Input audio data + float* in = c->planes[0]; // Input audio data float* out = NULL; // Output audio data - float* end = in+c->len/4; // End of loop + float* end = in+c->samples*c->nch; // End of loop int nchi = c->nch; // Number of input channels int ncho = l->nch; // Number of output channels register int j,k; - if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) - return NULL; + mp_audio_realloc_min(af->data, data->samples); - out = l->audio; + out = l->planes[0]; // Execute panning // FIXME: Too slow while(in < end){ @@ -184,8 +179,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) } // Set output data - c->audio = l->audio; - c->len = c->len / c->nch * l->nch; + c->planes[0] = l->planes[0]; set_channels(c, l->nch); return c; @@ -196,10 +190,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_pan_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; return AF_OK; } diff --git a/audio/filter/af_scaletempo.c b/audio/filter/af_scaletempo.c index fdcfd5560f..c8560af502 100644 --- a/audio/filter/af_scaletempo.c +++ b/audio/filter/af_scaletempo.c @@ -47,11 +47,11 @@ typedef struct af_scaletempo_s // stride float scale; float speed; + int frames_stride; float frames_stride_scaled; float frames_stride_error; int bytes_per_frame; int bytes_stride; - float bytes_stride_scaled; int bytes_queue; int bytes_queued; int bytes_to_slide; @@ -84,7 +84,7 @@ typedef struct af_scaletempo_s static int fill_queue(struct af_instance *af, struct mp_audio *data, int offset) { af_scaletempo_t *s = af->priv; - int bytes_in = data->len - offset; + int bytes_in = mp_audio_psize(data) - offset; int offset_unchanged = offset; if (s->bytes_to_slide > 0) { @@ -108,7 +108,7 @@ static int fill_queue(struct af_instance *af, struct mp_audio *data, int offset) int bytes_copy = MPMIN(s->bytes_queue - s->bytes_queued, bytes_in); assert(bytes_copy >= 0); memcpy(s->buf_queue + s->bytes_queued, - (int8_t *)data->audio + offset, bytes_copy); + (int8_t *)data->planes[0] + offset, bytes_copy); s->bytes_queued += bytes_copy; offset += bytes_copy; } @@ -220,24 +220,11 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) return data; } - // RESIZE_LOCAL_BUFFER - can't use macro - int max_bytes_out = ((int)(data->len / s->bytes_stride_scaled) + 1) - * s->bytes_stride; - if (max_bytes_out > af->data->len) { - mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, " - "old len = %i, new len = %i\n", af->info->name, - af->data->len, max_bytes_out); - af->data->audio = realloc(af->data->audio, max_bytes_out); - if (!af->data->audio) { - mp_msg(MSGT_AFILTER, MSGL_FATAL, - "[libaf] Could not allocate memory\n"); - return NULL; - } - af->data->len = max_bytes_out; - } + mp_audio_realloc_min(af->data, + ((int)(data->samples / s->frames_stride_scaled) + 1) * s->frames_stride); int offset_in = fill_queue(af, data, 0); - int8_t *pout = af->data->audio; + int8_t *pout = af->data->planes[0]; while (s->bytes_queued >= s->bytes_queue) { int ti; float tf; @@ -269,10 +256,11 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) // This filter can have a negative delay when scale > 1: // output corresponding to some length of input can be decided and written // after receiving only a part of that input. - af->delay = s->bytes_queued - s->bytes_to_slide; + af->delay = (s->bytes_queued - s->bytes_to_slide) / s->scale + / af->data->sstride / af->data->rate; - data->audio = af->data->audio; - data->len = pout - (int8_t *)af->data->audio; + data->planes[0] = af->data->planes[0]; + data->samples = (pout - (int8_t *)af->data->planes[0]) / af->data->sstride; return data; } @@ -291,6 +279,7 @@ static int control(struct af_instance *af, int cmd, void *arg) "[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n", s->speed, s->scale_nominal, s->scale); + mp_audio_force_interleaved_format(data); mp_audio_copy_config(af->data, data); if (s->scale == 1.0) { @@ -308,15 +297,14 @@ static int control(struct af_instance *af, int cmd, void *arg) } int bps = af->data->bps; - int frames_stride = srate * s->ms_stride; - s->bytes_stride = frames_stride * bps * nch; - s->bytes_stride_scaled = s->scale * s->bytes_stride; - s->frames_stride_scaled = s->scale * frames_stride; + s->frames_stride = srate * s->ms_stride; + s->bytes_stride = s->frames_stride * bps * nch; + s->frames_stride_scaled = s->scale * s->frames_stride; s->frames_stride_error = 0; - af->mul = (double)s->bytes_stride / s->bytes_stride_scaled; + af->mul = 1.0 / s->scale; af->delay = 0; - int frames_overlap = frames_stride * s->percent_overlap; + int frames_overlap = s->frames_stride * s->percent_overlap; if (frames_overlap <= 0) { s->bytes_standing = s->bytes_stride; s->samples_standing = s->bytes_standing / bps; @@ -401,8 +389,8 @@ static int control(struct af_instance *af, int cmd, void *arg) s->bytes_per_frame = bps * nch; s->num_channels = nch; - s->bytes_queue - = (s->frames_search + frames_stride + frames_overlap) * bps * nch; + s->bytes_queue = (s->frames_search + s->frames_stride + frames_overlap) + * bps * nch; s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING); if (!s->buf_queue) { mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n"); @@ -456,8 +444,6 @@ static int control(struct af_instance *af, int cmd, void *arg) static void uninit(struct af_instance *af) { af_scaletempo_t *s = af->priv; - free(af->data->audio); - free(af->data); free(s->buf_queue); free(s->buf_overlap); free(s->buf_pre_corr); @@ -476,10 +462,6 @@ static int af_open(struct af_instance *af) af->control = control; af->uninit = uninit; af->play = play; - af->mul = 1; - af->data = calloc(1, sizeof(struct mp_audio)); - if (af->data == NULL) - return AF_ERROR; s->speed_tempo = !!(s->speed_opt & SCALE_TEMPO); s->speed_pitch = !!(s->speed_opt & SCALE_PITCH); diff --git a/audio/filter/af_sinesuppress.c b/audio/filter/af_sinesuppress.c index b9c86ccfe9..ef6fd7d37b 100644 --- a/audio/filter/af_sinesuppress.c +++ b/audio/filter/af_sinesuppress.c @@ -85,7 +85,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } @@ -94,8 +93,8 @@ static struct mp_audio* play_s16(struct af_instance* af, struct mp_audio* data) { af_sinesuppress_t *s = af->setup; register int i = 0; - int16_t *a = (int16_t*)data->audio; // Audio data - int len = data->len/2; // Number of samples + int16_t *a = (int16_t*)data->planes[0]; // Audio data + int len = data->samples*data->nch; // Number of samples for (i = 0; i < len; i++) { @@ -149,10 +148,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play_s16; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_sinesuppress_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; ((af_sinesuppress_t*)af->setup)->freq = 50.0; diff --git a/audio/filter/af_sub.c b/audio/filter/af_sub.c index 7778e80b64..4fd16904c9 100644 --- a/audio/filter/af_sub.c +++ b/audio/filter/af_sub.c @@ -123,7 +123,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } @@ -143,8 +142,8 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) { struct mp_audio* c = data; // Current working data af_sub_t* s = af->setup; // Setup for this instance - float* a = c->audio; // Audio data - int len = c->len/4; // Number of samples in current audio block + float* a = c->planes[0]; // Audio data + int len = c->samples*c->nch; // Number of samples in current audio block int nch = c->nch; // Number of channels int ch = s->ch; // Channel in which to insert the sub audio register int i; @@ -166,10 +165,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=s=calloc(1,sizeof(af_sub_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; // Set default values s->ch = 5; // Channel nr 6 diff --git a/audio/filter/af_surround.c b/audio/filter/af_surround.c index e584e6505a..efeecdc1e3 100644 --- a/audio/filter/af_surround.c +++ b/audio/filter/af_surround.c @@ -144,9 +144,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - if(af->data) - free(af->data->audio); - free(af->data); free(af->setup); } @@ -165,17 +162,16 @@ static float steering_matrix[][12] = { static struct mp_audio* play(struct af_instance* af, struct mp_audio* data){ af_surround_t* s = (af_surround_t*)af->setup; float* m = steering_matrix[0]; - float* in = data->audio; // Input audio data + float* in = data->planes[0]; // Input audio data float* out = NULL; // Output audio data - float* end = in + data->len / sizeof(float); // Loop end + float* end = in + data->samples * data->nch; int i = s->i; // Filter queue index int ri = s->ri; // Read index for delay queue int wi = s->wi; // Write index for delay queue - if (AF_OK != RESIZE_LOCAL_BUFFER(af, data)) - return NULL; + mp_audio_realloc_min(af->data, data->samples); - out = af->data->audio; + out = af->data->planes[0]; while(in < end){ /* Dominance: @@ -237,8 +233,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data){ s->i = i; s->ri = ri; s->wi = wi; // Set output data - data->audio = af->data->audio; - data->len *= 2; + data->planes[0] = af->data->planes[0]; mp_audio_set_channels_old(data, af->data->nch); return data; @@ -248,10 +243,8 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=2; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_surround_t)); - if(af->data == NULL || af->setup == NULL) + if(af->setup == NULL) return AF_ERROR; ((af_surround_t*)af->setup)->d = 20; return AF_OK; diff --git a/audio/filter/af_sweep.c b/audio/filter/af_sweep.c index 0a140dcb65..c153d4261a 100644 --- a/audio/filter/af_sweep.c +++ b/audio/filter/af_sweep.c @@ -58,7 +58,6 @@ static int control(struct af_instance* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance* af) { - free(af->data); free(af->setup); } @@ -67,9 +66,9 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data) { af_sweept *s = af->setup; int i, j; - int16_t *in = (int16_t*)data->audio; + int16_t *in = (int16_t*)data->planes[0]; int chans = data->nch; - int in_len = data->len/(2*chans); + int in_len = data->samples; for(i=0; i<in_len; i++){ for(j=0; j<chans; j++) @@ -85,8 +84,6 @@ static int af_open(struct af_instance* af){ af->control=control; af->uninit=uninit; af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(struct mp_audio)); af->setup=calloc(1,sizeof(af_sweept)); return AF_OK; } diff --git a/audio/filter/af_volume.c b/audio/filter/af_volume.c index 9639ffb5c4..b0eef1865c 100644 --- a/audio/filter/af_volume.c +++ b/audio/filter/af_volume.c @@ -41,15 +41,21 @@ static int control(struct af_instance *af, int cmd, void *arg) struct priv *s = af->priv; switch (cmd) { - case AF_CONTROL_REINIT: - mp_audio_copy_config(af->data, (struct mp_audio *)arg); + case AF_CONTROL_REINIT: { + struct mp_audio *in = arg; - if (s->fast && (((struct mp_audio *)arg)->format != AF_FORMAT_FLOAT_NE)) + mp_audio_copy_config(af->data, in); + mp_audio_force_interleaved_format(af->data); + + if (s->fast && af_fmt_from_planar(in->format) != AF_FORMAT_FLOAT_NE) { mp_audio_set_format(af->data, AF_FORMAT_S16_NE); - else { + } else { mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE); } - return af_test_output(af, (struct mp_audio *)arg); + if (af_fmt_is_planar(in->format)) + mp_audio_set_format(af->data, af_fmt_to_planar(af->data->format)); + return af_test_output(af, in); + } case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET: s->level = *(float *)arg; return AF_OK; @@ -60,33 +66,37 @@ static int control(struct af_instance *af, int cmd, void *arg) return AF_UNKNOWN; } -static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) +static void filter_plane(struct af_instance *af, void *ptr, int num_samples) { - struct mp_audio *c = data; struct priv *s = af->priv; - if (af->data->format == AF_FORMAT_S16_NE) { - int16_t *a = c->audio; - int len = c->len / 2; + if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16_NE) { + int16_t *a = ptr; int vol = 256.0 * s->level; if (vol != 256) { - for (int i = 0; i < len; i++) { + for (int i = 0; i < num_samples; i++) { int x = (a[i] * vol) >> 8; a[i] = MPCLAMP(x, SHRT_MIN, SHRT_MAX); } } - } else if (af->data->format == AF_FORMAT_FLOAT_NE) { - float *a = c->audio; - int len = c->len / 4; + } else if (af_fmt_from_planar(af->data->format) == AF_FORMAT_FLOAT_NE) { + float *a = ptr; float vol = s->level; if (vol != 1.0) { - for (int i = 0; i < len; i++) { + for (int i = 0; i < num_samples; i++) { float x = a[i] * vol; a[i] = s->soft ? af_softclip(x) : MPCLAMP(x, -1.0, 1.0); } } } - return c; +} + +static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) +{ + for (int n = 0; n < data->num_planes; n++) + filter_plane(af, data->planes[n], data->samples * data->spf); + + return data; } static int af_open(struct af_instance *af) @@ -94,8 +104,6 @@ static int af_open(struct af_instance *af) struct priv *s = af->priv; af->control = control; af->play = play; - af->mul = 1; - af->data = talloc_zero(af, struct mp_audio); af_from_dB(1, &s->cfg_volume, &s->level, 20.0, -200.0, 60.0); return AF_OK; } diff --git a/audio/fmt-conversion.c b/audio/fmt-conversion.c index 94f1fbd1f3..93fda3eaa0 100644 --- a/audio/fmt-conversion.c +++ b/audio/fmt-conversion.c @@ -32,6 +32,12 @@ static const struct { {AV_SAMPLE_FMT_FLT, AF_FORMAT_FLOAT_NE}, {AV_SAMPLE_FMT_DBL, AF_FORMAT_DOUBLE_NE}, + {AV_SAMPLE_FMT_U8P, AF_FORMAT_U8P}, + {AV_SAMPLE_FMT_S16P, AF_FORMAT_S16P}, + {AV_SAMPLE_FMT_S32P, AF_FORMAT_S32P}, + {AV_SAMPLE_FMT_FLTP, AF_FORMAT_FLOATP}, + {AV_SAMPLE_FMT_DBLP, AF_FORMAT_DOUBLEP}, + {AV_SAMPLE_FMT_NONE, 0}, }; diff --git a/audio/format.c b/audio/format.c index 448b670671..d0cd04cb88 100644 --- a/audio/format.c +++ b/audio/format.c @@ -23,7 +23,9 @@ #include <string.h> #include <inttypes.h> #include <limits.h> +#include <assert.h> +#include "mpvcore/mp_common.h" #include "audio/filter/af.h" int af_fmt2bits(int format) @@ -62,6 +64,46 @@ int af_fmt_change_bits(int format, int bits) return af_fmt_is_valid(format) ? format : 0; } +static const int planar_formats[][2] = { + {AF_FORMAT_U8P, AF_FORMAT_U8}, + {AF_FORMAT_S16P, AF_FORMAT_S16}, + {AF_FORMAT_S32P, AF_FORMAT_S32}, + {AF_FORMAT_FLOATP, AF_FORMAT_FLOAT}, + {AF_FORMAT_DOUBLEP, AF_FORMAT_DOUBLE}, +}; + +// Return the planar format corresponding to the given format. +// If the format is already planar, return it. +// Return 0 if there's no equivalent. +int af_fmt_to_planar(int format) +{ + for (int n = 0; n < MP_ARRAY_SIZE(planar_formats); n++) { + if (planar_formats[n][1] == format) + return planar_formats[n][0]; + if (planar_formats[n][0] == format) + return format; + } + return 0; +} + +// Return the interleaved format corresponding to the given format. +// If the format is already interleaved, return it. +// Always succeeds if format is actually planar; otherwise return 0. +int af_fmt_from_planar(int format) +{ + for (int n = 0; n < MP_ARRAY_SIZE(planar_formats); n++) { + if (planar_formats[n][0] == format) + return planar_formats[n][1]; + } + return format; +} + +// false for interleaved and AF_FORMAT_UNKNOWN +bool af_fmt_is_planar(int format) +{ + return !!(format & AF_FORMAT_PLANAR); +} + #define FMT(string, id) \ {string, id}, @@ -87,6 +129,12 @@ const struct af_fmt_entry af_fmtstr_table[] = { FMT_ENDIAN("float", AF_FORMAT_FLOAT) FMT_ENDIAN("double", AF_FORMAT_DOUBLE) + FMT("u8p", AF_FORMAT_U8P) + FMT("s16p", AF_FORMAT_S16P) + FMT("s32p", AF_FORMAT_S32P) + FMT("floatp", AF_FORMAT_FLOATP) + FMT("doublep", AF_FORMAT_DOUBLEP) + {0} }; @@ -111,6 +159,7 @@ const char *af_fmt_to_str(int format) int af_fmt_seconds_to_bytes(int format, float seconds, int channels, int samplerate) { + assert(!af_fmt_is_planar(format)); int bps = (af_fmt2bits(format) / 8); int framelen = channels * bps; int bytes = seconds * bps * samplerate; diff --git a/audio/format.h b/audio/format.h index 95e792340c..9b855e4689 100644 --- a/audio/format.h +++ b/audio/format.h @@ -23,6 +23,7 @@ #ifndef MPLAYER_AF_FORMAT_H #define MPLAYER_AF_FORMAT_H +#include <stdbool.h> #include <sys/types.h> #include "config.h" #include "mpvcore/bstr.h" @@ -64,9 +65,15 @@ #define AF_FORMAT_F (2<<9) // Foating point #define AF_FORMAT_POINT_MASK (3<<9) -#define AF_FORMAT_MASK ((1<<11)-1) +// Interleaving (planar formats have data for each channel in separate planes) +#define AF_FORMAT_INTERLEAVED (0<<11) // must be 0 +#define AF_FORMAT_PLANAR (1<<11) +#define AF_FORMAT_INTERLEAVING_MASK (1<<11) -// PREDEFINED formats +#define AF_FORMAT_MASK ((1<<12)-1) + +#define AF_INTP (AF_FORMAT_I|AF_FORMAT_PLANAR) +#define AF_FLTP (AF_FORMAT_F|AF_FORMAT_PLANAR) // actual sample formats enum af_format { @@ -101,6 +108,13 @@ enum af_format { AF_FORMAT_MPEG2 = (AF_FORMAT_S_MPEG2), + // Planar variants + AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT|AF_FORMAT_NE), + AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_NE), + AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_32BIT|AF_FORMAT_NE), + AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT|AF_FORMAT_NE), + AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_32BIT|AF_FORMAT_NE), + // Native endian variants AF_FORMAT_U16 = AF_SELECT_LE_BE(AF_FORMAT_U16_LE, AF_FORMAT_U16_BE), AF_FORMAT_S16 = AF_SELECT_LE_BE(AF_FORMAT_S16_LE, AF_FORMAT_S16_BE), @@ -150,6 +164,10 @@ const char *af_fmt_to_str(int format); int af_fmt2bits(int format); int af_fmt_change_bits(int format, int bits); +int af_fmt_to_planar(int format); +int af_fmt_from_planar(int format); +bool af_fmt_is_planar(int format); + // Amount of bytes that contain audio of the given duration, aligned to frames. int af_fmt_seconds_to_bytes(int format, float seconds, int channels, int samplerate); diff --git a/audio/out/ao.c b/audio/out/ao.c index 55db34becb..50c95830c3 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -159,7 +159,10 @@ static struct ao *ao_create(bool probing, struct mpv_global *global, talloc_free(chmap); if (ao->driver->init(ao) < 0) goto error; - ao->bps = ao->channels.num * ao->samplerate * af_fmt2bits(ao->format) / 8; + ao->sstride = af_fmt2bits(ao->format) / 8; + if (!af_fmt_is_planar(ao->format)) + ao->sstride *= ao->channels.num; + ao->bps = ao->samplerate * ao->sstride; return ao; error: talloc_free(ao); @@ -206,9 +209,9 @@ void ao_uninit(struct ao *ao, bool cut_audio) talloc_free(ao); } -int ao_play(struct ao *ao, void *data, int len, int flags) +int ao_play(struct ao *ao, void **data, int samples, int flags) { - return ao->driver->play(ao, data, len, flags); + return ao->driver->play(ao, data, samples, flags); } int ao_control(struct ao *ao, enum aocontrol cmd, void *arg) @@ -254,10 +257,12 @@ int ao_play_silence(struct ao *ao, int samples) { if (samples <= 0 || AF_FORMAT_IS_SPECIAL(ao->format)) return 0; - int s = ao->channels.num * (af_fmt2bits(ao->format) / 8); - char *p = talloc_size(NULL, samples * s); - af_fill_silence(p, samples * s, ao->format); - int r = ao_play(ao, p, samples * s, 0); + char *p = talloc_size(NULL, samples * ao->sstride); + af_fill_silence(p, samples * ao->sstride, ao->format); + void *tmp[MP_NUM_CHANNELS]; + for (int n = 0; n < MP_NUM_CHANNELS; n++) + tmp[n] = p; + int r = ao_play(ao, tmp, samples, 0); talloc_free(p); return r; } diff --git a/audio/out/ao.h b/audio/out/ao.h index 159a6adc0f..dff9ad6a8b 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -56,7 +56,7 @@ struct ao_driver { void (*uninit)(struct ao *ao, bool cut_audio); void (*reset)(struct ao*ao); int (*get_space)(struct ao *ao); - int (*play)(struct ao *ao, void *data, int len, int flags); + int (*play)(struct ao *ao, void **data, int samples, int flags); float (*get_delay)(struct ao *ao); void (*pause)(struct ao *ao); void (*resume)(struct ao *ao); @@ -73,9 +73,11 @@ struct ao { struct mp_chmap channels; int format; int bps; // bytes per second + int sstride; // size of a sample on each plane + // (format_size*num_channels/num_planes) double pts; // some mplayer.c state (why is this here?) - struct bstr buffer; - int buffer_playable_size; // part of the part of the buffer the AO hasn't + struct mp_audio_buffer *buffer; // queued audio; passed to play() later + int buffer_playable_samples;// part of the part of the buffer the AO hasn't // accepted yet with play() bool probing; // if true, don't fail loudly on init bool untimed; @@ -95,7 +97,7 @@ struct ao *ao_init_best(struct mpv_global *global, struct encode_lavc_context *encode_lavc_ctx, int samplerate, int format, struct mp_chmap channels); void ao_uninit(struct ao *ao, bool cut_audio); -int ao_play(struct ao *ao, void *data, int len, int flags); +int ao_play(struct ao *ao, void **data, int samples, int flags); int ao_control(struct ao *ao, enum aocontrol cmd, void *arg); double ao_get_delay(struct ao *ao); int ao_get_space(struct ao *ao); diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 5816ee5f5f..2ef35db6cf 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -52,12 +52,11 @@ struct priv { snd_pcm_t *alsa; snd_pcm_format_t alsa_fmt; - size_t bytes_per_sample; int can_pause; snd_pcm_sframes_t prepause_frames; float delay_before_pause; - int buffersize; - int outburst; + int buffersize; // in frames + int outburst; // in frames int cfg_block; char *cfg_device; @@ -251,6 +250,7 @@ static const int mp_to_alsa_format[][2] = { static int find_alsa_format(int af_format) { + af_format = af_fmt_from_planar(af_format); for (int n = 0; mp_to_alsa_format[n][0] != AF_FORMAT_UNKNOWN; n++) { if (mp_to_alsa_format[n][0] == af_format) return mp_to_alsa_format[n][1]; @@ -432,10 +432,6 @@ static int init(struct ao *ao) err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams); CHECK_ALSA_ERROR("Unable to get initial parameters"); - err = snd_pcm_hw_params_set_access - (p->alsa, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); - CHECK_ALSA_ERROR("Unable to set access type"); - p->alsa_fmt = find_alsa_format(ao->format); if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) { p->alsa_fmt = SND_PCM_FORMAT_S16; @@ -458,6 +454,12 @@ static int init(struct ao *ao) err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt); CHECK_ALSA_ERROR("Unable to set format"); + snd_pcm_access_t access = af_fmt_is_planar(ao->format) + ? SND_PCM_ACCESS_RW_NONINTERLEAVED + : SND_PCM_ACCESS_RW_INTERLEAVED; + err = snd_pcm_hw_params_set_access(p->alsa, alsa_hwparams, access); + CHECK_ALSA_ERROR("Unable to set access type"); + int num_channels = ao->channels.num; err = snd_pcm_hw_params_set_channels_near (p->alsa, alsa_hwparams, &num_channels); @@ -478,9 +480,6 @@ static int init(struct ao *ao) (p->alsa, alsa_hwparams, &ao->samplerate, NULL); CHECK_ALSA_ERROR("Unable to set samplerate-2"); - p->bytes_per_sample = af_fmt2bits(ao->format) / 8; - p->bytes_per_sample *= ao->channels.num; - err = snd_pcm_hw_params_set_buffer_time_near (p->alsa, alsa_hwparams, &(unsigned int){BUFFER_TIME}, NULL); CHECK_ALSA_ERROR("Unable to set buffer time near"); @@ -499,14 +498,14 @@ static int init(struct ao *ao) err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize); CHECK_ALSA_ERROR("Unable to get buffersize"); - p->buffersize = bufsize * p->bytes_per_sample; - MP_VERBOSE(ao, "got buffersize=%i\n", p->buffersize); + p->buffersize = bufsize; + MP_VERBOSE(ao, "got buffersize=%i samples\n", p->buffersize); err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL); CHECK_ALSA_ERROR("Unable to get period size"); MP_VERBOSE(ao, "got period size %li\n", chunk_size); - p->outburst = chunk_size * p->bytes_per_sample; + p->outburst = chunk_size; /* setting software parameters */ err = snd_pcm_sw_params_current(p->alsa, alsa_swparams); @@ -537,8 +536,8 @@ static int init(struct ao *ao) p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams); - MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", - ao->samplerate, ao->channels.num, (int)p->bytes_per_sample, + MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bps/%d samples buffer/%s\n", + ao->samplerate, ao->channels.num, af_fmt2bits(ao->format), p->buffersize, snd_pcm_format_description(p->alsa_fmt)); return 0; @@ -634,32 +633,27 @@ static void reset(struct ao *ao) alsa_error: ; } -/* - plays 'len' bytes of 'data' - returns: number of bytes played - modified last at 29.06.02 by jp - thanxs for marius <marius@rospot.com> for giving us the light ;) - */ - -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; - int num_frames; snd_pcm_sframes_t res = 0; if (!(flags & AOPLAY_FINAL_CHUNK)) - len = len / p->outburst * p->outburst; - num_frames = len / p->bytes_per_sample; + samples = samples / p->outburst * p->outburst; if (!p->alsa) { MP_ERR(ao, "Device configuration error."); return -1; } - if (num_frames == 0) + if (samples == 0) return 0; do { - res = snd_pcm_writei(p->alsa, data, num_frames); + if (af_fmt_is_planar(ao->format)) { + res = snd_pcm_writen(p->alsa, data, samples); + } else { + res = snd_pcm_writei(p->alsa, data[0], samples); + } if (res == -EINTR) { /* nothing to do */ @@ -678,7 +672,7 @@ static int play(struct ao *ao, void *data, int len, int flags) } } while (res == 0); - return res < 0 ? -1 : res * p->bytes_per_sample; + return res < 0 ? -1 : res; alsa_error: return -1; @@ -696,7 +690,7 @@ static int get_space(struct ao *ao) err = snd_pcm_status(p->alsa, status); CHECK_ALSA_ERROR("cannot get pcm status"); - unsigned space = snd_pcm_status_get_avail(status) * p->bytes_per_sample; + unsigned space = snd_pcm_status_get_avail(status); if (space > p->buffersize) // Buffer underrun? space = p->buffersize; return space; diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index da526ada20..d61ce63d01 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -285,6 +285,8 @@ static int init(struct ao *ao) // Save selected device id p->device = selected_device; + ao->format = af_fmt_from_planar(ao->format); + bool supports_digital = false; /* Probe whether device support S/PDIF stream output if input is AC3 stream. */ if (AF_FORMAT_IS_AC3(ao->format)) { @@ -576,10 +578,12 @@ coreaudio_error: return CONTROL_ERROR; } -static int play(struct ao *ao, void *output_samples, int num_bytes, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; struct priv_d *d = p->digital; + void *output_samples = data[0]; + int num_bytes = samples * ao->sstride; // Check whether we need to reset the digital output stream. if (p->is_digital && d->stream_asbd_changed) { @@ -597,7 +601,7 @@ static int play(struct ao *ao, void *output_samples, int num_bytes, int flags) int wrote = mp_ring_write(p->buffer, output_samples, num_bytes); audio_resume(ao); - return wrote; + return wrote / ao->sstride; } static void reset(struct ao *ao) @@ -610,7 +614,7 @@ static void reset(struct ao *ao) static int get_space(struct ao *ao) { struct priv *p = ao->priv; - return mp_ring_available(p->buffer); + return mp_ring_available(p->buffer) / ao->sstride; } static float get_delay(struct ao *ao) diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c index 464947c0dc..f828a210dc 100644 --- a/audio/out/ao_dsound.c +++ b/audio/out/ao_dsound.c @@ -388,7 +388,7 @@ static int init(struct ao *ao) WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; - int format = ao->format; + int format = af_fmt_from_planar(ao->format); int rate = ao->samplerate; if (AF_FORMAT_IS_AC3(format)) @@ -596,7 +596,7 @@ static int get_space(struct ao *ao) int space = check_free_buffer_size(ao); if (space < p->min_free_space) return 0; - return space - p->min_free_space; + return (space - p->min_free_space) / ao->sstride; } /** @@ -606,9 +606,10 @@ static int get_space(struct ao *ao) \param flags currently unused \return number of played bytes */ -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; + int len = samples * ao->sstride; int space = check_free_buffer_size(ao); if (space < len) @@ -616,7 +617,7 @@ static int play(struct ao *ao, void *data, int len, int flags) if (!(flags & AOPLAY_FINAL_CHUNK)) len = (len / p->outburst) * p->outburst; - return write_buffer(ao, data, len); + return write_buffer(ao, data[0], len) / ao->sstride; } /** diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index 20dd0d4aab..8a55a54239 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -4,6 +4,8 @@ * Copyleft 2001 by Felix Bünemann (atmosfear@users.sf.net) * and Reimar Döffinger (Reimar.Doeffinger@stud.uni-karlsruhe.de) * + * Copyleft 2013 by William Light <wrl@illest.net> for the mpv project + * * This file is part of MPlayer. * * MPlayer is free software; you can redistribute it and/or modify @@ -38,20 +40,19 @@ #include <jack/jack.h> -//! maximum number of channels supported, avoids lots of mallocs -#define MAX_CHANS MP_NUM_CHANNELS - //! size of one chunk, if this is too small MPlayer will start to "stutter" //! after a short time of playback -#define CHUNK_SIZE (24 * 1024) +#define CHUNK_SIZE (8 * 1024) //! number of "virtual" chunks the buffer consists of #define NUM_CHUNKS 8 +struct port_ring { + jack_port_t *port; + struct mp_ring *ring; +}; + struct priv { - jack_port_t * ports[MAX_CHANS]; - int num_ports; // Number of used ports == number of channels jack_client_t *client; - int outburst; float jack_latency; char *cfg_port; char *cfg_client_name; @@ -60,76 +61,49 @@ struct priv { int autostart; int stdlayout; volatile int paused; - volatile int underrun; // signals if an underrun occured + volatile int underrun; volatile float callback_interval; volatile float callback_time; - struct mp_ring *ring; // buffer for audio data -}; - -static void silence(float **bufs, int cnt, int num_bufs); -struct deinterleave { - float **bufs; - int num_bufs; - int cur_buf; - int pos; + int num_ports; + struct port_ring ports[MP_NUM_CHANNELS]; }; -static void deinterleave(void *info, void *src, int len) -{ - struct deinterleave *di = info; - float *s = src; - int i; - len /= sizeof(float); - for (i = 0; i < len; i++) { - di->bufs[di->cur_buf++][di->pos] = s[i]; - if (di->cur_buf >= di->num_bufs) { - di->cur_buf = 0; - di->pos++; - } - } -} - -/** - * \brief read data from buffer and splitting it into channels - * \param bufs num_bufs float buffers, each will contain the data of one channel - * \param cnt number of samples to read per channel - * \param num_bufs number of channels to split the data into - * \return number of samples read per channel, equals cnt unless there was too - * little data in the buffer - * - * Assumes the data in the buffer is of type float, the number of bytes - * read is res * num_bufs * sizeof(float), where res is the return value. - * If there is not enough data in the buffer remaining parts will be filled - * with silence. - */ -static int read_buffer(struct mp_ring *ring, float **bufs, int cnt, int num_bufs) -{ - struct deinterleave di = { - bufs, num_bufs, 0, 0 - }; - int buffered = mp_ring_buffered(ring); - if (cnt * sizeof(float) * num_bufs > buffered) { - silence(bufs, cnt, num_bufs); - cnt = buffered / sizeof(float) / num_bufs; - } - mp_ring_read_cb(ring, &di, cnt * num_bufs * sizeof(float), deinterleave); - return cnt; -} - -// end ring buffer stuff - /** * \brief fill the buffers with silence * \param bufs num_bufs float buffers, each will contain the data of one channel * \param cnt number of samples in each buffer * \param num_bufs number of buffers */ -static void silence(float **bufs, int cnt, int num_bufs) +static void +silence(float *buf, jack_nframes_t nframes) { - int i; - for (i = 0; i < num_bufs; i++) - memset(bufs[i], 0, cnt * sizeof(float)); + memset(buf, 0, nframes * sizeof(*buf)); +} + +static int +process_port(struct ao *ao, struct port_ring *pr, jack_nframes_t nframes) +{ + struct priv *p = ao->priv; + int buffered; + float *buf; + + buf = jack_port_get_buffer(pr->port, nframes); + + if (p->paused || p->underrun) { + silence(buf, nframes); + return 0; + } + + buffered = mp_ring_buffered(pr->ring) / sizeof(float); + if (buffered < nframes) { + mp_ring_read(pr->ring, (void *) buf, buffered * sizeof(float)); + silence(&buf[buffered], nframes - buffered); + return 1; + } + + mp_ring_read(pr->ring, (void *) buf, nframes * sizeof(float)); + return 0; } /** @@ -140,18 +114,23 @@ static void silence(float **bufs, int cnt, int num_bufs) * * Write silence into buffers if paused or an underrun occured */ -static int outputaudio(jack_nframes_t nframes, void *arg) +static int +process(jack_nframes_t nframes, void *arg) { struct ao *ao = arg; struct priv *p = ao->priv; - float *bufs[MAX_CHANS]; - int i; - for (i = 0; i < p->num_ports; i++) - bufs[i] = jack_port_get_buffer(p->ports[i], nframes); - if (p->paused || p->underrun || !p->ring) - silence(bufs, nframes, p->num_ports); - else if (read_buffer(p->ring, bufs, nframes, p->num_ports) < nframes) + int i, underrun; + + underrun = 0; + + for (i = 0; i < p->num_ports; i++) { + if (process_port(ao, &p->ports[i], nframes)) + underrun = 1; + } + + if (underrun) p->underrun = 1; + if (p->estimate) { float now = mp_time_us() / 1000000.0; float diff = p->callback_time + p->callback_interval - now; @@ -161,117 +140,163 @@ static int outputaudio(jack_nframes_t nframes, void *arg) p->callback_time = now; p->callback_interval = (float)nframes / (float)ao->samplerate; } + return 0; } -static int init(struct ao *ao) +static int +connect_to_outports(struct ao *ao) { struct priv *p = ao->priv; + + char *port_name = (p->cfg_port && p->cfg_port[0]) ? p->cfg_port : NULL; const char **matching_ports = NULL; - char *port_name = p->cfg_port && p->cfg_port[0] ? p->cfg_port : NULL; - jack_options_t open_options = JackNullOption; int port_flags = JackPortIsInput; int i; + if (!port_name) + port_flags |= JackPortIsPhysical; + + matching_ports = jack_get_ports(p->client, port_name, NULL, port_flags); + + if (!matching_ports || !matching_ports[0]) { + MP_FATAL(ao, "no ports to connect to\n"); + goto err_get_ports; + } + + for (i = 0; i < p->num_ports && matching_ports[i]; i++) { + if (jack_connect(p->client, jack_port_name(p->ports[i].port), + matching_ports[i])) { + MP_FATAL(ao, "connecting failed\n"); + goto err_connect; + } + } + + free(matching_ports); + return 0; + +err_connect: + free(matching_ports); +err_get_ports: + return -1; +} + +static int +create_ports(struct ao *ao, int nports) +{ + struct priv *p = ao->priv; + struct port_ring *pr; + char pname[30]; + int i; + + for (i = 0; i < nports; i++) { + pr = &p->ports[i]; + + snprintf(pname, sizeof(pname), "out_%d", i); + pr->port = jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + + if (!pr->port) { + MP_FATAL(ao, "not enough ports available\n"); + goto err_port_register; + } + + pr->ring = mp_ring_new(p, NUM_CHUNKS * CHUNK_SIZE); + } + + p->num_ports = nports; + return 0; + +err_port_register: + return -1; +} + +static int init(struct ao *ao) +{ + struct priv *p = ao->priv; struct mp_chmap_sel sel = {0}; + jack_options_t open_options; - if (p->stdlayout == 0) { + ao->format = AF_FORMAT_FLOATP; + + switch (p->stdlayout) { + case 0: mp_chmap_sel_add_waveext(&sel); - } else if (p->stdlayout == 1) { + break; + + case 1: mp_chmap_sel_add_alsa_def(&sel); - } else { + break; + + default: mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) - goto err_out; + goto err_chmap; + open_options = JackNullOption; if (!p->autostart) open_options |= JackNoStartServer; + p->client = jack_client_open(p->cfg_client_name, open_options, NULL); if (!p->client) { MP_FATAL(ao, "cannot open server\n"); - goto err_out; - } - jack_set_process_callback(p->client, outputaudio, ao); - - // list matching ports if connections should be made - if (p->connect) { - if (!port_name) - port_flags |= JackPortIsPhysical; - matching_ports = jack_get_ports(p->client, port_name, NULL, port_flags); - if (!matching_ports || !matching_ports[0]) { - MP_FATAL(ao, "no physical ports available\n"); - goto err_out; - } - i = 1; - p->num_ports = ao->channels.num; - while (matching_ports[i]) - i++; - if (p->num_ports > i) - p->num_ports = i; + goto err_client_open; } - // create out output ports - for (i = 0; i < p->num_ports; i++) { - char pname[30]; - snprintf(pname, 30, "out_%d", i); - p->ports[i] = - jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - if (!p->ports[i]) { - MP_FATAL(ao, "not enough ports available\n"); - goto err_out; - } - } + if (create_ports(ao, ao->channels.num)) + goto err_create_ports; + + jack_set_process_callback(p->client, process, ao); + if (jack_activate(p->client)) { MP_FATAL(ao, "activate failed\n"); - goto err_out; - } - for (i = 0; i < p->num_ports; i++) { - if (jack_connect(p->client, jack_port_name(p->ports[i]), - matching_ports[i])) - { - MP_FATAL(ao, "connecting failed\n"); - goto err_out; - } + goto err_activate; } + ao->samplerate = jack_get_sample_rate(p->client); + + if (p->connect) + if (connect_to_outports(ao)) + goto err_connect; + jack_latency_range_t jack_latency_range; - jack_port_get_latency_range(p->ports[0], JackPlaybackLatency, + jack_port_get_latency_range(p->ports[0].port, JackPlaybackLatency, &jack_latency_range); p->jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(p->client)) / (float)ao->samplerate; p->callback_interval = 0; if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, p->num_ports)) - goto err_out; + goto err_chmap_sel_get_def; - ao->format = AF_FORMAT_FLOAT_NE; - int unitsize = ao->channels.num * sizeof(float); - p->outburst = (CHUNK_SIZE + unitsize - 1) / unitsize * unitsize; - p->ring = mp_ring_new(p, NUM_CHUNKS * p->outburst); - free(matching_ports); return 0; -err_out: - free(matching_ports); - if (p->client) - jack_client_close(p->client); +err_chmap_sel_get_def: +err_connect: + jack_deactivate(p->client); +err_activate: +err_create_ports: + jack_client_close(p->client); +err_client_open: +err_chmap: return -1; } static float get_delay(struct ao *ao) { struct priv *p = ao->priv; - int buffered = mp_ring_buffered(p->ring); // could be less + int buffered = mp_ring_buffered(p->ports[0].ring); // could be less float in_jack = p->jack_latency; + if (p->estimate && p->callback_interval > 0) { float elapsed = mp_time_us() / 1000000.0 - p->callback_time; in_jack += p->callback_interval - elapsed; if (in_jack < 0) in_jack = 0; } + return (float)buffered / (float)ao->bps + in_jack; } @@ -281,8 +306,12 @@ static float get_delay(struct ao *ao) static void reset(struct ao *ao) { struct priv *p = ao->priv; + int i; p->paused = 1; - mp_ring_reset(p->ring); + + for (i = 0; i < p->num_ports; i++) + mp_ring_reset(p->ports[i].ring); + p->paused = 0; } @@ -290,10 +319,10 @@ static void reset(struct ao *ao) static void uninit(struct ao *ao, bool immed) { struct priv *p = ao->priv; + if (!immed) mp_sleep_us(get_delay(ao) * 1000 * 1000); - // HACK, make sure jack doesn't loop-output dirty buffers - reset(ao); + mp_sleep_us(100 * 1000); jack_client_close(p->client); } @@ -319,19 +348,28 @@ static void audio_resume(struct ao *ao) static int get_space(struct ao *ao) { struct priv *p = ao->priv; - return mp_ring_available(p->ring); + return mp_ring_available(p->ports[0].ring) / ao->sstride; } /** * \brief write data into buffer and reset underrun flag */ -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; - if (!(flags & AOPLAY_FINAL_CHUNK)) - len -= len % p->outburst; + struct port_ring *pr; + int i, len, ret; + + len = samples * ao->sstride; + ret = 0; + + for (i = 0; i < p->num_ports; i++) { + pr = &p->ports[i]; + ret = mp_ring_write(pr->ring, data[i], len); + } + p->underrun = 0; - return mp_ring_write(p->ring, data, len); + return ret / ao->sstride; } #define OPT_BASE_STRUCT struct priv @@ -360,7 +398,7 @@ const struct ao_driver audio_out_jack = { OPT_FLAG("autostart", autostart, 0), OPT_FLAG("connect", connect, 0), OPT_CHOICE("std-channel-layout", stdlayout, 0, - ({"waveext", 0}, {"alsa", 1}, {"any", 2})), + ({"waveext", 0}, {"alsa", 1}, {"any", 2})), {0} }, }; diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index 153d5b92a0..c1fce6a715 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -103,6 +103,7 @@ static int init(struct ao *ao) ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE; + ao->format = af_fmt_from_planar(ao->format); { // first check if the selected format is somewhere in the list of @@ -290,8 +291,6 @@ static void fill_with_padding(void *buf, int cnt, int sz, const void *padding) } // close audio device -static int encode(struct ao *ao, double apts, void *data); -static int play(struct ao *ao, void *data, int len, int flags); static void uninit(struct ao *ao, bool cut_audio) { struct encode_lavc_context *ectx = ao->encode_lavc_ctx; @@ -309,7 +308,7 @@ static int get_space(struct ao *ao) { struct priv *ac = ao->priv; - return ac->aframesize * ac->sample_size * ao->channels.num * ac->framecount; + return ac->aframesize * ac->framecount; } // must get exactly ac->aframesize amount of data @@ -438,10 +437,10 @@ static int encode(struct ao *ao, double apts, void *data) return packet.size; } -// plays 'len' bytes of 'data' +// plays 'samples' samples of 'ni_data[0]' // it should round it down to frame sizes -// return: number of bytes played -static int play(struct ao *ao, void *data, int len, int flags) +// return: number of samples played +static int play(struct ao *ao, void **ni_data, int samples, int flags) { struct priv *ac = ao->priv; struct encode_lavc_context *ectx = ao->encode_lavc_ctx; @@ -450,6 +449,8 @@ static int play(struct ao *ao, void *data, int len, int flags) double nextpts; double pts = ao->pts; double outpts; + void *data = ni_data[0]; + int len = samples * ao->sstride; int bytelen = len; len /= ac->sample_size * ao->channels.num; @@ -470,8 +471,9 @@ static int play(struct ao *ao, void *data, int len, int flags) extralen / ac->sample_size, ac->sample_size, ac->sample_padding); // No danger of recursion, because AOPLAY_FINAL_CHUNK not set - written = play(ao, paddingbuf, bytelen + extralen, 0); - if (written < bytelen) { + written = + play(ao, &paddingbuf, (bytelen + extralen) / ao->sstride, 0); + if (written * ao->sstride < bytelen) { MP_ERR(ao, "did not write enough data at the end\n"); } talloc_free(paddingbuf); @@ -485,7 +487,7 @@ static int play(struct ao *ao, void *data, int len, int flags) while (encode(ao, outpts, NULL) > 0) ; - return FFMIN(written, bytelen); + return (FFMIN(written, bytelen)) / ao->sstride; } if (pts == MP_NOPTS_VALUE) { @@ -576,7 +578,7 @@ static int play(struct ao *ao, void *data, int len, int flags) ectx->next_in_pts = nextpts; } - return bufpos * ac->sample_size * ao->channels.num; + return bufpos; } const struct ao_driver audio_out_lavc = { diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c index ff6b12a1a6..9fe289e3e4 100644 --- a/audio/out/ao_null.c +++ b/audio/out/ao_null.c @@ -30,7 +30,8 @@ struct priv { double last_time; - float buffered_bytes; + // All values are in samples + float buffered; int buffersize; int outburst; }; @@ -40,9 +41,9 @@ static void drain(struct ao *ao) struct priv *priv = ao->priv; double now = mp_time_sec(); - priv->buffered_bytes -= (now - priv->last_time) * ao->bps; - if (priv->buffered_bytes < 0) - priv->buffered_bytes = 0; + priv->buffered -= (now - priv->last_time) * ao->samplerate; + if (priv->buffered < 0) + priv->buffered = 0; priv->last_time = now; } @@ -56,10 +57,15 @@ static int init(struct ao *ao) if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) return -1; - int samplesize = af_fmt2bits(ao->format) / 8; - priv->outburst = 256 * ao->channels.num * samplesize; + // Minimal unit of audio samples that can be written at once. If play() is + // called with sizes not aligned to this, a rounded size will be returned. + // (This is not needed by the AO API, but many AOs behave this way.) + priv->outburst = 256; + // A "buffer" for about 0.2 seconds of audio - priv->buffersize = (int)(ao->samplerate * 0.2 / 256 + 1) * priv->outburst; + int bursts = (int)(ao->samplerate * 0.2 + 1) / priv->outburst; + priv->buffersize = priv->outburst * bursts; + priv->last_time = mp_time_sec(); return 0; @@ -74,7 +80,7 @@ static void uninit(struct ao *ao, bool cut_audio) static void reset(struct ao *ao) { struct priv *priv = ao->priv; - priv->buffered_bytes = 0; + priv->buffered = 0; } // stop playing, keep buffers (for pause) @@ -94,17 +100,17 @@ static int get_space(struct ao *ao) struct priv *priv = ao->priv; drain(ao); - return priv->buffersize - priv->buffered_bytes; + return priv->buffersize - priv->buffered; } -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; - int maxbursts = (priv->buffersize - priv->buffered_bytes) / priv->outburst; - int playbursts = len / priv->outburst; + int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst; + int playbursts = samples / priv->outburst; int bursts = playbursts > maxbursts ? maxbursts : playbursts; - priv->buffered_bytes += bursts * priv->outburst; + priv->buffered += bursts * priv->outburst; return bursts * priv->outburst; } @@ -113,7 +119,7 @@ static float get_delay(struct ao *ao) struct priv *priv = ao->priv; drain(ao); - return priv->buffered_bytes / ao->bps; + return priv->buffered / (double)ao->samplerate; } const struct ao_driver audio_out_null = { diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c index 6fdc388711..c126852389 100644 --- a/audio/out/ao_openal.c +++ b/audio/out/ao_openal.c @@ -45,12 +45,12 @@ #define MAX_CHANS MP_NUM_CHANNELS #define NUM_BUF 128 #define CHUNK_SIZE 512 +#define CHUNK_SAMPLES (CHUNK_SIZE / 2) static ALuint buffers[MAX_CHANS][NUM_BUF]; static ALuint sources[MAX_CHANS]; static int cur_buf[MAX_CHANS]; static int unqueue_buf[MAX_CHANS]; -static int16_t *tmpbuf; static struct ao *ao_data; @@ -169,8 +169,7 @@ static int init(struct ao *ao) alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq); if (alcGetError(dev) == ALC_NO_ERROR && freq) ao->samplerate = freq; - ao->format = AF_FORMAT_S16_NE; - tmpbuf = malloc(CHUNK_SIZE); + ao->format = AF_FORMAT_S16P; return 0; err_out: @@ -182,7 +181,6 @@ static void uninit(struct ao *ao, bool immed) { ALCcontext *ctx = alcGetCurrentContext(); ALCdevice *dev = alcGetContextsDevice(ctx); - free(tmpbuf); if (!immed) { ALint state; alGetSourcei(sources[0], AL_SOURCE_STATE, &state); @@ -251,34 +249,30 @@ static int get_space(struct ao *ao) queued = NUM_BUF - queued - 3; if (queued < 0) return 0; - return queued * CHUNK_SIZE * ao->channels.num; + return queued * CHUNK_SAMPLES; } /** * \brief write data into buffer and reset underrun flag */ -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { ALint state; - int i, j, k; - int ch; - int16_t *d = data; - len /= ao->channels.num * CHUNK_SIZE; - for (i = 0; i < len; i++) { - for (ch = 0; ch < ao->channels.num; ch++) { - for (j = 0, k = ch; j < CHUNK_SIZE / 2; j++, k += ao->channels.num) - tmpbuf[j] = d[k]; - alBufferData(buffers[ch][cur_buf[ch]], AL_FORMAT_MONO16, tmpbuf, + int num = samples / CHUNK_SAMPLES; + for (int i = 0; i < num; i++) { + for (int ch = 0; ch < ao->channels.num; ch++) { + int16_t *d = data[ch]; + d += i * CHUNK_SAMPLES; + alBufferData(buffers[ch][cur_buf[ch]], AL_FORMAT_MONO16, d, CHUNK_SIZE, ao->samplerate); alSourceQueueBuffers(sources[ch], 1, &buffers[ch][cur_buf[ch]]); cur_buf[ch] = (cur_buf[ch] + 1) % NUM_BUF; } - d += ao->channels.num * CHUNK_SIZE / 2; } alGetSourcei(sources[0], AL_SOURCE_STATE, &state); if (state != AL_PLAYING) // checked here in case of an underrun alSourcePlayv(ao->channels.num, sources); - return len * ao->channels.num * CHUNK_SIZE; + return num * CHUNK_SAMPLES; } static float get_delay(struct ao *ao) @@ -286,7 +280,7 @@ static float get_delay(struct ao *ao) ALint queued; unqueue_buffers(); alGetSourcei(sources[0], AL_BUFFERS_QUEUED, &queued); - return queued * CHUNK_SIZE / 2 / (float)ao->samplerate; + return queued * CHUNK_SAMPLES / (float)ao->samplerate; } #define OPT_BASE_STRUCT struct priv diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index db9847851d..09a2951629 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -261,6 +261,8 @@ static int init(struct ao *ao) fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC); #endif + ao->format = af_fmt_from_planar(ao->format); + if (AF_FORMAT_IS_AC3(ao->format)) { ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate); } @@ -455,7 +457,7 @@ static int get_space(struct ao *ao) if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) != -1) { // calculate exact buffer space: playsize = p->zz.fragments * p->zz.fragsize; - return playsize; + return playsize / ao->sstride; } #endif @@ -473,14 +475,14 @@ static int get_space(struct ao *ao) } #endif - return p->outburst; + return p->outburst / ao->sstride; } // stop playing, keep buffers (for pause) static void audio_pause(struct ao *ao) { struct priv *p = ao->priv; - p->prepause_space = get_space(ao); + p->prepause_space = get_space(ao) * ao->sstride; #ifdef SNDCTL_DSP_RESET ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL); #else @@ -491,17 +493,18 @@ static void audio_pause(struct ao *ao) // plays 'len' bytes of 'data' // it should round it down to outburst*n // return: number of bytes played -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; + int len = samples * ao->sstride; if (len == 0) return len; if (len > p->outburst || !(flags & AOPLAY_FINAL_CHUNK)) { len /= p->outburst; len *= p->outburst; } - len = write(p->audio_fd, data, len); - return len; + len = write(p->audio_fd, data[0], len); + return len / ao->sstride; } // resume playing, after audio_pause() @@ -511,8 +514,7 @@ static void audio_resume(struct ao *ao) #ifndef SNDCTL_DSP_RESET reset(ao); #endif - int fillframes = (get_space(ao) - p->prepause_space) / - (af_fmt2bits(ao->format) / 8 * ao->channels.num); + int fillframes = get_space(ao) - p->prepause_space / ao->sstride; if (fillframes > 0) ao_play_silence(ao, fillframes); } diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c index f7d793700d..1d88fc6665 100644 --- a/audio/out/ao_pcm.c +++ b/audio/out/ao_pcm.c @@ -118,6 +118,9 @@ static int init(struct ao *ao) if (!priv->outputfilename) priv->outputfilename = talloc_strdup(priv, priv->waveheader ? "audiodump.wav" : "audiodump.pcm"); + + ao->format = af_fmt_from_planar(ao->format); + if (priv->waveheader) { // WAV files must have one of the following formats @@ -193,13 +196,14 @@ static int get_space(struct ao *ao) return 65536; } -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; + int len = samples * ao->sstride; - fwrite(data, len, 1, priv->fp); + fwrite(data[0], len, 1, priv->fp); priv->data_length += len; - return len; + return len / ao->sstride; } #define OPT_BASE_STRUCT struct priv diff --git a/audio/out/ao_portaudio.c b/audio/out/ao_portaudio.c index 8b235f8806..9c0d7804f8 100644 --- a/audio/out/ao_portaudio.c +++ b/audio/out/ao_portaudio.c @@ -242,6 +242,8 @@ static int init(struct ao *ao) = Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency, }; + ao->format = af_fmt_from_planar(ao->format); + const struct format_map *fmt = format_maps; while (fmt->pa_format) { if (fmt->mp_format == ao->format) { @@ -278,13 +280,13 @@ error_exit: return -1; } -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; pthread_mutex_lock(&priv->ring_mutex); - int write_len = mp_ring_write(priv->ring, data, len); + int write_len = mp_ring_write(priv->ring, data[0], samples * ao->sstride); if (flags & AOPLAY_FINAL_CHUNK) priv->play_remaining = true; @@ -293,7 +295,7 @@ static int play(struct ao *ao, void *data, int len, int flags) if (Pa_IsStreamStopped(priv->stream) == 1) check_pa_ret(Pa_StartStream(priv->stream)); - return write_len; + return write_len / ao->sstride; } static int get_space(struct ao *ao) @@ -306,7 +308,7 @@ static int get_space(struct ao *ao) pthread_mutex_unlock(&priv->ring_mutex); - return free; + return free / ao->sstride; } static float get_delay(struct ao *ao) diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index a4da2a179b..f1800f279c 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -286,6 +286,8 @@ static int init(struct ao *ao) ss.channels = ao->channels.num; ss.rate = ao->samplerate; + ao->format = af_fmt_from_planar(ao->format); + const struct format_map *fmt_map = format_maps; while (fmt_map->mp_format != ao->format) { if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { @@ -375,14 +377,14 @@ static void cork(struct ao *ao, bool pause) } // Play the specified data to the pulseaudio server -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); - if (pa_stream_write(priv->stream, data, len, NULL, 0, + if (pa_stream_write(priv->stream, data[0], samples * ao->sstride, NULL, 0, PA_SEEK_RELATIVE) < 0) { GENERIC_ERR_MSG("pa_stream_write() failed"); - len = -1; + samples = -1; } if (flags & AOPLAY_FINAL_CHUNK) { // Force start in case the stream was too short for prebuf @@ -390,7 +392,7 @@ static int play(struct ao *ao, void *data, int len, int flags) pa_operation_unref(op); } pa_threaded_mainloop_unlock(priv->mainloop); - return len; + return samples; } // Reset the audio stream, i.e. flush the playback buffer on the server side @@ -425,14 +427,14 @@ static void resume(struct ao *ao) cork(ao, false); } -// Return number of bytes that may be written to the server without blocking +// Return number of samples that may be written to the server without blocking static int get_space(struct ao *ao) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); size_t space = pa_stream_writable_size(priv->stream); pa_threaded_mainloop_unlock(priv->mainloop); - return space; + return space / ao->sstride; } // Return the current latency in seconds diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c index 162fb21feb..123ee14ef5 100644 --- a/audio/out/ao_rsound.c +++ b/audio/out/ao_rsound.c @@ -114,6 +114,8 @@ static int init(struct ao *ao) rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate); rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels.num); + ao->format = af_fmt_from_planar(ao->format); + int rsd_format = set_format(ao); rsd_set_param(priv->rd, RSD_FORMAT, &rsd_format); @@ -161,13 +163,13 @@ static void audio_resume(struct ao *ao) static int get_space(struct ao *ao) { struct priv *priv = ao->priv; - return rsd_get_avail(priv->rd); + return rsd_get_avail(priv->rd) / ao->sstride; } -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; - return rsd_write(priv->rd, data, len); + return rsd_write(priv->rd, data[0], samples * ao->sstride) / ao->sstride; } static float get_delay(struct ao *ao) diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c index a42c0812cb..c2b1c9d947 100644 --- a/audio/out/ao_sdl.c +++ b/audio/out/ao_sdl.c @@ -144,6 +144,8 @@ static int init(struct ao *ao) return -1; } + ao->format = af_fmt_from_planar(ao->format); + SDL_AudioSpec desired, obtained; switch (ao->format) { @@ -259,7 +261,7 @@ static int get_space(struct ao *ao) SDL_LockMutex(priv->buffer_mutex); int space = av_fifo_space(priv->buffer); SDL_UnlockMutex(priv->buffer_mutex); - return space; + return space / ao->sstride; } static void pause(struct ao *ao) @@ -290,20 +292,21 @@ static void resume(struct ao *ao) do_resume(ao); } -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; + int len = samples * ao->sstride; SDL_LockMutex(priv->buffer_mutex); int free = av_fifo_space(priv->buffer); if (len > free) len = free; - av_fifo_generic_write(priv->buffer, data, len, NULL); + av_fifo_generic_write(priv->buffer, data[0], len, NULL); SDL_CondSignal(priv->underrun_cond); SDL_UnlockMutex(priv->buffer_mutex); if (priv->unpause) { priv->unpause = 0; do_resume(ao); } - return len; + return len / ao->sstride; } static float get_delay(struct ao *ao) diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c index ab9eaf8197..cfe0616943 100644 --- a/audio/out/ao_sndio.c +++ b/audio/out/ao_sndio.c @@ -130,6 +130,9 @@ static int init(struct ao *ao) MP_ERR(ao, "can't open sndio %s\n", p->dev); goto error; } + + ao->format = af_fmt_from_planar(ao->format); + sio_initpar(&p->par); for (i = 0, ap = af_to_par;; i++, ap++) { if (i == sizeof(af_to_par) / sizeof(struct af_to_par)) { @@ -239,16 +242,16 @@ static void reset(struct ao *ao) /* * play given number of bytes until sio_write() blocks */ -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; int n; - n = sio_write(p->hdl, data, len); + n = sio_write(p->hdl, data[0], samples * ao->sstride); p->delay += n; if (flags & AOPLAY_FINAL_CHUNK) reset(ao); - return n; + return n / ao->sstride; } /* @@ -268,7 +271,7 @@ static int get_space(struct ao *ao) ; /* nothing */ sio_revents(p->hdl, p->pfd); - return p->par.bufsz * p->par.pchan * p->par.bps - p->delay; + return (p->par.bufsz * p->par.pchan * p->par.bps - p->delay) / ao->sstride; } /* diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index c605e1cd5d..b43bf04753 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -1197,7 +1197,7 @@ static int get_space(struct ao *ao) if (!ao || !ao->priv) return -1; struct wasapi_state *state = (struct wasapi_state *)ao->priv; - return mp_ring_available(state->ringbuff); + return mp_ring_available(state->ringbuff) / ao->sstride; } static void reset_buffers(struct wasapi_state *state) @@ -1231,6 +1231,7 @@ static void uninit(struct ao *ao, bool immed) static int init(struct ao *ao) { mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: init!\n"); + ao->format = af_fmt_from_planar(ao->format); struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) @@ -1338,25 +1339,24 @@ static void reset(struct ao *ao) reset_buffers(state); } -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { - int ret = 0; if (!ao || !ao->priv) - return ret; + return 0; struct wasapi_state *state = (struct wasapi_state *)ao->priv; if (WaitForSingleObject(state->fatal_error, 0) == WAIT_OBJECT_0) { /* something bad happened */ - return ret; + return 0; } - ret = mp_ring_write(state->ringbuff, data, len); + int ret = mp_ring_write(state->ringbuff, data[0], samples * ao->sstride); if (!state->is_playing) { /* start playing */ state->is_playing = 1; SetEvent(state->hPlay); } - return ret; + return ret / ao->sstride; } static float get_delay(struct ao *ao) diff --git a/audio/reorder_ch.c b/audio/reorder_ch.c index 57cb664a6f..b99731e6bf 100644 --- a/audio/reorder_ch.c +++ b/audio/reorder_ch.c @@ -63,38 +63,6 @@ void reorder_to_planar(void *restrict out, const void *restrict in, reorder_to_planar_(out, in, size, nchan, nmemb); } -static inline void reorder_to_packed_(uint8_t *out, uint8_t **in, - size_t size, size_t nchan, size_t nmemb) -{ - size_t outstep = nchan * size; - - for (size_t c = 0; c < nchan; ++c) { - char *outptr = out + c * size; - char *inptr = in[c]; - for (size_t i = 0; i < nmemb; ++i, outptr += outstep, inptr += size) { - memcpy(outptr, inptr, size); - } - } -} - -// out = destination array of packed samples of given size, nmemb frames -// in[channel] = source array of samples for the given channel -void reorder_to_packed(uint8_t *out, uint8_t **in, - size_t size, size_t nchan, size_t nmemb) -{ - if (nchan == 1) - memcpy(out, in, size * nchan * nmemb); - // See reorder_to_planar() why this is done this way - else if (size == 1) - reorder_to_packed_(out, in, 1, nchan, nmemb); - else if (size == 2) - reorder_to_packed_(out, in, 2, nchan, nmemb); - else if (size == 4) - reorder_to_packed_(out, in, 4, nchan, nmemb); - else - reorder_to_packed_(out, in, size, nchan, nmemb); -} - #define MAX_SAMPLESIZE 8 static void reorder_channels_(uint8_t *restrict data, int *restrict ch_order, diff --git a/audio/reorder_ch.h b/audio/reorder_ch.h index 6b5902c1b6..d81aab7dfa 100644 --- a/audio/reorder_ch.h +++ b/audio/reorder_ch.h @@ -27,8 +27,6 @@ void reorder_to_planar(void *restrict out, const void *restrict in, size_t size, size_t nchan, size_t nmemb); -void reorder_to_packed(uint8_t *out, uint8_t **in, - size_t size, size_t nchan, size_t nmemb); void reorder_channels(void *restrict data, int *restrict ch_order, size_t sample_size, size_t num_ch, size_t num_frames); @@ -2598,13 +2598,11 @@ fi echores "$_zlib" -# Any version of libmpg123 that knows MPG123_RESYNC_LIMIT shall be fine. -# That is, 1.2.0 onwards. Recommened is 1.14 onwards, though. echocheck "mpg123 support" def_mpg123='#define HAVE_MPG123 0' if test "$_mpg123" = auto; then _mpg123=no - pkg_config_add 'libmpg123 >= 1.2.0' && _mpg123=yes + pkg_config_add 'libmpg123 >= 1.14.0' && _mpg123=yes fi if test "$_mpg123" = yes ; then def_mpg123='#define HAVE_MPG123 1' diff --git a/demux/demux.c b/demux/demux.c index 4e5f83f8ab..da5957efdd 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -255,7 +255,6 @@ struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type) struct sh_audio *sht = talloc_zero(demuxer, struct sh_audio); sht->gsh = sh; sht->opts = sh->opts; - sht->sample_format = AF_FORMAT_S16_NE; sh->audio = sht; break; } diff --git a/demux/stheader.h b/demux/stheader.h index 5aa77ba693..c88ed0b0f7 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -92,11 +92,8 @@ typedef struct sh_audio { int samplerate; struct mp_chmap channels; int i_bps; // == bitrate (compressed bytes/sec) - // decoder buffers: - int audio_out_minsize; // minimal output from decoder may be this much - char *a_buffer; // buffer for decoder output - int a_buffer_len; - int a_buffer_size; + // decoder state: + struct mp_audio_buffer *decode_buffer; struct af_stream *afilter; // the audio filter stream const struct ad_functions *ad_driver; // win32-compatible codec parameters: @@ -104,7 +101,7 @@ typedef struct sh_audio { // note codec extradata may be either under "wf" or "codecdata" unsigned char *codecdata; int codecdata_len; - int pts_bytes; // bytes output by decoder after last known pts + int pts_offset; // number of samples output by decoder after last known pts } sh_audio_t; typedef struct sh_video { diff --git a/mpvcore/player/audio.c b/mpvcore/player/audio.c index e0c35c628e..a13e8d9c07 100644 --- a/mpvcore/player/audio.c +++ b/mpvcore/player/audio.c @@ -30,6 +30,8 @@ #include "mpvcore/mp_common.h" #include "audio/mixer.h" +#include "audio/audio.h" +#include "audio/audio_buffer.h" #include "audio/decode/dec_audio.h" #include "audio/filter/af.h" #include "audio/out/ao.h" @@ -147,7 +149,11 @@ void reinit_audio_chain(struct MPContext *mpctx) MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n"); goto init_error; } - ao->buffer.start = talloc_new(ao); + + ao->buffer = mp_audio_buffer_create(ao); + mp_audio_buffer_reinit_fmt(ao->buffer, ao->format, &ao->channels, + ao->samplerate); + char *s = mp_audio_fmt_to_str(ao->samplerate, &ao->channels, ao->format); MP_INFO(mpctx, "AO: [%s] %s\n", ao->driver->name, s); talloc_free(s); @@ -174,12 +180,9 @@ no_audio: double written_audio_pts(struct MPContext *mpctx) { sh_audio_t *sh_audio = mpctx->sh_audio; - if (!sh_audio) + if (!sh_audio || !sh_audio->initialized) return MP_NOPTS_VALUE; - double bps = sh_audio->channels.num * sh_audio->samplerate * - (af_fmt2bits(sh_audio->sample_format) / 8); - // first calculate the end pts of audio that has been output by decoder double a_pts = sh_audio->pts; if (a_pts == MP_NOPTS_VALUE) @@ -188,24 +191,24 @@ double written_audio_pts(struct MPContext *mpctx) // sh_audio->pts is the timestamp of the latest input packet with // known pts that the decoder has decoded. sh_audio->pts_bytes is // the amount of bytes the decoder has written after that timestamp. - a_pts += sh_audio->pts_bytes / bps; + a_pts += sh_audio->pts_offset / (double)sh_audio->samplerate; // Now a_pts hopefully holds the pts for end of audio from decoder. // Subtract data in buffers between decoder and audio out. // Decoded but not filtered - a_pts -= sh_audio->a_buffer_len / bps; + a_pts -= mp_audio_buffer_seconds(sh_audio->decode_buffer); - // Data buffered in audio filters, measured in bytes of "missing" output + // Data buffered in audio filters, measured in seconds of "missing" output double buffered_output = af_calc_delay(sh_audio->afilter); // Data that was ready for ao but was buffered because ao didn't fully // accept everything to internal buffers yet - buffered_output += mpctx->ao->buffer.len; + buffered_output += mp_audio_buffer_seconds(mpctx->ao->buffer); // Filters divide audio length by playback_speed, so multiply by it // to get the length in original units without speedup or slowdown - a_pts -= buffered_output * mpctx->opts->playback_speed / mpctx->ao->bps; + a_pts -= buffered_output * mpctx->opts->playback_speed; return a_pts + mpctx->video_offset; } @@ -219,29 +222,42 @@ double playing_audio_pts(struct MPContext *mpctx) return pts - mpctx->opts->playback_speed * ao_get_delay(mpctx->ao); } -static int write_to_ao(struct MPContext *mpctx, void *data, int len, int flags, +static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags, double pts) { if (mpctx->paused) return 0; struct ao *ao = mpctx->ao; - double bps = ao->bps / mpctx->opts->playback_speed; - int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8; ao->pts = pts; - int played = ao_play(mpctx->ao, data, len, flags); - assert(played <= len); - assert(played % unitsize == 0); + double real_samplerate = ao->samplerate / mpctx->opts->playback_speed; + int played = ao_play(mpctx->ao, data->planes, data->samples, flags); + assert(played <= data->samples); if (played > 0) { - mpctx->shown_aframes += played / unitsize; - mpctx->delay += played / bps; + mpctx->shown_aframes += played; + mpctx->delay += played / real_samplerate; // Keep correct pts for remaining data - could be used to flush // remaining buffer when closing ao. - ao->pts += played / bps; + ao->pts += played / real_samplerate; return played; } return 0; } +static int write_silence_to_ao(struct MPContext *mpctx, int samples, int flags, + double pts) +{ + struct mp_audio tmp = {0}; + mp_audio_buffer_get_format(mpctx->ao->buffer, &tmp); + tmp.samples = samples; + char *p = talloc_size(NULL, tmp.samples * tmp.sstride); + for (int n = 0; n < tmp.num_planes; n++) + tmp.planes[n] = p; + mp_audio_fill_silence(&tmp, 0, tmp.samples); + int r = write_to_ao(mpctx, &tmp, 0, pts); + talloc_free(p); + return r; +} + #define ASYNC_PLAY_DONE -3 static int audio_start_sync(struct MPContext *mpctx, int playsize) { @@ -251,14 +267,14 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize) int res; // Timing info may not be set without - res = decode_audio(sh_audio, &ao->buffer, 1); + res = decode_audio(sh_audio, ao->buffer, 1); if (res < 0) return res; - int bytes; + int samples; bool did_retry = false; double written_pts; - double bps = ao->bps / opts->playback_speed; + double real_samplerate = ao->samplerate / opts->playback_speed; bool hrseek = mpctx->hrseek_active; // audio only hrseek mpctx->hrseek_active = false; while (1) { @@ -269,64 +285,56 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize) else ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay - mpctx->audio_delay; - bytes = ptsdiff * bps; - bytes -= bytes % (ao->channels.num * af_fmt2bits(ao->format) / 8); + samples = ptsdiff * real_samplerate; // ogg demuxers give packets without timing if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) { if (!did_retry) { // Try to read more data to see packets that have pts - res = decode_audio(sh_audio, &ao->buffer, ao->bps); + res = decode_audio(sh_audio, ao->buffer, ao->samplerate); if (res < 0) return res; did_retry = true; continue; } - bytes = 0; + samples = 0; } if (fabs(ptsdiff) > 300 || isnan(ptsdiff)) // pts reset or just broken? - bytes = 0; + samples = 0; - if (bytes > 0) + if (samples > 0) break; mpctx->syncing_audio = false; - int a = MPMIN(-bytes, MPMAX(playsize, 20000)); - res = decode_audio(sh_audio, &ao->buffer, a); - bytes += ao->buffer.len; - if (bytes >= 0) { - memmove(ao->buffer.start, - ao->buffer.start + ao->buffer.len - bytes, bytes); - ao->buffer.len = bytes; + int skip_samples = -samples; + int a = MPMIN(skip_samples, MPMAX(playsize, 2500)); + res = decode_audio(sh_audio, ao->buffer, a); + if (skip_samples <= mp_audio_buffer_samples(ao->buffer)) { + mp_audio_buffer_skip(ao->buffer, skip_samples); if (res < 0) return res; - return decode_audio(sh_audio, &ao->buffer, playsize); + return decode_audio(sh_audio, ao->buffer, playsize); } - ao->buffer.len = 0; + mp_audio_buffer_clear(ao->buffer); if (res < 0) return res; } if (hrseek) // Don't add silence in audio-only case even if position is too late return 0; - int fillbyte = 0; - if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) - fillbyte = 0x80; - if (bytes >= playsize) { + if (samples >= playsize) { /* This case could fall back to the one below with - * bytes = playsize, but then silence would keep accumulating - * in a_out_buffer if the AO accepts less data than it asks for + * samples = playsize, but then silence would keep accumulating + * in ao->buffer if the AO accepts less data than it asks for * in playsize. */ - char *p = malloc(playsize); - memset(p, fillbyte, playsize); - write_to_ao(mpctx, p, playsize, 0, written_pts - bytes / bps); - free(p); + write_silence_to_ao(mpctx, playsize, 0, + written_pts - samples / real_samplerate); return ASYNC_PLAY_DONE; } mpctx->syncing_audio = false; - decode_audio_prepend_bytes(&ao->buffer, bytes, fillbyte); - return decode_audio(sh_audio, &ao->buffer, playsize); + mp_audio_buffer_prepend_silence(ao->buffer, samples); + return decode_audio(sh_audio, ao->buffer, playsize); } int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) @@ -340,7 +348,6 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) bool partial_fill = false; sh_audio_t * const sh_audio = mpctx->sh_audio; bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK); - int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8; if (mpctx->paused) playsize = 1; // just initialize things (audio pts at least) @@ -359,7 +366,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) if (mpctx->syncing_audio || mpctx->hrseek_active) res = audio_start_sync(mpctx, playsize); else - res = decode_audio(sh_audio, &ao->buffer, playsize); + res = decode_audio(sh_audio, ao->buffer, playsize); if (res < 0) { // EOF, error or format change if (res == -2) { @@ -378,21 +385,19 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) } if (endpts != MP_NOPTS_VALUE && modifiable_audio_format) { - double bytes = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay) - * ao->bps / opts->playback_speed; - if (playsize > bytes) { - playsize = MPMAX(bytes, 0); + double samples = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay) + * ao->samplerate / opts->playback_speed; + if (playsize > samples) { + playsize = MPMAX(samples, 0); audio_eof = true; partial_fill = true; } } - assert(ao->buffer.len % unitsize == 0); - if (playsize > ao->buffer.len) { + if (playsize > mp_audio_buffer_samples(ao->buffer)) { + playsize = mp_audio_buffer_samples(ao->buffer); partial_fill = true; - playsize = ao->buffer.len; } - playsize -= playsize % unitsize; if (!playsize) return partial_fill && audio_eof ? -2 : -partial_fill; @@ -406,14 +411,16 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) } } - assert(ao->buffer_playable_size <= ao->buffer.len); - int played = write_to_ao(mpctx, ao->buffer.start, playsize, playflags, - written_audio_pts(mpctx)); - ao->buffer_playable_size = playsize - played; + assert(ao->buffer_playable_samples <= mp_audio_buffer_samples(ao->buffer)); + + struct mp_audio data; + mp_audio_buffer_peek(ao->buffer, &data); + data.samples = MPMIN(data.samples, playsize); + int played = write_to_ao(mpctx, &data, playflags, written_audio_pts(mpctx)); + ao->buffer_playable_samples = playsize - played; if (played > 0) { - ao->buffer.len -= played; - memmove(ao->buffer.start, ao->buffer.start + played, ao->buffer.len); + mp_audio_buffer_skip(ao->buffer, played); } else if (!mpctx->paused && audio_eof && ao_get_delay(ao) < .04) { // Sanity check to avoid hanging in case current ao doesn't output // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK @@ -428,14 +435,14 @@ void clear_audio_output_buffers(struct MPContext *mpctx) { if (mpctx->ao) { ao_reset(mpctx->ao); - mpctx->ao->buffer.len = 0; - mpctx->ao->buffer_playable_size = 0; + mp_audio_buffer_clear(mpctx->ao->buffer); + mpctx->ao->buffer_playable_samples = 0; } } // Drop decoded data queued for filtering. void clear_audio_decode_buffers(struct MPContext *mpctx) { - if (mpctx->sh_audio) - mpctx->sh_audio->a_buffer_len = 0; + if (mpctx->sh_audio && mpctx->sh_audio->decode_buffer) + mp_audio_buffer_clear(mpctx->sh_audio->decode_buffer); } diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c index a35da703ed..fffb1566c2 100644 --- a/mpvcore/player/loadfile.c +++ b/mpvcore/player/loadfile.c @@ -43,6 +43,8 @@ #include "mpvcore/input/input.h" #include "audio/mixer.h" +#include "audio/audio.h" +#include "audio/audio_buffer.h" #include "audio/decode/dec_audio.h" #include "audio/out/ao.h" #include "demux/demux.h" @@ -163,11 +165,13 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) // Note: with gapless_audio, stop_play is not correctly set if (opts->gapless_audio || mpctx->stop_play == AT_END_OF_FILE) { drain = true; - int len = ao->buffer_playable_size; - assert(len <= ao->buffer.len); - int played = ao_play(ao, ao->buffer.start, len, + struct mp_audio data; + mp_audio_buffer_peek(ao->buffer, &data); + int samples = ao->buffer_playable_samples; + assert(samples <= data.samples); + int played = ao_play(ao, data.planes, samples, AOPLAY_FINAL_CHUNK); - if (played < len) + if (played < samples) MP_WARN(ao, "Audio output truncated at end.\n"); } ao_uninit(ao, drain); |