summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-16 21:00:20 +0200
committerwm4 <wm4@nowhere>2017-08-16 21:10:54 +0200
commit1f593beeb4c649c4718db6f9a4ee37a897af6ead (patch)
tree08d78c2cc473c234fc85ed55a48473f89c76f308
parent16e0a3948288e37034c572617cf47b0a4dc0e10e (diff)
downloadmpv-1f593beeb4c649c4718db6f9a4ee37a897af6ead.tar.bz2
mpv-1f593beeb4c649c4718db6f9a4ee37a897af6ead.tar.xz
audio: introduce a new type to hold audio frames
This is pretty pointless, but I believe it allows us to claim that the new code is not affected by the copyright of the old code. This is needed, because the original mp_audio struct was written by someone who has disagreed with LGPL relicensing (it was called af_data at the time, and was defined in af.h). The "GPL'ed" struct contents that surive are pretty trivial: just the data pointer, and some metadata like the format, samplerate, etc. - but at least in this case, any new code would be extremely similar anyway, and I'm not really sure whether it's OK to claim different copyright. So what we do is we just use AVFrame (which of course is LGPL with 100% certainty), and add some accessors around it to adapt it to mpv conventions. Also, this gets rid of some annoying conventions of mp_audio, like the struct fields that require using an accessor to write to them anyway. For the most part, this change is only dumb replacements of mp_audio related functions and fields. One minor actual change is that you can't allocate the new type on the stack anymore. Some code still uses mp_audio. All audio filter code will be deleted, so it makes no sense to convert this code. (Audio filters which are LGPL and which we keep will have to be ported to a new filter infrastructure anyway.) player/audio.c uses it because it interacts with the old filter code. push.c has some complex use of mp_audio and mp_audio_buffer, but this and pull.c will most likely be rewritten to do something else.
-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) {