aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar wm4 <wm4@nowhere>2013-11-12 23:42:04 +0100
committerGravatar wm4 <wm4@nowhere>2013-11-12 23:42:04 +0100
commite4bbb1d348dafbb32722f413648006a7bd9d0897 (patch)
tree7165ed9f86a77b751187600d0a9de8b35416f380
parente4f2fcc0ecd31322df65141edf0ddbff9c075f5d (diff)
parent22b3f522cacfbdba76d311c86efd6091512eb089 (diff)
Merge branch 'planar_audio'
Conflicts: audio/out/ao_lavc.c
-rw-r--r--Makefile1
-rw-r--r--audio/audio.c172
-rw-r--r--audio/audio.h34
-rw-r--r--audio/audio_buffer.c152
-rw-r--r--audio/audio_buffer.h44
-rw-r--r--audio/decode/ad.h4
-rw-r--r--audio/decode/ad_lavc.c161
-rw-r--r--audio/decode/ad_mpg123.c442
-rw-r--r--audio/decode/ad_spdif.c55
-rw-r--r--audio/decode/dec_audio.c188
-rw-r--r--audio/decode/dec_audio.h7
-rw-r--r--audio/filter/af.c49
-rw-r--r--audio/filter/af.h13
-rw-r--r--audio/filter/af_bs2b.c7
-rw-r--r--audio/filter/af_center.c9
-rw-r--r--audio/filter/af_channels.c25
-rw-r--r--audio/filter/af_convert24.c26
-rw-r--r--audio/filter/af_convertsignendian.c11
-rw-r--r--audio/filter/af_delay.c14
-rw-r--r--audio/filter/af_drc.c22
-rw-r--r--audio/filter/af_dummy.c11
-rw-r--r--audio/filter/af_equalizer.c13
-rw-r--r--audio/filter/af_export.c11
-rw-r--r--audio/filter/af_extrastereo.c14
-rw-r--r--audio/filter/af_format.c16
-rw-r--r--audio/filter/af_hrtf.c20
-rw-r--r--audio/filter/af_karaoke.c17
-rw-r--r--audio/filter/af_ladspa.c20
-rw-r--r--audio/filter/af_lavcac3enc.c289
-rw-r--r--audio/filter/af_lavfi.c66
-rw-r--r--audio/filter/af_lavrresample.c77
-rw-r--r--audio/filter/af_pan.c20
-rw-r--r--audio/filter/af_scaletempo.c54
-rw-r--r--audio/filter/af_sinesuppress.c9
-rw-r--r--audio/filter/af_sub.c9
-rw-r--r--audio/filter/af_surround.c19
-rw-r--r--audio/filter/af_sweep.c7
-rw-r--r--audio/filter/af_volume.c44
-rw-r--r--audio/fmt-conversion.c6
-rw-r--r--audio/format.c49
-rw-r--r--audio/format.h22
-rw-r--r--audio/out/ao.c19
-rw-r--r--audio/out/ao.h10
-rw-r--r--audio/out/ao_alsa.c54
-rw-r--r--audio/out/ao_coreaudio.c10
-rw-r--r--audio/out/ao_dsound.c9
-rw-r--r--audio/out/ao_jack.c320
-rw-r--r--audio/out/ao_lavc.c22
-rw-r--r--audio/out/ao_null.c34
-rw-r--r--audio/out/ao_openal.c30
-rw-r--r--audio/out/ao_oss.c18
-rw-r--r--audio/out/ao_pcm.c10
-rw-r--r--audio/out/ao_portaudio.c10
-rw-r--r--audio/out/ao_pulse.c14
-rw-r--r--audio/out/ao_rsound.c8
-rw-r--r--audio/out/ao_sdl.c11
-rw-r--r--audio/out/ao_sndio.c11
-rw-r--r--audio/out/ao_wasapi.c14
-rw-r--r--audio/reorder_ch.c32
-rw-r--r--audio/reorder_ch.h2
-rwxr-xr-xconfigure4
-rw-r--r--demux/demux.c1
-rw-r--r--demux/stheader.h9
-rw-r--r--mpvcore/player/audio.c145
-rw-r--r--mpvcore/player/loadfile.c12
65 files changed, 1549 insertions, 1489 deletions
diff --git a/Makefile b/Makefile
index 771b2a6245..495fe79e61 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
diff --git a/configure b/configure
index bc7199d70d..54c865a6a8 100755
--- a/configure
+++ b/configure
@@ -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);