summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-01-18 14:44:20 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-01-30 03:10:27 -0800
commitb9f804b566c4c528714e4ec5e63675ad7ba5fefd (patch)
tree49d6fcd42ce6597a67aa2af59b7f20beb21a2e14
parent76276c92104c31ee936ba5c76a76072f09978c5f (diff)
downloadmpv-b9f804b566c4c528714e4ec5e63675ad7ba5fefd.tar.bz2
mpv-b9f804b566c4c528714e4ec5e63675ad7ba5fefd.tar.xz
audio: rewrite filtering glue code
Use the new filtering code for audio too.
-rw-r--r--Copyright10
-rw-r--r--DOCS/interface-changes.rst22
-rw-r--r--DOCS/man/af.rst7
-rw-r--r--audio/aconverter.h41
-rw-r--r--audio/aframe.c130
-rw-r--r--audio/aframe.h11
-rw-r--r--audio/audio.c625
-rw-r--r--audio/audio.h102
-rw-r--r--audio/filter/af.c824
-rw-r--r--audio/filter/af.h163
-rw-r--r--audio/filter/af_format.c173
-rw-r--r--audio/filter/af_lavcac3enc.c504
-rw-r--r--audio/filter/af_lavfi.c413
-rw-r--r--audio/filter/af_lavrresample.c187
-rw-r--r--audio/filter/af_rubberband.c446
-rw-r--r--audio/filter/af_scaletempo.c577
-rw-r--r--audio/filter/tools.c72
-rw-r--r--audio/format.c2
-rw-r--r--audio/format.h1
-rw-r--r--filters/f_auto_filters.c90
-rw-r--r--filters/f_auto_filters.h3
-rw-r--r--filters/f_autoconvert.c159
-rw-r--r--filters/f_autoconvert.h11
-rw-r--r--filters/f_lavfi.c101
-rw-r--r--filters/f_output_chain.c355
-rw-r--r--filters/f_output_chain.h27
-rw-r--r--filters/f_swresample.c (renamed from audio/aconverter.c)336
-rw-r--r--filters/f_swresample.h42
-rw-r--r--filters/f_utils.c118
-rw-r--r--filters/f_utils.h6
-rw-r--r--filters/filter.h5
-rw-r--r--filters/user_filters.c29
-rw-r--r--filters/user_filters.h7
-rw-r--r--options/options.c12
-rw-r--r--options/options.h1
-rw-r--r--player/audio.c529
-rw-r--r--player/command.c75
-rw-r--r--player/core.h11
-rw-r--r--wscript_build.py14
39 files changed, 2483 insertions, 3758 deletions
diff --git a/Copyright b/Copyright
index 4a8b056059..b4f3dcfe96 100644
--- a/Copyright
+++ b/Copyright
@@ -34,8 +34,6 @@ a LGPL mode to mpv, MPlayer code had to be relicensed from GPLv2+ to LGPLv2.1+
by asking the MPlayer authors for permission. Since permission could not be
obtained from everyone, LGPL mode disables the following features, some of
them quite central:
-- no audio filtering, which breaks: --af, pitch correction, fine control over
- downmix/upmix/resampling behavior
- Linux X11 video output
- BSD audio output via OSS
- NVIDIA/Linux hardware decoding (vdpau, although nvdec usually works)
@@ -47,15 +45,8 @@ at all.
The following files are still GPL only (--enable-lgpl disables them):
- audio/filter/* will be replaced with new filter chain
- audio/filter/af_format.c mostly LGPL (except af glue code)
- audio/filter/af_lavc3enc.c as above
- audio/filter/af_lavfi.c as above
- audio/filter/af_scaletempo.c as above
- audio/filter/af_rubberband.c as above
audio/out/ao_jack.c will stay GPL
audio/out/ao_oss.c will stay GPL
- audio/audio.* needed by af code only
demux/demux_tv.c will stay GPL
stream/ai_* will stay GPL (TV code)
stream/audio_in.* will stay GPL (TV code)
@@ -88,7 +79,6 @@ The following files are still GPL only (--enable-lgpl disables them):
The following files contain some optional GPL code (--enable-lgpl disables it):
options/parse_commandline.c dvd:// expansion
- player/audio.c libaf glue code
None of the exceptions listed above affect the final binary if it's built as
LGPL. Linked libraries still can affect the final license (for example if
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index 2379470277..64dd36670a 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -43,6 +43,28 @@ Interface changes
- inserting an incompatible filter with hwdec at runtime would refuse
to insert the filter; now it will add it successfully, but disables
the filter slightly later
+ - some behavior changes in the audio filter chain, including:
+ - a manually inserted lavrresample filter is not necessarily used for
+ sample format conversion anymore, so it's pretty useless
+ - changing playback speed will not respect --af-defaults anymore
+ - having libavfilter based filters after the scaletempo or rubberband
+ filters is not supported anymore, and may desync if playback speed is
+ changed (libavfilter does not support the metadata for playback speed)
+ - the lavcac3enc filter does not auto detach itself anymore; instead it
+ passes through the data after converting it to the sample rate and
+ channel configuration the ac3 encoder expects; also, if the audio
+ format changes midstream in a way that causes the filter to switch
+ between PCM and AC3 output, the audio output won't be reconfigured,
+ and audio playback will fail due to libswresample being unable to
+ convert between PCM and AC3 (Note: the responsible developer didn't
+ give a shit)
+ - inserting a filter that changes the output channel layout will not
+ reconfigure the AO - you need to run an additional "ao-reload"
+ command to force this if you want that
+ - using "string" gapless audio (--gapless-audio=yes) can fail if the
+ audio formats are not convertible (such as switching between PCM and
+ AC3 passthrough)
+ - remove out-format sub-parameter from "format" audio filter (no replacement)
--- mpv 0.28.0 ---
- rename --hwdec=mediacodec option to mediacodec-copy, to reflect
conventions followed by other hardware video decoding APIs
diff --git a/DOCS/man/af.rst b/DOCS/man/af.rst
index eb139bc833..5d190cc82b 100644
--- a/DOCS/man/af.rst
+++ b/DOCS/man/af.rst
@@ -52,7 +52,8 @@ Available filters are:
Do not detach if input and output audio format/rate/channels match.
(If you just want to set defaults for this filter that will be used
even by automatically inserted lavrresample instances, you should
- prefer setting them with ``--af-defaults=lavrresample:...``.)
+ prefer setting them with the ``--audio-resample-...`` options.) This
+ does not do anything anymore and the filter will never detach.
``normalize=<yes|no|auto>``
Whether to normalize when remixing channel layouts (default: auto).
``auto`` uses the value set by ``--audio-normalize-downmix``.
@@ -97,7 +98,7 @@ Available filters are:
Select the libavcodec encoder used. Currently, this should be an AC-3
encoder, and using another codec will fail horribly.
-``format=format:srate:channels:out-format:out-srate:out-channels``
+``format=format:srate:channels:out-srate:out-channels``
Does not do any format conversion itself. Rather, it may cause the
filter system to insert necessary conversion filters before or after this
filter if needed. It is primarily useful for controlling the audio format
@@ -126,8 +127,6 @@ Available filters are:
Force mixing to a specific channel layout. See ``--audio-channels`` option
for possible values.
- ``<out-format>``
-
``<out-srate>``
``<out-channels>``
diff --git a/audio/aconverter.h b/audio/aconverter.h
deleted file mode 100644
index 22ca93e4c1..0000000000
--- a/audio/aconverter.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-
-#include "chmap.h"
-
-struct mp_aconverter;
-struct mp_aframe;
-struct mpv_global;
-struct mp_log;
-
-struct mp_resample_opts {
- int filter_size;
- int phase_shift;
- int linear;
- double cutoff;
- int normalize;
- int allow_passthrough;
- char **avopts;
-};
-
-#define MP_RESAMPLE_OPTS_DEF { \
- .filter_size = 16, \
- .cutoff = 0.0, \
- .phase_shift = 10, \
- .normalize = 0, \
- }
-
-extern const struct m_sub_options resample_config;
-
-struct mp_aconverter *mp_aconverter_create(struct mpv_global *global,
- struct mp_log *log,
- const struct mp_resample_opts *opts);
-bool mp_aconverter_reconfig(struct mp_aconverter *p,
- int in_rate, int in_format, struct mp_chmap in_channels,
- int out_rate, int out_format, struct mp_chmap out_channels);
-void mp_aconverter_flush(struct mp_aconverter *p);
-void mp_aconverter_set_speed(struct mp_aconverter *p, double speed);
-bool mp_aconverter_write_input(struct mp_aconverter *p, struct mp_aframe *in);
-struct mp_aframe *mp_aconverter_read_output(struct mp_aconverter *p, bool *eof);
-double mp_aconverter_get_latency(struct mp_aconverter *p);
diff --git a/audio/aframe.c b/audio/aframe.c
index 1f053a6715..9115cf67fd 100644
--- a/audio/aframe.c
+++ b/audio/aframe.c
@@ -32,6 +32,11 @@ struct mp_aframe {
// We support spdif formats, which are allocated as AV_SAMPLE_FMT_S16.
int format;
double pts;
+ double speed;
+};
+
+struct avframe_opaque {
+ double speed;
};
static void free_frame(void *ptr)
@@ -43,11 +48,11 @@ static void free_frame(void *ptr)
struct mp_aframe *mp_aframe_create(void)
{
struct mp_aframe *frame = talloc_zero(NULL, struct mp_aframe);
- frame->pts = MP_NOPTS_VALUE;
frame->av_frame = av_frame_alloc();
if (!frame->av_frame)
abort();
talloc_set_destructor(frame, free_frame);
+ mp_aframe_reset(frame);
return frame;
}
@@ -61,6 +66,7 @@ struct mp_aframe *mp_aframe_new_ref(struct mp_aframe *frame)
dst->chmap = frame->chmap;
dst->format = frame->format;
dst->pts = frame->pts;
+ dst->speed = frame->speed;
if (mp_aframe_is_allocated(frame)) {
if (av_frame_ref(dst->av_frame, frame->av_frame) < 0)
@@ -80,6 +86,7 @@ void mp_aframe_reset(struct mp_aframe *frame)
frame->chmap.num = 0;
frame->format = 0;
frame->pts = MP_NOPTS_VALUE;
+ frame->speed = 1.0;
}
// Remove all actual audio data and leave only the metadata.
@@ -120,6 +127,11 @@ struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame)
mp_chmap_from_channels(&frame->chmap, av_frame->channels);
#endif
+ if (av_frame->opaque_ref) {
+ struct avframe_opaque *op = (void *)av_frame->opaque_ref->data;
+ frame->speed = op->speed;
+ }
+
return frame;
}
@@ -137,6 +149,16 @@ struct AVFrame *mp_aframe_to_avframe(struct mp_aframe *frame)
if (!mp_chmap_is_lavc(&frame->chmap))
return NULL;
+ if (!frame->av_frame->opaque_ref && frame->speed != 1.0) {
+ frame->av_frame->opaque_ref =
+ av_buffer_alloc(sizeof(struct avframe_opaque));
+ if (!frame->av_frame->opaque_ref)
+ return NULL;
+
+ struct avframe_opaque *op = (void *)frame->av_frame->opaque_ref->data;
+ op->speed = frame->speed;
+ }
+
return av_frame_clone(frame->av_frame);
}
@@ -183,6 +205,7 @@ void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src)
void mp_aframe_copy_attributes(struct mp_aframe *dst, struct mp_aframe *src)
{
dst->pts = src->pts;
+ dst->speed = src->speed;
int rate = dst->av_frame->sample_rate;
@@ -316,6 +339,37 @@ void mp_aframe_set_pts(struct mp_aframe *frame, double pts)
frame->pts = pts;
}
+// Set a speed factor. This is multiplied with the sample rate to get the
+// "effective" samplerate (mp_aframe_get_effective_rate()), which will be used
+// to do PTS calculations. If speed!=1.0, the PTS values always refer to the
+// original PTS (before changing speed), and if you want reasonably continuous
+// PTS between frames, you need to use the effective samplerate.
+void mp_aframe_set_speed(struct mp_aframe *frame, double factor)
+{
+ frame->speed = factor;
+}
+
+// Adjust current speed factor.
+void mp_aframe_mul_speed(struct mp_aframe *frame, double factor)
+{
+ frame->speed *= factor;
+}
+
+double mp_aframe_get_speed(struct mp_aframe *frame)
+{
+ return frame->speed;
+}
+
+// Matters for speed changed frames (such as a frame which has been resampled
+// to play at a different speed).
+// Return the sample rate at which the frame would have to be played to result
+// in the same duration as the original frame before the speed change.
+// This is used for A/V sync.
+double mp_aframe_get_effective_rate(struct mp_aframe *frame)
+{
+ return mp_aframe_get_rate(frame) / frame->speed;
+}
+
// Return number of data pointers.
int mp_aframe_get_planes(struct mp_aframe *frame)
{
@@ -339,6 +393,18 @@ int mp_aframe_get_total_plane_samples(struct mp_aframe *frame)
? 1 : mp_aframe_get_channels(frame));
}
+char *mp_aframe_format_str_buf(char *buf, size_t buf_size, struct mp_aframe *fmt)
+{
+ char ch[128];
+ mp_chmap_to_str_buf(ch, sizeof(ch), &fmt->chmap);
+ char *hr_ch = mp_chmap_to_str_hr(&fmt->chmap);
+ if (strcmp(hr_ch, ch) != 0)
+ mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch);
+ snprintf(buf, buf_size, "%dHz %s %dch %s", fmt->av_frame->sample_rate,
+ ch, fmt->chmap.num, af_fmt_to_str(fmt->format));
+ return buf;
+}
+
// Set data to the audio after the given number of samples (i.e. slice it).
void mp_aframe_skip_samples(struct mp_aframe *f, int samples)
{
@@ -352,25 +418,25 @@ void mp_aframe_skip_samples(struct mp_aframe *f, int samples)
f->av_frame->nb_samples -= samples;
if (f->pts != MP_NOPTS_VALUE)
- f->pts += samples / (double)mp_aframe_get_rate(f);
+ f->pts += samples / mp_aframe_get_effective_rate(f);
}
// Return the timestamp of the sample just after the end of this frame.
double mp_aframe_end_pts(struct mp_aframe *f)
{
- int rate = mp_aframe_get_rate(f);
- if (f->pts == MP_NOPTS_VALUE || rate < 1)
+ double rate = mp_aframe_get_effective_rate(f);
+ if (f->pts == MP_NOPTS_VALUE || rate <= 0)
return MP_NOPTS_VALUE;
- return f->pts + f->av_frame->nb_samples / (double)rate;
+ return f->pts + f->av_frame->nb_samples / rate;
}
// Return the duration in seconds of the frame (0 if invalid).
double mp_aframe_duration(struct mp_aframe *f)
{
- int rate = mp_aframe_get_rate(f);
- if (rate < 1)
+ double rate = mp_aframe_get_effective_rate(f);
+ if (rate <= 0)
return 0;
- return f->av_frame->nb_samples / (double)rate;
+ return f->av_frame->nb_samples / rate;
}
// Clip the given frame to the given timestamp range. Adjusts the frame size
@@ -378,7 +444,7 @@ double mp_aframe_duration(struct mp_aframe *f)
void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end)
{
double f_end = mp_aframe_end_pts(f);
- int rate = mp_aframe_get_rate(f);
+ double rate = mp_aframe_get_effective_rate(f);
if (f_end == MP_NOPTS_VALUE)
return;
if (end != MP_NOPTS_VALUE) {
@@ -405,6 +471,52 @@ void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end)
}
}
+bool mp_aframe_copy_samples(struct mp_aframe *dst, int dst_offset,
+ struct mp_aframe *src, int src_offset,
+ int samples)
+{
+ if (!mp_aframe_config_equals(dst, src))
+ return false;
+
+ if (mp_aframe_get_size(dst) < dst_offset + samples ||
+ mp_aframe_get_size(src) < src_offset + samples)
+ return false;
+
+ uint8_t **s = mp_aframe_get_data_ro(src);
+ uint8_t **d = mp_aframe_get_data_rw(dst);
+ if (!s || !d)
+ return false;
+
+ int planes = mp_aframe_get_planes(dst);
+ size_t sstride = mp_aframe_get_sstride(dst);
+
+ for (int n = 0; n < planes; n++) {
+ memcpy(d[n] + dst_offset * sstride, s[n] + src_offset * sstride,
+ samples * sstride);
+ }
+
+ return true;
+}
+
+bool mp_aframe_set_silence(struct mp_aframe *f, int offset, int samples)
+{
+ if (mp_aframe_get_size(f) < offset + samples)
+ return false;
+
+ int format = mp_aframe_get_format(f);
+ uint8_t **d = mp_aframe_get_data_rw(f);
+ if (!d)
+ return false;
+
+ int planes = mp_aframe_get_planes(f);
+ size_t sstride = mp_aframe_get_sstride(f);
+
+ for (int n = 0; n < planes; n++)
+ af_fill_silence(d[n] + offset * sstride, samples * sstride, format);
+
+ return true;
+}
+
struct mp_aframe_pool {
AVBufferPool *avpool;
int element_size;
diff --git a/audio/aframe.h b/audio/aframe.h
index 8ea676c198..ed92c223f6 100644
--- a/audio/aframe.h
+++ b/audio/aframe.h
@@ -36,21 +36,32 @@ int mp_aframe_get_channels(struct mp_aframe *frame);
int mp_aframe_get_rate(struct mp_aframe *frame);
int mp_aframe_get_size(struct mp_aframe *frame);
double mp_aframe_get_pts(struct mp_aframe *frame);
+double mp_aframe_get_speed(struct mp_aframe *frame);
+double mp_aframe_get_effective_rate(struct mp_aframe *frame);
bool mp_aframe_set_format(struct mp_aframe *frame, int format);
bool mp_aframe_set_chmap(struct mp_aframe *frame, struct mp_chmap *in);
bool mp_aframe_set_rate(struct mp_aframe *frame, int rate);
bool mp_aframe_set_size(struct mp_aframe *frame, int samples);
void mp_aframe_set_pts(struct mp_aframe *frame, double pts);
+void mp_aframe_set_speed(struct mp_aframe *frame, double factor);
+void mp_aframe_mul_speed(struct mp_aframe *frame, double factor);
int mp_aframe_get_planes(struct mp_aframe *frame);
int mp_aframe_get_total_plane_samples(struct mp_aframe *frame);
size_t mp_aframe_get_sstride(struct mp_aframe *frame);
+char *mp_aframe_format_str_buf(char *buf, size_t buf_size, struct mp_aframe *fmt);
+#define mp_aframe_format_str(fmt) mp_aframe_format_str_buf((char[32]){0}, 32, (fmt))
+
void mp_aframe_skip_samples(struct mp_aframe *f, int samples);
double mp_aframe_end_pts(struct mp_aframe *f);
double mp_aframe_duration(struct mp_aframe *f);
void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end);
+bool mp_aframe_copy_samples(struct mp_aframe *dst, int dst_offset,
+ struct mp_aframe *src, int src_offset,
+ int samples);
+bool mp_aframe_set_silence(struct mp_aframe *f, int offset, int samples);
struct mp_aframe_pool;
struct mp_aframe_pool *mp_aframe_pool_create(void *ta_parent);
diff --git a/audio/audio.c b/audio/audio.c
deleted file mode 100644
index 55e4266f45..0000000000
--- a/audio/audio.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * 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 <stdint.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include <libavutil/buffer.h>
-#include <libavutil/frame.h>
-#include <libavutil/mem.h>
-#include <libavutil/version.h>
-
-#include "mpv_talloc.h"
-#include "common/common.h"
-#include "fmt-conversion.h"
-#include "audio.h"
-#include "aframe.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_fmt_to_bytes(mpa->format);
- 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;
- update_redundant_info(mpa);
-}
-
-void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels)
-{
- mp_chmap_from_channels(&mpa->channels, num_channels);
- update_redundant_info(mpa);
-}
-
-void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap)
-{
- mpa->channels = *chmap;
- update_redundant_info(mpa);
-}
-
-void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src)
-{
- 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)
-{
- return a->format == b->format && a->rate == b->rate &&
- mp_chmap_equals(&a->channels, &b->channels);
-}
-
-bool mp_audio_config_valid(const struct mp_audio *mpa)
-{
- return mp_chmap_is_valid(&mpa->channels) && af_fmt_is_valid(mpa->format)
- && mpa->rate >= 1 && mpa->rate < 10000000;
-}
-
-char *mp_audio_config_to_str_buf(char *buf, size_t buf_sz, struct mp_audio *mpa)
-{
- char ch[128];
- mp_chmap_to_str_buf(ch, sizeof(ch), &mpa->channels);
- char *hr_ch = mp_chmap_to_str_hr(&mpa->channels);
- if (strcmp(hr_ch, ch) != 0)
- mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch);
- snprintf(buf, buf_sz, "%dHz %s %dch %s", mpa->rate,
- ch, mpa->channels.num, af_fmt_to_str(mpa->format));
- return buf;
-}
-
-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->allocated[n] = NULL;
- }
- mpa->samples = 0;
-}
-
-static int get_plane_size(const struct mp_audio *mpa, int samples)
-{
- if (samples < 0 || !mp_audio_config_valid(mpa))
- return -1;
- if (samples >= INT_MAX / mpa->sstride)
- return -1;
- return MPMAX(samples * mpa->sstride, 1);
-}
-
-static void mp_audio_destructor(void *ptr)
-{
- struct mp_audio *mpa = ptr;
- for (int n = 0; n < MP_NUM_CHANNELS; n++)
- av_buffer_unref(&mpa->allocated[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).
- *
- * This also makes sure the resulting buffer is writable (even in the case
- * the buffer has the correct size).
- *
- * 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)
-{
- int size = get_plane_size(mpa, samples);
- if (size < 0)
- abort(); // oom or invalid parameters
- if (!mp_audio_is_writeable(mpa)) {
- for (int n = 0; n < MP_NUM_CHANNELS; n++) {
- av_buffer_unref(&mpa->allocated[n]);
- mpa->planes[n] = NULL;
- }
- }
- for (int n = 0; n < mpa->num_planes; n++) {
- if (!mpa->allocated[n] || size != mpa->allocated[n]->size) {
- if (av_buffer_realloc(&mpa->allocated[n], size) < 0)
- abort(); // OOM
- }
- mpa->planes[n] = mpa->allocated[n]->data;
- }
- for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) {
- av_buffer_unref(&mpa->allocated[n]);
- mpa->planes[n] = NULL;
- }
- talloc_set_destructor(mpa, mp_audio_destructor);
-}
-
-// Like mp_audio_realloc(), but only reallocate if the audio grows in size.
-// If the buffer is reallocated, also preallocate.
-void mp_audio_realloc_min(struct mp_audio *mpa, int samples)
-{
- if (samples > mp_audio_get_allocated_size(mpa) || !mp_audio_is_writeable(mpa)) {
- size_t alloc = ta_calc_prealloc_elems(samples);
- if (alloc > INT_MAX)
- abort(); // oom
- mp_audio_realloc(mpa, alloc);
- }
-}
-
-/* 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++) {
- for (int i = 0; i < MP_NUM_CHANNELS && mpa->allocated[i]; i++) {
- uint8_t *start = mpa->allocated[i]->data;
- uint8_t *end = start + mpa->allocated[i]->size;
- uint8_t *plane = mpa->planes[n];
- if (plane >= start && plane < end) {
- int s = MPMIN((end - plane) / mpa->sstride, INT_MAX);
- size = n == 0 ? s : MPMIN(size, s);
- goto next;
- }
- }
- return 0; // plane is not covered by any buffer
- next: ;
- }
- 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);
- }
-}
-
-// Copy fields that describe characteristics of the audio frame, but which are
-// no