aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--audio/aframe.c444
-rw-r--r--audio/aframe.h53
-rw-r--r--audio/audio.c24
-rw-r--r--audio/audio.h4
-rw-r--r--audio/decode/ad.h4
-rw-r--r--audio/decode/ad_lavc.c33
-rw-r--r--audio/decode/ad_spdif.c41
-rw-r--r--audio/decode/dec_audio.c33
-rw-r--r--audio/decode/dec_audio.h7
-rw-r--r--audio/out/ao.c11
-rw-r--r--audio/out/ao.h4
-rw-r--r--player/audio.c57
-rw-r--r--player/command.c43
-rw-r--r--player/core.h10
-rw-r--r--player/lavfi.c59
-rw-r--r--player/lavfi.h6
-rw-r--r--player/loadfile.c2
-rw-r--r--player/playloop.c2
-rw-r--r--player/video.c8
-rw-r--r--wscript_build.py1
20 files changed, 706 insertions, 140 deletions
diff --git a/audio/aframe.c b/audio/aframe.c
new file mode 100644
index 0000000000..5178c718b4
--- /dev/null
+++ b/audio/aframe.c
@@ -0,0 +1,444 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libavutil/frame.h>
+
+#include "common/common.h"
+
+#include "chmap.h"
+#include "fmt-conversion.h"
+#include "format.h"
+#include "aframe.h"
+
+struct mp_aframe {
+ AVFrame *av_frame;
+ // We support channel layouts different from AVFrame channel masks
+ struct mp_chmap chmap;
+ // We support spdif formats, which are allocated as AV_SAMPLE_FMT_S16.
+ int format;
+ double pts;
+};
+
+static void free_frame(void *ptr)
+{
+ struct mp_aframe *frame = ptr;
+ av_frame_free(&frame->av_frame);
+}
+
+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);
+ return frame;
+}
+
+struct mp_aframe *mp_aframe_new_ref(struct mp_aframe *frame)
+{
+ if (!frame)
+ return NULL;
+
+ struct mp_aframe *dst = mp_aframe_create();
+
+ dst->chmap = frame->chmap;
+ dst->format = frame->format;
+ dst->pts = frame->pts;
+
+ if (mp_aframe_is_allocated(frame)) {
+ if (av_frame_ref(dst->av_frame, frame->av_frame) < 0)
+ abort();
+ } else {
+ // av_frame_ref() would fail.
+ mp_aframe_config_copy(dst, frame);
+ }
+
+ return dst;
+}
+
+// Revert to state after mp_aframe_create().
+void mp_aframe_reset(struct mp_aframe *frame)
+{
+ av_frame_unref(frame->av_frame);
+ frame->chmap.num = 0;
+ frame->format = 0;
+ frame->pts = MP_NOPTS_VALUE;
+}
+
+// Remove all actual audio data and leave only the metadata.
+void mp_aframe_unref_data(struct mp_aframe *frame)
+{
+ // In a fucked up way, this is less complex than just unreffing the data.
+ struct mp_aframe *tmp = mp_aframe_create();
+ MPSWAP(struct mp_aframe, *tmp, *frame);
+ mp_aframe_reset(frame);
+ mp_aframe_config_copy(frame, tmp);
+ talloc_free(tmp);
+}
+
+// Return a new reference to the data in av_frame. av_frame itself is not
+// touched. Returns NULL if not representable, or if input is NULL.
+// Does not copy the timestamps.
+struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame)
+{
+ if (!av_frame || av_frame->width > 0 || av_frame->height > 0)
+ return NULL;
+
+ int format = af_from_avformat(av_frame->format);
+ if (!format && av_frame->format != AV_SAMPLE_FMT_NONE)
+ return NULL;
+
+ struct mp_aframe *frame = mp_aframe_create();
+
+ // This also takes care of forcing refcounting.
+ if (av_frame_ref(frame->av_frame, av_frame) < 0)
+ abort();
+
+ frame->format = format;
+ mp_chmap_from_lavc(&frame->chmap, frame->av_frame->channel_layout);
+
+#if LIBAVUTIL_VERSION_MICRO >= 100
+ // FFmpeg being a stupid POS again
+ if (frame->chmap.num != frame->av_frame->channels)
+ mp_chmap_from_channels(&frame->chmap, av_frame->channels);
+#endif
+
+ return frame;
+}
+
+// Return a new reference to the data in frame. Returns NULL is not
+// representable (), or if input is NULL.
+// Does not copy the timestamps.
+struct AVFrame *mp_aframe_to_avframe(struct mp_aframe *frame)
+{
+ if (!frame)
+ return NULL;
+
+ if (af_to_avformat(frame->format) != frame->av_frame->format)
+ return NULL;
+
+ if (!mp_chmap_is_lavc(&frame->chmap))
+ return NULL;
+
+ return av_frame_clone(frame->av_frame);
+}
+
+struct AVFrame *mp_aframe_to_avframe_and_unref(struct mp_aframe *frame)
+{
+ AVFrame *av = mp_aframe_to_avframe(frame);
+ talloc_free(frame);
+ return av;
+}
+
+// You must not use this.
+struct AVFrame *mp_aframe_get_raw_avframe(struct mp_aframe *frame)
+{
+ return frame->av_frame;
+}
+
+// Return whether it has associated audio data. (If not, metadata only.)
+bool mp_aframe_is_allocated(struct mp_aframe *frame)
+{
+ return frame->av_frame->buf[0] || frame->av_frame->extended_data[0];
+}
+
+// Clear dst, and then copy the configuration to it.
+void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src)
+{
+ mp_aframe_reset(dst);
+
+ dst->chmap = src->chmap;
+ dst->format = src->format;
+ dst->pts = src->pts;
+
+ if (av_frame_copy_props(dst->av_frame, src->av_frame) < 0)
+ abort();
+ dst->av_frame->format = src->av_frame->format;
+ dst->av_frame->channel_layout = src->av_frame->channel_layout;
+#if LIBAVUTIL_VERSION_MICRO >= 100
+ // FFmpeg being a stupid POS again
+ dst->av_frame->channels = src->av_frame->channels;
+#endif
+}
+
+// Return whether a and b use the same physical audio format. Extra metadata
+// such as PTS, per-frame signalling, and AVFrame side data is not compared.
+bool mp_aframe_config_equals(struct mp_aframe *a, struct mp_aframe *b)
+{
+ struct mp_chmap ca = {0}, cb = {0};
+ mp_aframe_get_chmap(a, &ca);
+ mp_aframe_get_chmap(b, &cb);
+ return mp_chmap_equals(&ca, &cb) &&
+ mp_aframe_get_rate(a) == mp_aframe_get_rate(b) &&
+ mp_aframe_get_format(a) == mp_aframe_get_format(b);
+}
+
+// Return whether all required format fields have been set.
+bool mp_aframe_config_is_valid(struct mp_aframe *frame)
+{
+ return frame->format && frame->chmap.num && frame->av_frame->sample_rate;
+}
+
+// Return the pointer to the first sample for each plane. The pointers stay
+// valid until the next call that mutates frame somehow. You must not write to
+// the audio data. Returns NULL if no frame allocated.
+uint8_t **mp_aframe_get_data_ro(struct mp_aframe *frame)
+{
+ return mp_aframe_is_allocated(frame) ? frame->av_frame->extended_data : NULL;
+}
+
+// Like mp_aframe_get_data_ro(), but you can write to the audio data.
+// Additionally, it will return NULL if copy-on-write fails.
+uint8_t **mp_aframe_get_data_rw(struct mp_aframe *frame)
+{
+ if (!mp_aframe_is_allocated(frame))
+ return NULL;
+ if (av_frame_make_writable(frame->av_frame) < 0)
+ return NULL;
+ return frame->av_frame->extended_data;
+}
+
+int mp_aframe_get_format(struct mp_aframe *frame)
+{
+ return frame->format;
+}
+
+bool mp_aframe_get_chmap(struct mp_aframe *frame, struct mp_chmap *out)
+{
+ if (!mp_chmap_is_valid(&frame->chmap))
+ return false;
+ *out = frame->chmap;
+ return true;
+}
+
+int mp_aframe_get_channels(struct mp_aframe *frame)
+{
+ return frame->chmap.num;
+}
+
+int mp_aframe_get_rate(struct mp_aframe *frame)
+{
+ return frame->av_frame->sample_rate;
+}
+
+int mp_aframe_get_size(struct mp_aframe *frame)
+{
+ return frame->av_frame->nb_samples;
+}
+
+double mp_aframe_get_pts(struct mp_aframe *frame)
+{
+ return frame->pts;
+}
+
+bool mp_aframe_set_format(struct mp_aframe *frame, int format)
+{
+ if (mp_aframe_is_allocated(frame))
+ return false;
+ enum AVSampleFormat av_format = frame->av_frame->format;
+ if (av_format == AV_SAMPLE_FMT_NONE && frame->format) {
+ if (!af_fmt_is_spdif(format))
+ return false;
+ av_format = AV_SAMPLE_FMT_S16;
+ }
+ frame->format = format;
+ frame->av_frame->format = av_format;
+ return true;
+}
+
+bool mp_aframe_set_chmap(struct mp_aframe *frame, struct mp_chmap *in)
+{
+ if (!mp_chmap_is_valid(in) && !mp_chmap_is_empty(in))
+ return false;
+ if (mp_aframe_is_allocated(frame) && in->num != frame->chmap.num)
+ return false;
+ uint64_t lavc_layout = mp_chmap_to_lavc_unchecked(in);
+ if (!lavc_layout && in->num)
+ return false;
+ frame->chmap = *in;
+ frame->av_frame->channel_layout = lavc_layout;
+#if LIBAVUTIL_VERSION_MICRO >= 100
+ // FFmpeg being a stupid POS again
+ frame->av_frame->channels = frame->chmap.num;
+#endif
+ return true;
+}
+
+bool mp_aframe_set_rate(struct mp_aframe *frame, int rate)
+{
+ if (rate < 1 && rate > 10000000)
+ return false;
+ frame->av_frame->sample_rate = rate;
+ return true;
+}
+
+bool mp_aframe_set_size(struct mp_aframe *frame, int samples)
+{
+ if (!mp_aframe_is_allocated(frame) || mp_aframe_get_size(frame) < samples)
+ return false;
+ frame->av_frame->nb_samples = MPMAX(samples, 0);
+ return true;
+}
+
+void mp_aframe_set_pts(struct mp_aframe *frame, double pts)
+{
+ frame->pts = pts;
+}
+
+// Return number of data pointers.
+int mp_aframe_get_planes(struct mp_aframe *frame)
+{
+ return af_fmt_is_planar(mp_aframe_get_format(frame))
+ ? mp_aframe_get_channels(frame) : 1;
+}
+
+// Return number of bytes between 2 consecutive samples on the same plane.
+size_t mp_aframe_get_sstride(struct mp_aframe *frame)
+{
+ int format = mp_aframe_get_format(frame);
+ return af_fmt_to_bytes(format) *
+ (af_fmt_is_planar(format) ? 1 : mp_aframe_get_channels(frame));
+}
+
+// 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)
+{
+ assert(samples >= 0 && samples <= mp_aframe_get_size(f));
+
+ int num_planes = mp_aframe_get_planes(f);
+ size_t sstride = mp_aframe_get_sstride(f);
+ for (int n = 0; n < num_planes; n++)
+ f->av_frame->extended_data[n] += samples * sstride;
+
+ f->av_frame->nb_samples -= samples;
+
+ if (f->pts != MP_NOPTS_VALUE)
+ f->pts += samples / (double)mp_aframe_get_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)
+ return MP_NOPTS_VALUE;
+ return f->pts + f->av_frame->nb_samples / (double)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)
+ return 0;
+ return f->av_frame->nb_samples / (double)rate;
+}
+
+// Clip the given frame to the given timestamp range. Adjusts the frame size
+// and timestamp.
+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);
+ if (f_end == MP_NOPTS_VALUE)
+ return;
+ if (end != MP_NOPTS_VALUE) {
+ if (f_end >= end) {
+ if (f->pts >= end) {
+ f->av_frame->nb_samples = 0;
+ } else {
+ int new = (end - f->pts) * rate;
+ f->av_frame->nb_samples = MPCLAMP(new, 0, f->av_frame->nb_samples);
+ }
+ }
+ }
+ if (start != MP_NOPTS_VALUE) {
+ if (f->pts < start) {
+ if (f_end <= start) {
+ f->av_frame->nb_samples = 0;
+ f->pts = f_end;
+ } else {
+ int skip = (start - f->pts) * rate;
+ skip = MPCLAMP(skip, 0, f->av_frame->nb_samples);
+ mp_aframe_skip_samples(f, skip);
+ }
+ }
+ }
+}
+
+struct mp_aframe_pool {
+ AVBufferPool *avpool;
+ int element_size;
+};
+
+struct mp_aframe_pool *mp_aframe_pool_create(void *ta_parent)
+{
+ return talloc_zero(ta_parent, struct mp_aframe_pool);
+}
+
+static void mp_aframe_pool_destructor(void *p)
+{
+ struct mp_aframe_pool *pool = p;
+ av_buffer_pool_uninit(&pool->avpool);
+}
+
+// Like mp_aframe_allocate(), but use the pool to allocate data.
+int mp_aframe_pool_allocate(struct mp_aframe_pool *pool, struct mp_aframe *frame,
+ int samples)
+{
+ int planes = mp_aframe_get_planes(frame);
+ size_t sstride = mp_aframe_get_sstride(frame);
+ int plane_size = MP_ALIGN_UP(sstride * MPMAX(samples, 1), 32);
+ int size = plane_size * planes;
+
+ if (size <= 0 || mp_aframe_is_allocated(frame))
+ return -1;
+
+ if (!pool->avpool || size > pool->element_size) {
+ size_t alloc = ta_calc_prealloc_elems(size);
+ if (alloc >= INT_MAX)
+ return -1;
+ av_buffer_pool_uninit(&pool->avpool);
+ pool->element_size = alloc;
+ pool->avpool = av_buffer_pool_init(pool->element_size, NULL);
+ if (!pool->avpool)
+ return -1;
+ talloc_set_destructor(pool, mp_aframe_pool_destructor);
+ }
+
+ // Yes, you have to do all this shit manually.
+ // At least it's less stupid than av_frame_get_buffer(), which just wipes
+ // the entire frame struct on error for no reason.
+ AVFrame *av_frame = frame->av_frame;
+ if (av_frame->extended_data != av_frame->data)
+ av_freep(&av_frame->extended_data); // sigh
+ av_frame->extended_data =
+ av_mallocz_array(planes, sizeof(av_frame->extended_data[0]));
+ if (!av_frame->extended_data)
+ abort();
+ av_frame->buf[0] = av_buffer_pool_get(pool->avpool);
+ if (!av_frame->buf[0])
+ return -1;
+ av_frame->linesize[0] = samples * sstride;
+ for (int n = 0; n < planes; n++)
+ av_frame->extended_data[n] = av_frame->buf[0]->data + n * plane_size;
+ av_frame->nb_samples = samples;
+
+ return 0;
+}
diff --git a/audio/aframe.h b/audio/aframe.h
new file mode 100644
index 0000000000..5661178419
--- /dev/null
+++ b/audio/aframe.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <stdint.h>
+
+struct mp_aframe;
+struct AVFrame;
+struct mp_chmap;
+
+struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame);
+struct mp_aframe *mp_aframe_create(void);
+struct mp_aframe *mp_aframe_new_ref(struct mp_aframe *frame);
+
+void mp_aframe_reset(struct mp_aframe *frame);
+void mp_aframe_unref_data(struct mp_aframe *frame);
+
+struct AVFrame *mp_aframe_to_avframe(struct mp_aframe *frame);
+struct AVFrame *mp_aframe_to_avframe_and_unref(struct mp_aframe *frame);
+struct AVFrame *mp_aframe_get_raw_avframe(struct mp_aframe *frame);
+
+bool mp_aframe_is_allocated(struct mp_aframe *frame);
+
+void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src);
+bool mp_aframe_config_equals(struct mp_aframe *a, struct mp_aframe *b);
+bool mp_aframe_config_is_valid(struct mp_aframe *frame);
+
+uint8_t **mp_aframe_get_data_ro(struct mp_aframe *frame);
+uint8_t **mp_aframe_get_data_rw(struct mp_aframe *frame);
+
+int mp_aframe_get_format(struct mp_aframe *frame);
+bool mp_aframe_get_chmap(struct mp_aframe *frame, struct mp_chmap *out);
+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);
+
+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);
+
+int mp_aframe_get_planes(struct mp_aframe *frame);
+size_t mp_aframe_get_sstride(struct mp_aframe *frame);
+
+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);
+
+struct mp_aframe_pool;
+struct mp_aframe_pool *mp_aframe_pool_create(void *ta_parent);
+int mp_aframe_pool_allocate(struct mp_aframe_pool *pool, struct mp_aframe *frame,
+ int samples);
diff --git a/audio/audio.c b/audio/audio.c
index 502bbf2134..5c31d3e81a 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -29,6 +29,7 @@
#include "common/common.h"
#include "fmt-conversion.h"
#include "audio.h"
+#include "aframe.h"
static void update_redundant_info(struct mp_audio *mpa)
{
@@ -403,6 +404,29 @@ fail:
return NULL;
}
+struct mp_audio *mp_audio_from_aframe(struct mp_aframe *aframe)
+{
+ struct AVFrame *av = mp_aframe_get_raw_avframe(aframe);
+ struct mp_audio *res = mp_audio_from_avframe(av);
+ if (!res)
+ return NULL;
+ struct mp_chmap chmap = {0};
+ mp_aframe_get_chmap(aframe, &chmap);
+ mp_audio_set_channels(res, &chmap);
+ mp_audio_set_format(res, mp_aframe_get_format(aframe));
+ res->pts = mp_aframe_get_pts(aframe);
+ return res;
+}
+
+void mp_audio_config_from_aframe(struct mp_audio *dst, struct mp_aframe *src)
+{
+ struct mp_chmap chmap = {0};
+ mp_aframe_get_chmap(src, &chmap);
+ mp_audio_set_channels(dst, &chmap);
+ mp_audio_set_format(dst, mp_aframe_get_format(src));
+ dst->rate = mp_aframe_get_rate(src);
+}
+
int mp_audio_to_avframe(struct mp_audio *frame, struct AVFrame *avframe)
{
av_frame_unref(avframe);
diff --git a/audio/audio.h b/audio/audio.h
index 0f32f080b9..a8370a0eb7 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -83,6 +83,10 @@ struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe);
struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame);
int mp_audio_to_avframe(struct mp_audio *frame, struct AVFrame *avframe);
+struct mp_aframe;
+struct mp_audio *mp_audio_from_aframe(struct mp_aframe *aframe);
+void mp_audio_config_from_aframe(struct mp_audio *dst, struct mp_aframe *src);
+
struct mp_audio_pool;
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent);
struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
diff --git a/audio/decode/ad.h b/audio/decode/ad.h
index 0af05e1827..a8384c277f 100644
--- a/audio/decode/ad.h
+++ b/audio/decode/ad.h
@@ -23,7 +23,7 @@
#include "demux/demux.h"
#include "audio/format.h"
-#include "audio/audio.h"
+#include "audio/aframe.h"
#include "dec_audio.h"
struct mp_decoder_list;
@@ -39,7 +39,7 @@ struct ad_functions {
bool (*send_packet)(struct dec_audio *da, struct demux_packet *pkt);
// Return whether decoding is still going on (false if EOF was reached).
// Never returns false & *out set, but can return true with !*out.
- bool (*receive_frame)(struct dec_audio *da, struct mp_audio **out);
+ bool (*receive_frame)(struct dec_audio *da, struct mp_aframe **out);
};
enum ad_ctrl {
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index d701630fc6..fb429d567b 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -40,7 +40,6 @@
struct priv {
AVCodecContext *avctx;
AVFrame *avframe;
- struct mp_audio frame;
bool force_channel_map;
uint32_t skip_samples, trim_samples;
bool preroll_done;
@@ -191,7 +190,7 @@ static bool send_packet(struct dec_audio *da, struct demux_packet *mpkt)
return true;
}
-static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
+static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
@@ -217,25 +216,18 @@ static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
double out_pts = mp_pts_from_av(priv->avframe->pts, &priv->codec_timebase);
- struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
+ struct mp_aframe *mpframe = mp_aframe_from_avframe(priv->avframe);
if (!mpframe)
return true;
- struct mp_chmap lavc_chmap = mpframe->channels;
- if (lavc_chmap.num != avctx->channels)
- mp_chmap_from_channels(&lavc_chmap, avctx->channels);
- if (priv->force_channel_map) {
- if (lavc_chmap.num == da->codec->channels.num)
- lavc_chmap = da->codec->channels;
- }
- mp_audio_set_channels(mpframe, &lavc_chmap);
+ if (priv->force_channel_map)
+ mp_aframe_set_chmap(mpframe, &da->codec->channels);
- mpframe->pts = out_pts;
+ if (out_pts == MP_NOPTS_VALUE)
+ out_pts = priv->next_pts;
+ mp_aframe_set_pts(mpframe, out_pts);
- if (mpframe->pts == MP_NOPTS_VALUE)
- mpframe->pts = priv->next_pts;
- if (mpframe->pts != MP_NOPTS_VALUE)
- priv->next_pts = mpframe->pts + mpframe->samples / (double)mpframe->rate;
+ priv->next_pts = mp_aframe_end_pts(mpframe);
#if LIBAVCODEC_VERSION_MICRO >= 100
AVFrameSideData *sd =
@@ -254,14 +246,14 @@ static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
priv->preroll_done = true;
}
- uint32_t skip = MPMIN(priv->skip_samples, mpframe->samples);
+ uint32_t skip = MPMIN(priv->skip_samples, mp_aframe_get_size(mpframe));
if (skip) {
- mp_audio_skip_samples(mpframe, skip);
+ mp_aframe_skip_samples(mpframe, skip);
priv->skip_samples -= skip;
}
- uint32_t trim = MPMIN(priv->trim_samples, mpframe->samples);
+ uint32_t trim = MPMIN(priv->trim_samples, mp_aframe_get_size(mpframe));
if (trim) {
- mpframe->samples -= trim;
+ mp_aframe_set_size(mpframe, mp_aframe_get_size(mpframe) - trim);
priv->trim_samples -= trim;
}
@@ -269,7 +261,6 @@ static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
av_frame_unref(priv->avframe);
- MP_DBG(da, "Decoded %d samples\n", mpframe->samples);
return true;
}
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index 4b3e8149ec..0ca20e5485 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -40,8 +40,9 @@ struct spdifContext {
uint8_t out_buffer[OUTBUF_SIZE];
bool need_close;
bool use_dts_hd;
- struct mp_audio fmt;
- struct mp_audio_pool *pool;
+ struct mp_aframe *fmt;
+ int sstride;
+ struct mp_aframe_pool *pool;
bool got_eof;
struct demux_packet *queued_packet;
};
@@ -84,7 +85,7 @@ static int init(struct dec_audio *da, const char *decoder)
da->priv = spdif_ctx;
spdif_ctx->log = da->log;
spdif_ctx->use_dts_hd = da->opts->dtshd;
- spdif_ctx->pool = mp_audio_pool_create(spdif_ctx);
+ spdif_ctx->pool = mp_aframe_pool_create(spdif_ctx);
if (strcmp(decoder, "spdif_dts_hd") == 0)
spdif_ctx->use_dts_hd = true;
@@ -198,6 +199,9 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt)
AVDictionary *format_opts = NULL;
+ spdif_ctx->fmt = mp_aframe_create();
+ talloc_steal(spdif_ctx, spdif_ctx->fmt);
+
int num_channels = 0;
int sample_format = 0;
int samplerate = 0;
@@ -246,9 +250,14 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt)
default:
abort();
}
- mp_audio_set_num_channels(&spdif_ctx->fmt, num_channels);
- mp_audio_set_format(&spdif_ctx->fmt, sample_format);
- spdif_ctx->fmt.rate = samplerate;
+
+ struct mp_chmap chmap;
+ mp_chmap_from_channels(&chmap, num_channels);
+ mp_aframe_set_chmap(spdif_ctx->fmt, &chmap);
+ mp_aframe_set_format(spdif_ctx->fmt, sample_format);
+ mp_aframe_set_rate(spdif_ctx->fmt, samplerate);
+
+ spdif_ctx->sstride = mp_aframe_get_sstride(spdif_ctx->fmt);
if (avformat_write_header(lavf_ctx, &format_opts) < 0) {
MP_FATAL(da, "libavformat spdif initialization failed.\n");
@@ -279,7 +288,7 @@ static bool send_packet(struct dec_audio *da, struct demux_packet *mpkt)
return true;
}
-static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
+static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
{
struct spdifContext *spdif_ctx = da->priv;
@@ -308,13 +317,21 @@ static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
goto done;
}
- int samples = spdif_ctx->out_buffer_len / spdif_ctx->fmt.sstride;
- *out = mp_audio_pool_get(spdif_ctx->pool, &spdif_ctx->fmt, samples);
- if (!*out)
+ *out = mp_aframe_new_ref(spdif_ctx->fmt);
+ int samples = spdif_ctx->out_buffer_len / spdif_ctx->sstride;
+ if (mp_aframe_pool_allocate(spdif_ctx->pool, *out, samples) < 0) {
+ TA_FREEP(out);
goto done;
+ }
+
+ uint8_t **data = mp_aframe_get_data_rw(*out);
+ if (!data) {
+ TA_FREEP(out);
+ goto done;
+ }
- memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
- (*out)->pts = pts;
+ memcpy(data[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
+ mp_aframe_set_pts(*out, pts);
done:
talloc_free(spdif_ctx->queued_packet);
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 1351cb8ecd..401e26fb7b 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -38,8 +38,6 @@
#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"
@@ -179,25 +177,24 @@ static void fix_audio_pts(struct dec_audio *da)
if (!da->current_frame)
return;
- if (da->current_frame->pts != MP_NOPTS_VALUE) {
- double newpts = da->current_frame->pts;
-
+ double frame_pts = mp_aframe_get_pts(da->current_frame);
+ if (frame_pts != MP_NOPTS_VALUE) {
if (da->pts != MP_NOPTS_VALUE)
- MP_STATS(da, "value %f audio-pts-err", da->pts - newpts);
+ MP_STATS(da, "value %f audio-pts-err", da->pts - frame_pts);
// Keep the interpolated timestamp if it doesn't deviate more
// than 1 ms from the real one. (MKV rounded timestamps.)
- if (da->pts == MP_NOPTS_VALUE || fabs(da->pts - newpts) > 0.001)
- da->pts = newpts;
+ if (da->pts == MP_NOPTS_VALUE || fabs(da->pts - frame_pts) > 0.001)
+ da->pts = frame_pts;
}
if (da->pts == MP_NOPTS_VALUE && da->header->missing_timestamps)
da->pts = 0;
- da->current_frame->pts = da->pts;
+ mp_aframe_set_pts(da->current_frame, da->pts);
if (da->pts != MP_NOPTS_VALUE)
- da->pts += da->current_frame->samples / (double)da->current_frame->rate;
+ da->pts += mp_aframe_duration(da->current_frame);
}
void audio_work(struct dec_audio *da)
@@ -228,11 +225,6 @@ void audio_work(struct dec_audio *da)
bool progress = da->ad_driver->receive_frame(da, &da->current_frame);
- if (da->current_frame && !mp_audio_config_valid(da->current_frame)) {
- talloc_free(da->current_frame);
- da->current_frame = NULL;
- }
-
da->current_state = da->current_frame ? DATA_OK : DATA_AGAIN;
if (!progress)
da->current_state = DATA_EOF;
@@ -242,10 +234,11 @@ void audio_work(struct dec_audio *da)
bool segment_end = da->current_state == DATA_EOF;
if (da->current_frame) {
- mp_audio_clip_timestamps(da->current_frame, da->start, da->end);
- if (da->current_frame->pts != MP_NOPTS_VALUE && da->start != MP_NOPTS_VALUE)
- segment_end = da->current_frame->pts >= da->end;
- if (da->current_frame->samples == 0) {
+ mp_aframe_clip_timestamps(da->current_frame, da->start, da->end);
+ double frame_pts = mp_aframe_get_pts(da->current_frame);
+ if (frame_pts != MP_NOPTS_VALUE && da->start != MP_NOPTS_VALUE)
+ segment_end = frame_pts >= da->end;
+ if (mp_aframe_get_size(da->current_frame) == 0) {
talloc_free(da->current_frame);
da->current_frame = NULL;
}
@@ -280,7 +273,7 @@ void audio_work(struct dec_audio *da)
// DATA_WAIT: waiting for demuxer; will receive a wakeup signal
// DATA_EOF: end of file, no more frames to be expected
// DATA_AGAIN: dropped frame or something similar
-int audio_get_frame(struct dec_audio *da, struct mp_audio **out_frame)
+int audio_get_frame(struct dec_audio *da, struct mp_aframe **out_frame)
{
*out_frame = NULL;
if (da->current_frame) {
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index 886b617b58..ea504328df 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -19,11 +19,10 @@
#define MPLAYER_DEC_AUDIO_H
#include "audio/chmap.h"
-#include "audio/audio.h"
+#include "audio/aframe.h"
#include "demux/demux.h"
#include "demux/stheader.h"
-struct mp_audio_buffer;
struct mp_decoder_list;
struct dec_audio {
@@ -48,7 +47,7 @@ struct dec_audio {
double start, end;
struct demux_packet *packet;
struct demux_packet *new_segment;
- struct mp_audio *current_frame;
+ struct mp_aframe *current_frame;
int current_state;
};
@@ -57,7 +56,7 @@ int audio_init_best_codec(struct dec_audio *d_audio);
void audio_uninit(struct dec_audio *d_audio);
void audio_work(struct dec_audio *d_audio);
-int audio_get_frame(struct dec_audio *d_audio, struct mp_audio **out_frame);
+int audio_get_frame(struct dec_audio *d_audio, struct mp_aframe **out_frame);
void audio_reset_decoding(struct dec_audio *d_audio);
diff --git a/audio/out/ao.c b/audio/out/ao.c
index ab94355fa7..c38c04c6a9 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -26,7 +26,6 @@
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
-#include "audio/audio.h"
#include "options/options.h"
#include "options/m_config.h"
@@ -480,12 +479,12 @@ bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
// --- The following functions just return immutable information.
-void ao_get_format(struct ao *ao, struct mp_audio *format)
+void ao_get_format(struct ao *ao,
+ int *samplerate, int *format, struct mp_chmap *channels)
{
- *format = (struct mp_audio){0};
- mp_audio_set_format(format, ao->format);
- mp_audio_set_channels(format, &ao->channels);
- format->rate = ao->samplerate;
+ *samplerate = ao->samplerate;
+ *format = ao->format;
+ *channels = ao->channels;
}
const char *ao_get_name(struct ao *ao)
diff --git a/audio/out/ao.h b/audio/out/ao.h
index 211f0e5974..fbbd76fee8 100644
--- a/audio/out/ao.h
+++ b/audio/out/ao.h
@@ -81,7 +81,6 @@ struct ao;
struct mpv_global;
struct input_ctx;
struct encode_lavc_context;
-struct mp_audio;
struct ao *ao_init_best(struct mpv_global *global,
int init_flags,
@@ -89,7 +88,8 @@ 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);
-void ao_get_format(struct ao *ao, struct mp_audio *format);
+void ao_get_format(struct ao *ao,
+ int *samplerate, int *format, struct mp_chmap *channels);
const char *ao_get_name(struct ao *ao);
const char *ao_get_description(struct ao *ao);
bool ao_untimed(struct ao *ao);
diff --git a/player/audio.c b/player/audio.c
index fcc442b974..25d7baa6af 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -352,6 +352,7 @@ static void ao_chain_uninit(struct ao_chain *ao_c)
af_destroy(ao_c->af);
talloc_free(ao_c->input_frame);
+ talloc_free(ao_c->input_format);
talloc_free(ao_c->ao_buffer);
talloc_free(ao_c);
}
@@ -368,6 +369,18 @@ void uninit_audio_chain(struct MPContext *mpctx)
}
}
+static void get_ao_format(struct ao *ao, struct mp_audio *aformat)
+{
+ int samplerate;
+ int format;
+ struct mp_chmap channels;
+ ao_get_format(ao, &samplerate, &format, &channels);
+ *aformat = (struct mp_audio){0};
+ mp_audio_set_format(aformat, format);
+ mp_audio_set_channels(aformat, &channels);
+ aformat->rate = samplerate;
+}
+
static void reinit_audio_filters_and_output(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
@@ -377,11 +390,9 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
struct af_stream *afs = ao_c->af;
if (ao_c->input_frame)
- mp_audio_copy_config(&ao_c->input_format, ao_c->input_frame);
+ mp_aframe_config_copy(ao_c->input_format, ao_c->input_frame);
- struct mp_audio in_format = ao_c->input_format;
-
- if (!mp_audio_config_valid(&in_format)) {
+ if (!mp_aframe_config_is_valid(ao_c->input_format)) {
// We don't know the audio format yet - so configure it later as we're
// resyncing. fill_audio_buffers() will call this function again.
mp_wakeup_core(mpctx);
@@ -390,18 +401,20 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
// Weak gapless audio: drain AO on decoder format changes
if (mpctx->ao_decoder_fmt && mpctx->ao && opts->gapless_audio < 0 &&
- !mp_audio_config_equals(mpctx->ao_decoder_fmt, &in_format))
+ !mp_aframe_config_equals(mpctx->ao_decoder_fmt, ao_c->input_format))
{
uninit_audio_out(mpctx);
}
+ struct mp_audio in_format;
+ mp_audio_config_from_aframe(&in_format, ao_c->input_format);
if (mpctx->ao && mp_audio_config_equals(&in_format, &afs->input))
return;
afs->output = (struct mp_audio){0};
if (mpctx->ao) {
- ao_get_format(mpctx->ao, &afs->output);
- } else if (af_fmt_is_pcm(in_format.format)) {
+ get_ao_format(mpctx->ao, &afs->output);
+ } else if (af_fmt_is_pcm(mp_aframe_get_format(ao_c->input_format))) {
afs->output.rate = opts->force_srate;
mp_audio_set_format(&afs->output, opts->audio_output_format);
if (opts->audio_output_channels.num_chmaps == 1) {
@@ -455,7 +468,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
struct mp_audio fmt = {0};
if (mpctx->ao)
- ao_get_format(mpctx->ao, &fmt);
+ get_ao_format(mpctx->ao, &fmt);
// Verify passthrough format was not changed.
if (mpctx->ao && af_fmt_is_spdif(afs->output.format)) {
@@ -477,7 +490,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
if (!audio_init_best_codec(ao_c->audio_src))
goto init_error;
reset_audio_state(mpctx);
- ao_c->input_format = (struct mp_audio){0};
+ mp_aframe_reset(ao_c->input_format);
mp_wakeup_core(mpctx); // reinit with new format next time
return;
}
@@ -492,8 +505,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
if (!mp_audio_config_equals(&afs->output, &afs->filter_output))
afs->initialized = 0;
- mpctx->ao_decoder_fmt = talloc(NULL, struct mp_audio);
- *mpctx->ao_decoder_fmt = in_format;
+ mpctx->ao_decoder_fmt = mp_aframe_create();
+ mp_aframe_config_copy(mpctx->ao_decoder_fmt, ao_c->input_format);
MP_INFO(mpctx, "AO: [%s] %s\n", ao_get_name(mpctx->ao),
mp_audio_config_to_str(&fmt));
@@ -580,6 +593,7 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
ao_c->pts = MP_NOPTS_VALUE;
ao_c->ao_buffer = mp_audio_buffer_create(NULL);
ao_c->ao = mpctx->ao;
+ ao_c->input_format = mp_aframe_create();
if (track) {
ao_c->track = track;
@@ -593,7 +607,7 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
if (mpctx->ao) {
struct mp_audio fmt;
- ao_get_format(mpctx->ao, &fmt);
+ get_ao_format(mpctx->ao, &fmt);
mp_audio_buffer_reinit(ao_c->ao_buffer, &fmt);
}
@@ -614,9 +628,7 @@ double written_audio_pts(struct MPContext *mpctx)
if (!ao_c)
return MP_NOPTS_VALUE;
- struct mp_audio in_format = ao_c->input_format;
-
- if (!mp_audio_config_valid(&in_format) || ao_c->af->initialized < 1)
+ if (ao_c->af->initialized < 1)
return MP_NOPTS_VALUE;
// first calculate the end pts of audio that has been output by decoder
@@ -653,7 +665,7 @@ static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags
return 0;
struct ao *ao = mpctx->ao;
struct mp_audio out_format;
- ao_get_format(ao, &out_format);
+ get_ao_format(ao, &out_format);
#if HAVE_ENCODING
encode_lavc_set_audio_pts(mpctx->encode_lavc_ctx, playing_audio_pts(mpctx));
#endif
@@ -706,7 +718,7 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
return true;
struct mp_audio out_format = {0};
- ao_get_format(mpctx->ao, &out_format);
+ get_ao_format(mpctx->ao, &out_format);
double play_samplerate = out_format.rate / mpctx->audio_speed;
if (!opts->initial_audio_sync) {
@@ -879,14 +891,19 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
}
// On format change, make sure to drain the filter chain.
- if (!mp_audio_config_equals(&afs->input, ao_c->input_frame)) {
+ struct mp_audio in_format;
+ mp_audio_config_from_aframe(&in_format, ao_c->input_format);
+ if (!mp_audio_config_equals(&afs->input, &in_format)) {
copy_output(mpctx, outbuf, minsamples, endpts, true, &eof);
res = AD_NEW_FMT;
break;
}
- struct mp_audio *mpa = ao_c->input_frame;
+ struct mp_audio *mpa = mp_audio_from_aframe(ao_c->input_frame);
+ talloc_free(ao_c->input_frame);
ao_c->input_frame = NULL;
+ if (!mpa)
+ abort();
if (mpa->pts == MP_NOPTS_VALUE) {
ao_c->pts = MP_NOPTS_VALUE;
} else {
@@ -990,7 +1007,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
}
struct mp_audio out_format = {0};
- ao_get_format(mpctx->ao, &out_format);
+ get_ao_format(mpctx->ao, &out_format);
double play_samplerate = out_format.rate / mpctx->audio_speed;
int align = af_format_sample_alignment(out_format.format);
diff --git a/player/command.c b/player/command.c
index b023e350c9..51b025cad4 100644
--- a/player/command.c
+++ b/player/command.c
@@ -56,7 +56,7 @@
#include "video/decode/vd.h"
#include "video/out/vo.h"
#include "video/csputils.h"
-#include "audio/audio_buffer.h"
+#include "audio/aframe.h"
#include "audio/out/ao.h"
#include "audio/filter/af.h"
#include "video/decode/dec_video.h"
@@ -2019,17 +2019,20 @@ static int mp_property_audio_codec(void *ctx, struct m_property *prop,
return m_property_strdup_ro(action, arg, c);
}
-static int property_audiofmt(struct mp_audio a, int action, void *arg)
+static int property_audiofmt(struct mp_aframe *fmt, int action, void *arg)
{
- if (!mp_audio_config_valid(&a))
+ if (!fmt || !mp_aframe_config_is_valid(fmt))
return M_PROPERTY_UNAVAILABLE;
+ struct mp_chmap chmap = {0};
+ mp_aframe_get_chmap(fmt, &chmap);
+
struct m_sub_property props[] = {
- {"samplerate", SUB_PROP_INT(a.rate)},
- {"channel-count", SUB_PROP_INT(a.channels.num)},
- {"channels", SUB_PROP_STR(mp_chmap_to_str(&a.channels))},
- {"hr-channels", SUB_PROP_STR(mp_chmap_to_str_hr(&a.channels))},
- {"format", SUB_PROP_STR(af_fmt_to_str(a.format))},
+ {"samplerate", SUB_PROP_INT(mp_aframe_get_rate(fmt))},
+ {"channel-count", SUB_PROP_INT(chmap.num)},
+ {"channels", SUB_PROP_STR(mp_chmap_to_str(&chmap))},
+ {"hr-channels", SUB_PROP_STR(mp_chmap_to_str_hr(&chmap))},
+ {"format", SUB_PROP_STR(af_fmt_to_str(mp_aframe_get_format(fmt)))},
{0}
};
@@ -2040,20 +2043,28 @@ static int mp_property_audio_params(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
- struct mp_audio fmt = {0};
- if (mpctx->ao_chain)
- fmt = mpctx->ao_chain->input_format;
- return property_audiofmt(fmt, action, arg);
+ return property_audiofmt(mpctx->ao_chain ? mpctx->ao_chain->input_format : NULL,
+ action, arg);
}
static int mp_property_audio_out_params(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
- struct mp_audio fmt = {0};
- if (mpctx->ao)
- ao_get_format(mpctx->ao, &fmt);
- return property_audiofmt(fmt, action, arg);
+ struct mp_aframe *frame = NULL;
+ if (mpctx->ao) {
+ frame = mp_aframe_create();
+ int samplerate;
+ int format;
+ struct mp_chmap channels;
+ ao_get_format(mpctx->ao, &samplerate, &format, &channels);
+ mp_aframe_set_rate(frame, samplerate);
+ mp_aframe_set_format(frame, format);
+ mp_aframe_set_chmap(frame, &channels);
+ }
+ int r = property_audiofmt(frame, action, arg);
+ talloc_free(frame);
+ return r;
}
/// Balance (RW)
diff --git a/player/core.h b/player/core.h
index bdb8b4c3a5..ea7e0c1ec1 100644
--- a/player/core.h
+++ b/player/core.h
@@ -28,7 +28,7 @@
#include "common/common.h"
#include "options/options.h"
#include "sub/osd.h"
-#include "audio/audio.h"
+#include "audio/aframe.h"
#include "video/mp_image.h"
#include "video/out/vo.h"
@@ -205,10 +205,10 @@ struct ao_chain {
double ao_resume_time;
// 1-element input frame queue.
- struct mp_audio *input_frame;
+ struct mp_aframe *input_frame;
- // Last known input_mpi format (so vf can be reinitialized any time).
- struct mp_audio input_format;
+ // Last known input_mpi format (so af can be reinitialized any time).
+ struct mp_aframe *input_format;
struct track *track;
struct lavfi_pad *filter_src;
@@ -313,7 +313,7 @@ typedef struct MPContext {
struct lavfi *lavfi;
struct ao *ao;
- struct mp_audio *ao_decoder_fmt; // for weak gapless audio check
+ struct mp_aframe *ao_decoder_fmt; // for weak gapless audio check
struct ao_chain *ao_chain;
struct vo_chain *vo_chain;
diff --git a/player/lavfi.c b/player/lavfi.c
index ee0ca281e4..e5bfe7fdf5 100644
--- a/player/lavfi.c
+++ b/player/lavfi.c
@@ -37,7 +37,8 @@
#include "common/av_common.h"
#include "common/msg.h"
-#include "audio/audio.h"
+#include "audio/format.h"
+#include "audio/aframe.h"
#include "video/mp_image.h"
#include "audio/fmt-conversion.h"
#include "video/fmt-conversion.h"
@@ -96,7 +97,7 @@ struct lavfi_pad {
// 1-frame queue (used for both input and output)
struct mp_image *pending_v;
- struct mp_audio *pending_a;
+ struct mp_aframe *pending_a;
// -- dir==LAVFI_IN
@@ -107,7 +108,7 @@ struct lavfi_pad {
// used to check for format changes manually
struct mp_image *in_fmt_v;
- struct mp_audio in_fmt_a;
+ struct mp_aframe *in_fmt_a;
// -- dir==LAVFI_OUT
@@ -199,7 +200,7 @@ static void free_graph(struct lavfi *c)
pad->filter_pad = -1;
pad->buffer = NULL;
TA_FREEP(&pad->in_fmt_v);
- pad->in_fmt_a = (struct mp_audio){0};
+ TA_FREEP(&pad->in_fmt_a);
pad->buffer_is_eof = false;
pad->input_needed = false;
pad->input_waiting = false;
@@ -312,9 +313,14 @@ static void send_global_eof(struct lavfi *c)
// libavfilter allows changing some parameters on the fly, but not
// others.
-static bool is_aformat_ok(struct mp_audio *a, struct mp_audio *b)
+static bool is_aformat_ok(struct mp_aframe *a, struct mp_aframe *b)
{
- return mp_audio_config_equals(a, b);
+ struct mp_chmap ca = {0}, cb = {0};
+ mp_aframe_get_chmap(a, &ca);
+ mp_aframe_get_chmap(b, &cb);
+ return mp_chmap_equals(&ca, &cb) &&
+ mp_aframe_get_rate(a) == mp_aframe_get_rate(b) &&
+ mp_aframe_get_format(a) == mp_aframe_get_format(b);
}
static bool is_vformat_ok(struct mp_image *a, struct mp_image *b)
{
@@ -331,9 +337,9 @@ static void check_format_changes(struct lavfi *c)
if (!pad->buffer || pad->dir != LAVFI_IN)
continue;
- if (pad->type == STREAM_AUDIO && pad->pending_a && pad->in_fmt_a.format) {
+ if (pad->type == STREAM_AUDIO && pad->pending_a && pad->in_fmt_a) {
c->draining_new_format |= !is_aformat_ok(pad->pending_a,
- &pad->in_fmt_a);
+ pad->in_fmt_a);
}
if (pad->type == STREAM_VIDEO && pad->pending_v && pad->in_fmt_v) {
c->draining_new_format |= !is_vformat_ok(pad->pending_v,
@@ -389,7 +395,10 @@ static bool init_pads(struct lavfi *c)
if (pad->pending_a) {
assert(pad->type == STREAM_AUDIO);
- mp_audio_copy_config(&pad->in_fmt_a, pad->pending_a);
+ pad->in_fmt_a = mp_aframe_new_ref(pad->pending_a);
+ if (!pad->in_fmt_a)
+ goto error;
+ mp_aframe_unref_data(pad->in_fmt_a);
} else if (pad->pending_v) {
assert(pad->type == STREAM_VIDEO);
pad->in_fmt_v = mp_image_new_ref(pad->pending_v);
@@ -400,9 +409,11 @@ static bool init_pads(struct lavfi *c)
// libavfilter makes this painful. Init it with a dummy config,
// just so we can tell it the stream is EOF.
if (pad->type == STREAM_AUDIO) {
- mp_audio_set_format(&pad->in_fmt_a, AF_FORMAT_FLOAT);
- mp_audio_set_num_channels(&pad->in_fmt_a, 2);
- pad->in_fmt_a.rate = 48000;
+ pad->in_fmt_a = mp_aframe_create();
+ mp_aframe_set_format(pad->in_fmt_a, AF_FORMAT_FLOAT);
+ mp_aframe_set_chmap(pad->in_fmt_a,
+ &(struct mp_chmap)MP_CHMAP_INIT_STEREO);
+ mp_aframe_set_rate(pad->in_fmt_a, 48000);
} else if (pad->type == STREAM_VIDEO) {
pad->in_fmt_v = talloc_zero(NULL, struct mp_image);
mp_image_setfmt(pad->in_fmt_v, IMGFMT_420P);
@@ -421,11 +432,13 @@ static bool init_pads(struct lavfi *c)
char *filter_name = NULL;
if (pad->type == STREAM_AUDIO) {
params->time_base = pad->timebase =
- (AVRational){1, pad->in_fmt_a.rate};
- params->format = af_to_avformat(pad->in_fmt_a.format);
- params->sample_rate = pad->in_fmt_a.rate;
- params->channel_layout =
- mp_chmap_to_lavc(&pad->in_fmt_a.channels);
+ (AVRational){1, mp_aframe_get_rate(pad->in_fmt_a)};
+ params->format =
+ af_to_avformat(mp_aframe_get_format(pad->in_fmt_a));
+ params->sample_rate = mp_aframe_get_rate(pad->in_fmt_a);
+ struct mp_chmap chmap = {0};
+ mp_aframe_get_chmap(pad->in_fmt_a, &chmap);
+ params->channel_layout = mp_chmap_to_lavc(&chmap);
filter_name = "abuffer";
} else if (pad->type == STREAM_VIDEO) {
params->time_base = pad->timebase = AV_TIME_BASE_Q;
@@ -565,8 +578,8 @@ static void feed_input_pads(struct lavfi *c)
frame = mp_image_to_av_frame_and_unref(pad->pending_v);
pad->pending_v = NULL;
} else if (pad->pending_a) {
- pts = pad->pending_a->pts;
- frame = mp_audio_to_avframe_and_unref(pad->pending_a);
+ pts = mp_aframe_get_pts(pad->pending_a);
+ frame = mp_aframe_to_avframe_and_unref(pad->pending_a);
pad->pending_a = NULL;
} else {
if (!pad->input_eof) {
@@ -621,9 +634,9 @@ static void read_output_pads(struct lavfi *c)
pad->output_needed = false;
double pts = mp_pts_from_av(c->tmp_frame->pts, &pad->timebase);
if (pad->type == STREAM_AUDIO) {
- pad->pending_a = mp_audio_from_avframe(c->tmp_frame);
+ pad->pending_a = mp_aframe_from_avframe(c->tmp_frame);
if (pad->pending_a)
- pad->pending_a->pts = pts;
+ mp_aframe_set_pts(pad->pending_a, pts);
} else if (pad->type == STREAM_VIDEO) {
pad->pending_v = mp_image_from_av_frame(c->tmp_frame);
if (pad->pending_v)
@@ -733,7 +746,7 @@ static int lavfi_request_frame(struct lavfi_pad *pad)
// DATA_STARVE: needs more input data
// DATA_WAIT: needs more input data, and all inputs in LAVFI_WAIT state
// DATA_EOF: no more data
-int lavfi_request_frame_a(struct lavfi_pad *pad, struct mp_audio **out_aframe)
+int lavfi_request_frame_a(struct lavfi_pad *pad, struct mp_aframe **out_aframe)
{
int r = lavfi_request_frame(pad);
*out_aframe = pad->pending_a;
@@ -787,7 +800,7 @@ static void lavfi_sent_frame(struct lavfi_pad *pad)
}
// See lavfi_send_status() for remarks.
-void lavfi_send_frame_a(struct lavfi_pad *pad, struct mp_audio *aframe)
+void lavfi_send_frame_a(struct lavfi_pad *pad, struct mp_aframe *aframe)
{
assert(pad->type == STREAM_AUDIO);
assert(!pad->pending_a);
diff --git a/player/lavfi.h b/player/lavfi.h
index ef19a14179..92c32954d7 100644
--- a/player/lavfi.h
+++ b/player/lavfi.h
@@ -5,7 +5,7 @@ struct mp_log;
struct lavfi;
struct lavfi_pad;
struct mp_image;
-struct mp_audio;
+struct mp_aframe;
enum lavfi_direction {
LAVFI_IN = 1,
@@ -25,11 +25,11 @@ bool lavfi_has_failed(struct lavfi *c);
void lavfi_seek_reset(struct lavfi *c);
void lavfi_pad_set_hwdec_devs(struct lavfi_pad *pad,
struct mp_hwdec_devices *hwdevs);
-int lavfi_request_frame_a(struct lavfi_pad *pad, struct mp_audio **out_aframe);
+int lavfi_request_frame_a(struct lavfi_pad *pad, struct mp_aframe **out_aframe);
int lavfi_request_frame_v(struct lavfi_pad *pad, struct mp_image **out_vframe);
bool lavfi_needs_input(struct lavfi_pad *pad);
void lavfi_send_status(struct lavfi_pad *pad, int status);
-void lavfi_send_frame_a(struct lavfi_pad *pad, struct mp_audio *aframe);
+void lavfi_send_frame_a(struct lavfi_pad *pad, struct mp_aframe *aframe);
void lavfi_send_frame_v(struct lavfi_pad *pad, struct mp_image *vframe);
#endif
diff --git a/player/loadfile.c b/player/loadfile.c
index 4a5c0e1d2c..543fd02458 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -43,8 +43,6 @@
#include "common/recorder.h"
#include "input/input.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"
diff --git a/player/playloop.c b/player/playloop.c
index ea73981a4f..c9bc91010b 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -1053,7 +1053,7 @@ static void handle_complex_filter_decoders(struct MPContext *mpctx)
continue;
if (track->d_audio) {
audio_work(track->d_audio);
- struct mp_audio *fr;
+ struct mp_aframe *fr;
int res = audio_get_frame(track->d_audio, &fr);
if (res == DATA_OK) {
lavfi_send_frame_a(track->sink, fr);
diff --git a/player/video.c b/player/video.c
index 0dca3a597f..3a9941d8e0 100644
--- a/player/video.c
+++ b/player/video.c
@@ -1053,9 +1053,11 @@ static double find_best_speed(struct MPContext *mpctx, double vsync)
static bool using_spdif_passthrough(struct MPContext *mpctx)
{
if (mpctx->ao_chain && mpctx->ao_chain->ao) {
- struct mp_audio out_format = {0};
- ao_get_format(mpctx->ao_chain->ao, &out_format);
- return !af_fmt_is_pcm(out_format.format);
+ int samplerate;
+ int format;
+ struct mp_chmap channels;
+ ao_get_format(mpctx->ao_chain->ao, &samplerate, &format, &channels);
+ return !af_fmt_is_pcm(format);
}
return false;
}
diff --git a/wscript_build.py b/wscript_build.py
index 600c1c93fe..15e04d11cc 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -157,6 +157,7 @@ def build(ctx):
( "audio/chmap_sel.c" ),
( "audio/fmt-conversion.c" ),
( "audio/format.c" ),
+ ( "audio/aframe.c" ),
( "audio/decode/ad_lavc.c" ),
( "audio/decode/ad_spdif.c" ),
( "audio/decode/dec_audio.c" ),