diff options
-rw-r--r-- | audio/aframe.c | 444 | ||||
-rw-r--r-- | audio/aframe.h | 53 | ||||
-rw-r--r-- | audio/audio.c | 24 | ||||
-rw-r--r-- | audio/audio.h | 4 | ||||
-rw-r--r-- | audio/decode/ad.h | 4 | ||||
-rw-r--r-- | audio/decode/ad_lavc.c | 33 | ||||
-rw-r--r-- | audio/decode/ad_spdif.c | 41 | ||||
-rw-r--r-- | audio/decode/dec_audio.c | 33 | ||||
-rw-r--r-- | audio/decode/dec_audio.h | 7 | ||||
-rw-r--r-- | audio/out/ao.c | 11 | ||||
-rw-r--r-- | audio/out/ao.h | 4 | ||||
-rw-r--r-- | player/audio.c | 57 | ||||
-rw-r--r-- | player/command.c | 43 | ||||
-rw-r--r-- | player/core.h | 10 | ||||
-rw-r--r-- | player/lavfi.c | 59 | ||||
-rw-r--r-- | player/lavfi.h | 6 | ||||
-rw-r--r-- | player/loadfile.c | 2 | ||||
-rw-r--r-- | player/playloop.c | 2 | ||||
-rw-r--r-- | player/video.c | 8 | ||||
-rw-r--r-- | wscript_build.py | 1 |
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" ), |