summaryrefslogtreecommitdiffstats
path: root/audio/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/audio.c')
-rw-r--r--audio/audio.c148
1 files changed, 137 insertions, 11 deletions
diff --git a/audio/audio.c b/audio/audio.c
index 9d41928436..ace455f123 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -17,42 +17,58 @@
#include <assert.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 +90,113 @@ 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;
+}
+
+/* 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++) {
+ mpa->planes[n] = talloc_realloc_size(mpa, mpa->planes[n], size);
+ }
+ for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) {
+ talloc_free(mpa->planes[n]);
+ mpa->planes[n] = NULL;
+ }
+}
+
+// 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 = talloc_get_size(mpa->planes[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;
+}