aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--audio/decode/ad.h49
-rw-r--r--audio/decode/ad_lavc.c130
-rw-r--r--audio/decode/ad_spdif.c158
-rw-r--r--audio/decode/dec_audio.c309
-rw-r--r--audio/decode/dec_audio.h66
-rw-r--r--common/common.h8
-rw-r--r--filters/f_decoder_wrapper.c80
-rw-r--r--filters/f_decoder_wrapper.h11
-rw-r--r--filters/f_output_chain.c9
-rw-r--r--options/options.c1
-rw-r--r--player/audio.c220
-rw-r--r--player/command.c5
-rw-r--r--player/core.h10
-rw-r--r--player/loadfile.c30
-rw-r--r--player/main.c1
-rw-r--r--player/playloop.c38
-rw-r--r--player/video.c1
-rw-r--r--wscript_build.py1
18 files changed, 330 insertions, 797 deletions
diff --git a/audio/decode/ad.h b/audio/decode/ad.h
deleted file mode 100644
index a8384c277f..0000000000
--- a/audio/decode/ad.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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/>.
- */
-
-#ifndef MPLAYER_AD_H
-#define MPLAYER_AD_H
-
-#include "common/codecs.h"
-#include "demux/stheader.h"
-#include "demux/demux.h"
-
-#include "audio/format.h"
-#include "audio/aframe.h"
-#include "dec_audio.h"
-
-struct mp_decoder_list;
-
-/* interface of audio decoder drivers */
-struct ad_functions {
- const char *name;
- void (*add_decoders)(struct mp_decoder_list *list);
- int (*init)(struct dec_audio *da, const char *decoder);
- void (*uninit)(struct dec_audio *da);
- int (*control)(struct dec_audio *da, int cmd, void *arg);
- // Return whether or not the packet has been consumed.
- 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_aframe **out);
-};
-
-enum ad_ctrl {
- ADCTRL_RESET = 1, // flush and reset state, e.g. after seeking
-};
-
-#endif /* MPLAYER_AD_H */
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index fb429d567b..7713a506a6 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -27,27 +27,30 @@
#include <libavutil/intreadwrite.h>
#include "mpv_talloc.h"
-
-#include "config.h"
+#include "audio/aframe.h"
+#include "audio/fmt-conversion.h"
#include "common/av_common.h"
#include "common/codecs.h"
+#include "common/global.h"
#include "common/msg.h"
+#include "demux/packet.h"
+#include "demux/stheader.h"
+#include "filters/f_decoder_wrapper.h"
+#include "filters/filter_internal.h"
#include "options/options.h"
-#include "ad.h"
-#include "audio/fmt-conversion.h"
-
struct priv {
AVCodecContext *avctx;
AVFrame *avframe;
- bool force_channel_map;
+ struct mp_chmap force_channel_map;
uint32_t skip_samples, trim_samples;
bool preroll_done;
double next_pts;
AVRational codec_timebase;
-};
+ bool eof_returned;
-static void uninit(struct dec_audio *da);
+ struct mp_decoder public;
+};
#define OPT_BASE_STRUCT struct ad_lavc_params
struct ad_lavc_params {
@@ -73,26 +76,24 @@ const struct m_sub_options ad_lavc_conf = {
},
};
-static int init(struct dec_audio *da, const char *decoder)
+static bool init(struct mp_filter *da, struct mp_codec_params *codec,
+ const char *decoder)
{
- struct MPOpts *mpopts = da->opts;
+ struct priv *ctx = da->priv;
+ struct MPOpts *mpopts = da->global->opts;
struct ad_lavc_params *opts = mpopts->ad_lavc_params;
AVCodecContext *lavc_context;
AVCodec *lavc_codec;
- struct mp_codec_params *c = da->codec;
-
- struct priv *ctx = talloc_zero(NULL, struct priv);
- da->priv = ctx;
- ctx->codec_timebase = mp_get_codec_timebase(da->codec);
+ ctx->codec_timebase = mp_get_codec_timebase(codec);
- ctx->force_channel_map = c->force_channels;
+ if (codec->force_channels)
+ ctx->force_channel_map = codec->channels;
lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec) {
MP_ERR(da, "Cannot find codec '%s' in libavcodec...\n", decoder);
- uninit(da);
- return 0;
+ return false;
}
lavc_context = avcodec_alloc_context3(lavc_codec);
@@ -121,10 +122,9 @@ static int init(struct dec_audio *da, const char *decoder)
mp_set_avopts(da->log, lavc_context, opts->avopts);
- if (mp_set_avctx_codec_headers(lavc_context, c) < 0) {
+ if (mp_set_avctx_codec_headers(lavc_context, codec) < 0) {
MP_ERR(da, "Could not set decoder parameters.\n");
- uninit(da);
- return 0;
+ return false;
}
mp_set_avcodec_threads(da->log, lavc_context, opts->threads);
@@ -132,41 +132,35 @@ static int init(struct dec_audio *da, const char *decoder)
/* open it */
if (avcodec_open2(lavc_context, lavc_codec, NULL) < 0) {
MP_ERR(da, "Could not open codec.\n");
- uninit(da);
- return 0;
+ return false;
}
ctx->next_pts = MP_NOPTS_VALUE;
- return 1;
+ return true;
}
-static void uninit(struct dec_audio *da)
+static void destroy(struct mp_filter *da)
{
struct priv *ctx = da->priv;
- if (!ctx)
- return;
avcodec_free_context(&ctx->avctx);
av_frame_free(&ctx->avframe);
}
-static int control(struct dec_audio *da, int cmd, void *arg)
+static void reset(struct mp_filter *da)
{
struct priv *ctx = da->priv;
- switch (cmd) {
- case ADCTRL_RESET:
- avcodec_flush_buffers(ctx->avctx);
- ctx->skip_samples = 0;
- ctx->trim_samples = 0;
- ctx->preroll_done = false;
- ctx->next_pts = MP_NOPTS_VALUE;
- return CONTROL_TRUE;
- }
- return CONTROL_UNKNOWN;
+
+ avcodec_flush_buffers(ctx->avctx);
+ ctx->skip_samples = 0;
+ ctx->trim_samples = 0;
+ ctx->preroll_done = false;
+ ctx->next_pts = MP_NOPTS_VALUE;
+ ctx->eof_returned = false;
}
-static bool send_packet(struct dec_audio *da, struct demux_packet *mpkt)
+static bool send_packet(struct mp_filter *da, struct demux_packet *mpkt)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
@@ -190,7 +184,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_aframe **out)
+static bool receive_frame(struct mp_filter *da, struct mp_frame *out)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
@@ -200,7 +194,8 @@ static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
if (ret == AVERROR_EOF) {
// If flushing was initialized earlier and has ended now, make it start
// over in case we get new packets at some point in the future.
- control(da, ADCTRL_RESET, NULL);
+ // (Dont' reset the filter itself, we want to keep other state.)
+ avcodec_flush_buffers(priv->avctx);
return false;
} else if (ret < 0 && ret != AVERROR(EAGAIN)) {
MP_ERR(da, "Error decoding audio.\n");
@@ -220,8 +215,8 @@ static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
if (!mpframe)
return true;
- if (priv->force_channel_map)
- mp_aframe_set_chmap(mpframe, &da->codec->channels);
+ if (priv->force_channel_map.num)
+ mp_aframe_set_chmap(mpframe, &priv->force_channel_map);
if (out_pts == MP_NOPTS_VALUE)
out_pts = priv->next_pts;
@@ -257,24 +252,57 @@ static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
priv->trim_samples -= trim;
}
- *out = mpframe;
+ *out = MAKE_FRAME(MP_FRAME_AUDIO, mpframe);
av_frame_unref(priv->avframe);
return true;
}
+static void process(struct mp_filter *ad)
+{
+ struct priv *priv = ad->priv;
+
+ lavc_process(ad, &priv->eof_returned, send_packet, receive_frame);
+}
+
+static const struct mp_filter_info ad_lavc_filter = {
+ .name = "ad_lavc",
+ .priv_size = sizeof(struct priv),
+ .process = process,
+ .reset = reset,
+ .destroy = destroy,
+};
+
+static struct mp_decoder *create(struct mp_filter *parent,
+ struct mp_codec_params *codec,
+ const char *decoder)
+{
+ struct mp_filter *da = mp_filter_create(parent, &ad_lavc_filter);
+ if (!da)
+ return NULL;
+
+ mp_filter_add_pin(da, MP_PIN_IN, "in");
+ mp_filter_add_pin(da, MP_PIN_OUT, "out");
+
+ da->log = mp_log_new(da, parent->log, NULL);
+
+ struct priv *priv = da->priv;
+ priv->public.f = da;
+
+ if (!init(da, codec, decoder)) {
+ talloc_free(da);
+ return NULL;
+ }
+ return &priv->public;
+}
+
static void add_decoders(struct mp_decoder_list *list)
{
mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
}
-const struct ad_functions ad_lavc = {
- .name = "lavc",
+const struct mp_decoder_fns ad_lavc = {
+ .create = create,
.add_decoders = add_decoders,
- .init = init,
- .uninit = uninit,
- .control = control,
- .send_packet = send_packet,
- .receive_frame = receive_frame,
};
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index cc800224e9..c97c62ddaa 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -24,11 +24,16 @@
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
-#include "config.h"
-#include "common/msg.h"
+#include "audio/aframe.h"
+#include "audio/format.h"
#include "common/av_common.h"
+#include "common/codecs.h"
+#include "common/msg.h"
+#include "demux/packet.h"
+#include "demux/stheader.h"
+#include "filters/f_decoder_wrapper.h"
+#include "filters/filter_internal.h"
#include "options/options.h"
-#include "ad.h"
#define OUTBUF_SIZE 65536
@@ -43,8 +48,8 @@ struct spdifContext {
struct mp_aframe *fmt;
int sstride;
struct mp_aframe_pool *pool;
- bool got_eof;
- struct demux_packet *queued_packet;
+
+ struct mp_decoder public;
};
static int write_packet(void *p, uint8_t *buf, int buf_size)
@@ -62,7 +67,8 @@ static int write_packet(void *p, uint8_t *buf, int buf_size)
return buf_size;
}
-static void uninit(struct dec_audio *da)
+// (called on both filter destruction _and_ if lavf fails to init)
+static void destroy(struct mp_filter *da)
{
struct spdifContext *spdif_ctx = da->priv;
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
@@ -74,26 +80,11 @@ static void uninit(struct dec_audio *da)
av_freep(&lavf_ctx->pb->buffer);
av_freep(&lavf_ctx->pb);
avformat_free_context(lavf_ctx);
- talloc_free(spdif_ctx->queued_packet);
spdif_ctx->lavf_ctx = NULL;
}
}
-static int init(struct dec_audio *da, const char *decoder)
-{
- struct spdifContext *spdif_ctx = talloc_zero(NULL, struct spdifContext);
- da->priv = spdif_ctx;
- spdif_ctx->log = da->log;
- spdif_ctx->pool = mp_aframe_pool_create(spdif_ctx);
-
- if (strcmp(decoder, "spdif_dts_hd") == 0)
- spdif_ctx->use_dts_hd = true;
-
- spdif_ctx->codec_id = mp_codec_to_av_codec_id(da->codec->codec);
- return spdif_ctx->codec_id != AV_CODEC_ID_NONE;
-}
-
-static void determine_codec_params(struct dec_audio *da, AVPacket *pkt,
+static void determine_codec_params(struct mp_filter *da, AVPacket *pkt,
int *out_profile, int *out_rate)
{
struct spdifContext *spdif_ctx = da->priv;
@@ -156,7 +147,7 @@ done:
MP_WARN(da, "Failed to parse codec profile.\n");
}
-static int init_filter(struct dec_audio *da, AVPacket *pkt)
+static int init_filter(struct mp_filter *da, AVPacket *pkt)
{
struct spdifContext *spdif_ctx = da->priv;
@@ -270,39 +261,36 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt)
return 0;
fail:
- uninit(da);
+ destroy(da);
+ mp_filter_internal_mark_failed(da);
return -1;
}
-
-static bool send_packet(struct dec_audio *da, struct demux_packet *mpkt)
+static void process(struct mp_filter *da)
{
struct spdifContext *spdif_ctx = da->priv;
- if (spdif_ctx->queued_packet || spdif_ctx->got_eof)
- return false;
-
- spdif_ctx->queued_packet = mpkt ? demux_copy_packet(mpkt) : NULL;
- spdif_ctx->got_eof = !mpkt;
- return true;
-}
-
-static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
-{
- struct spdifContext *spdif_ctx = da->priv;
+ if (!mp_pin_can_transfer_data(da->ppins[1], da->ppins[0]))
+ return;
- if (spdif_ctx->got_eof) {
- spdif_ctx->got_eof = false;
- return false;
+ struct mp_frame inframe = mp_pin_out_read(da->ppins[0]);
+ if (inframe.type == MP_FRAME_EOF) {
+ mp_pin_in_write(da->ppins[1], inframe);
+ return;
+ } else if (inframe.type != MP_FRAME_PACKET) {
+ if (inframe.type) {
+ MP_ERR(da, "unknown frame type\n");
+ mp_filter_internal_mark_failed(da);
+ }
+ return;
}
- if (!spdif_ctx->queued_packet)
- return true;
-
- double pts = spdif_ctx->queued_packet->pts;
+ struct demux_packet *mpkt = inframe.data;
+ struct mp_aframe *out = NULL;
+ double pts = mpkt->pts;
AVPacket pkt;
- mp_set_av_packet(&pkt, spdif_ctx->queued_packet, NULL);
+ mp_set_av_packet(&pkt, mpkt, NULL);
pkt.pts = pkt.dts = 0;
if (!spdif_ctx->lavf_ctx) {
if (init_filter(da, &pkt) < 0)
@@ -316,39 +304,29 @@ static bool receive_frame(struct dec_audio *da, struct mp_aframe **out)
goto done;
}
- *out = mp_aframe_new_ref(spdif_ctx->fmt);
+ 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);
+ 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);
+ uint8_t **data = mp_aframe_get_data_rw(out);
if (!data) {
- TA_FREEP(out);
+ TA_FREEP(&out);
goto done;
}
memcpy(data[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
- mp_aframe_set_pts(*out, pts);
+ mp_aframe_set_pts(out, pts);
done:
- talloc_free(spdif_ctx->queued_packet);
- spdif_ctx->queued_packet = NULL;
- return true;
-}
-
-static int control(struct dec_audio *da, int cmd, void *arg)
-{
- struct spdifContext *spdif_ctx = da->priv;
- switch (cmd) {
- case ADCTRL_RESET:
- talloc_free(spdif_ctx->queued_packet);
- spdif_ctx->queued_packet = NULL;
- spdif_ctx->got_eof = false;
- return CONTROL_TRUE;
+ talloc_free(mpkt);
+ if (out) {
+ mp_pin_in_write(da->ppins[1], MAKE_FRAME(MP_FRAME_AUDIO, out));
+ } else {
+ mp_filter_internal_mark_failed(da);
}
- return CONTROL_UNKNOWN;
}
static const int codecs[] = {
@@ -405,12 +383,44 @@ struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref)
return list;
}
-const struct ad_functions ad_spdif = {
- .name = "spdif",
- .add_decoders = NULL,
- .init = init,
- .uninit = uninit,
- .control = control,
- .send_packet = send_packet,
- .receive_frame = receive_frame,
+static const struct mp_filter_info ad_spdif_filter = {
+ .name = "ad_spdif",
+ .priv_size = sizeof(struct spdifContext),
+ .process = process,
+ .destroy = destroy,
+};
+
+static struct mp_decoder *create(struct mp_filter *parent,
+ struct mp_codec_params *codec,
+ const char *decoder)
+{
+ struct mp_filter *da = mp_filter_create(parent, &ad_spdif_filter);
+ if (!da)
+ return NULL;
+
+ mp_filter_add_pin(da, MP_PIN_IN, "in");
+ mp_filter_add_pin(da, MP_PIN_OUT, "out");
+
+ da->log = mp_log_new(da, parent->log, NULL);
+
+ struct spdifContext *spdif_ctx = da->priv;
+ spdif_ctx->log = da->log;
+ spdif_ctx->pool = mp_aframe_pool_create(spdif_ctx);
+ spdif_ctx->public.f = da;
+
+ if (strcmp(decoder, "spdif_dts_hd") == 0)
+ spdif_ctx->use_dts_hd = true;
+
+ spdif_ctx->codec_id = mp_codec_to_av_codec_id(codec->codec);
+
+
+ if (spdif_ctx->codec_id == AV_CODEC_ID_NONE) {
+ talloc_free(da);
+ return NULL;
+ }
+ return &spdif_ctx->public;
+}
+
+const struct mp_decoder_fns ad_spdif = {
+ .create = create,
};
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
deleted file mode 100644
index 111f981690..0000000000
--- a/audio/decode/dec_audio.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <math.h>
-#include <assert.h>
-
-#include <libavutil/mem.h>
-
-#include "demux/codec_tags.h"
-
-#include "common/codecs.h"
-#include "common/msg.h"
-#include "common/recorder.h"
-#include "misc/bstr.h"
-#include "options/options.h"
-
-#include "stream/stream.h"
-#include "demux/demux.h"
-
-#include "demux/stheader.h"
-
-#include "dec_audio.h"
-#include "ad.h"
-#include "audio/format.h"
-
-extern const struct ad_functions ad_lavc;
-
-// Not a real codec - specially treated.
-extern const struct ad_functions ad_spdif;
-
-static const struct ad_functions * const ad_drivers[] = {
- &ad_lavc,
- NULL
-};
-
-static void uninit_decoder(struct dec_audio *d_audio)
-{
- audio_reset_decoding(d_audio);
- if (d_audio->ad_driver) {
- MP_VERBOSE(d_audio, "Uninit audio decoder.\n");
- d_audio->ad_driver->uninit(d_audio);
- }
- d_audio->ad_driver = NULL;
- talloc_free(d_audio->priv);
- d_audio->priv = NULL;
-}
-
-static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
-{
- if (!d_audio->ad_driver->init(d_audio, decoder)) {
- MP_VERBOSE(d_audio, "Audio decoder init failed.\n");
- d_audio->ad_driver = NULL;
- uninit_decoder(d_audio);
- return 0;
- }
-
- return 1;
-}
-
-struct mp_decoder_list *audio_decoder_list(void)
-{
- struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
- for (int i = 0; ad_drivers[i] != NULL; i++)
- ad_drivers[i]->add_decoders(list);
- return list;
-}
-
-static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio)
-{
- struct MPOpts *opts = d_audio->opts;
- const char *codec = d_audio->codec->codec;
-
- struct mp_decoder_list *list = audio_decoder_list();
- struct mp_decoder_list *new =
- mp_select_decoders(d_audio->log, list, codec, opts->audio_decoders);
- if (d_audio->try_spdif && codec) {
- struct mp_decoder_list *spdif =
- select_spdif_codec(codec, opts->audio_spdif);
- mp_append_decoders(spdif, new);
- talloc_free(new);
- new = spdif;
- }
- talloc_free(list);
- return new;
-}
-
-static const struct ad_functions *find_driver(const char *name)
-{
- for (int i = 0; ad_drivers[i] != NULL; i++) {
- if (strcmp(ad_drivers[i]->name, name) == 0)
- return ad_drivers[i];
- }
- if (strcmp(name, "spdif") == 0)
- return &ad_spdif;
- return NULL;
-}
-
-int audio_init_best_codec(struct dec_audio *d_audio)
-{
- uninit_decoder(d_audio);
- assert(!d_audio->ad_driver);
-
- struct mp_decoder_entry *decoder = NULL;
- struct mp_decoder_list *list = audio_select_decoders(d_audio);
-
- mp_print_decoders(d_audio->log, MSGL_V, "Codec list:", list);
-
- for (int n = 0; n < list->num_entries; n++) {
- struct mp_decoder_entry *sel = &list->entries[n];
- const struct ad_functions *driver = find_driver(sel->family);
- if (!driver)
- continue;
- MP_VERBOSE(d_audio, "Opening audio decoder %s\n", sel->decoder);
- d_audio->ad_driver = driver;
- if (init_audio_codec(d_audio, sel->decoder)) {
- decoder = sel;
- break;
- }
- MP_WARN(d_audio, "Audio decoder init failed for %s\n", sel->decoder);
- }
-
- if (d_audio->ad_driver) {
- d_audio->decoder_desc =
- talloc_asprintf(d_audio, "%s (%s)", decoder->decoder, decoder->desc);
- MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
- } else {
- MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
- d_audio->codec->codec);
- }
-
- talloc_free(list);
- return !!d_audio->ad_driver;
-}
-
-void audio_uninit(struct dec_audio *d_audio)
-{
- if (!d_audio)
- return;
- uninit_decoder(d_audio);
- talloc_free(d_audio);
-}
-
-void audio_reset_decoding(struct dec_audio *d_audio)
-{
- if (d_audio->ad_driver)
- d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
- d_audio->pts = MP_NOPTS_VALUE;
- talloc_free(d_audio->current_frame);
- d_audio->current_frame = NULL;
- talloc_free(d_audio->packet);
- d_audio->packet = NULL;
- talloc_free(d_audio->new_segment);
- d_audio->new_segment = NULL;
- d_audio->start = d_audio->end = MP_NOPTS_VALUE;
-}
-
-static void fix_audio_pts(struct dec_audio *da)
-{
- if (!da->current_frame)
- return;
-
- 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 - 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 - frame_pts) > 0.001)
- da->pts = frame_pts;
- }
-
- if (da->pts == MP_NOPTS_VALUE && da->header->missing_timestamps)
- da->pts = 0;
-
- mp_aframe_set_pts(da->current_frame, da->pts);
-
- if (da->pts != MP_NOPTS_VALUE)
- da->pts += mp_aframe_duration(da->current_frame);
-}
-
-static bool is_new_segment(struct dec_audio *da, struct demux_packet *p)
-{
- return p->segmented &&
- (p->start != da->start || p->end != da->end || p->codec != da->codec);
-}
-
-static void feed_packet(struct dec_audio *da)
-{
- if (da->current_frame || !da->ad_driver)
- return;
-
- if (!da->packet && !da->new_segment &&
- demux_read_packet_async(da->header, &da->packet) == 0)
- {
- da->current_state = DATA_WAIT;
- return;
- }
-
- if (da->packet && is_new_segment(da, da->packet)) {
- assert(!da->new_segment);
- da->new_segment = da->packet;
- da->packet = NULL;
- }
-
- if (da->ad_driver->send_packet(da, da->packet)) {
- if (da->recorder_sink)
- mp_recorder_feed_packet(da->recorder_sink, da->packet);
-
- talloc_free(da->packet);
- da->packet = NULL;
- }
-
- da->current_state = DATA_AGAIN;
-}
-
-static void read_frame(struct dec_audio *da)
-{
- if (da->current_frame || !da->ad_driver)
- return;
-
- bool progress = da->ad_driver->receive_frame(da, &da->current_frame);
-
- da->current_state = da->current_frame ? DATA_OK : DATA_AGAIN;
- if (!progress)
- da->current_state = DATA_EOF;
-
- fix_audio_pts(da);
-
- bool segment_end = da->current_state == DATA_EOF;
-
- if (da->current_frame) {
- 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;
- }
- }
-
- // If there's a new segment, start it as soon as we're drained/finished.
- if (segment_end && da->new_segment) {
- struct demux_packet *new_segment = da->new_segment;
- da->new_segment = NULL;
-
- if (da->codec == new_segment->codec) {
- audio_reset_decoding(da);
- } else {
- da->codec = new_segment->codec;
- da->ad_driver->uninit(da);
- da->ad_driver = NULL;
- audio_init_best_codec(da);
- }
-
- da->start = new_segment->start;
- da->end = new_segment->end;
-
- da->packet = new_segment;
- da->current_state = DATA_AGAIN;
- }
-}
-
-void audio_work(struct dec_audio *da)
-{
- read_frame(da);
- if (!da->current_frame) {
- feed_packet(da);
- if (da->current_state == DATA_WAIT)
- return;
- read_frame(da); // retry, to avoid redundant iterations
- }
-}
-
-// Fetch an audio frame decoded with audio_work(). Returns one of:
-// DATA_OK: *out_frame is set to a new image
-// 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_aframe **out_frame)
-{
- *out_frame = NULL;
- if (da->current_frame) {
- *out_frame = da->current_frame;
- da->current_frame = NULL;
- return DATA_OK;
- }
- if (da->current_state == DATA_OK)
- return DATA_AGAIN;
- return da->current_state;
-}
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
deleted file mode 100644
index ea504328df..0000000000
--- a/audio/decode/dec_audio.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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/>.
- */
-
-#ifndef MPLAYER_DEC_AUDIO_H
-#define MPLAYER_DEC_AUDIO_H
-
-#include "audio/chmap.h"
-#include "audio/aframe.h"
-#include "demux/demux.h"
-#include "demux/stheader.h"
-
-struct mp_decoder_list;
-
-struct dec_audio {
- struct mp_log *log;
- struct MPOpts *opts;
- struct mpv_global *global;
- const struct ad_functions *ad_driver;
- struct sh_stream *header;
- struct mp_codec_params *codec;
- char *decoder_desc;
-
- bool try_spdif;
-
- struct mp_recorder_sink *recorder_sink;
-
- // For free use by the ad_driver
- void *priv;
-
- // Strictly internal (dec_audio.c).
-
- double pts; // endpts of previous frame
- double start, end;
- struct demux_packet *packet;
- struct demux_packet *new_segment;
- struct mp_aframe *current_frame;
- int current_state;
-};
-
-struct mp_decoder_list *audio_decoder_list(void);
-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_aframe **out_frame);
-
-void audio_reset_decoding(struct dec_audio *d_audio);
-
-// ad_spdif.c
-struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref);
-
-#endif /* MPLAYER_DEC_AUDIO_H */
diff --git a/common/common.h b/common/common.h
index 224a6e023a..14a9973371 100644
--- a/common/common.h
+++ b/common/common.h
@@ -58,14 +58,6 @@ enum stream_type {
STREAM_TYPE_COUNT,
};
-enum {
- DATA_OK = 1, // data is actually being returned
- DATA_WAIT = 0, // async wait: check state again after next wakeup
- DATA_AGAIN = -2, // repeat request (internal progress was made)
- DATA_STARVE = -1, // need input (might require to drain other outputs)
- DATA_EOF = -3, // no more data available
-};
-
extern const char mpv_version[];
extern const char mpv_builddate[];
extern const char mpv_copyright[];
diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c
index e85621957f..7e948faebb 100644
--- a/filters/f_decoder_wrapper.c
+++ b/filters/f_decoder_wrapper.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <math.h>
#include <assert.h>
#include <libavutil/buffer.h>
@@ -36,6 +37,7 @@
#include "common/global.h"
#include "common/recorder.h"
+#include "audio/aframe.h"
#include "video/out/vo.h"
#include "video/csputils.h"
@@ -149,6 +151,13 @@ struct mp_decoder_list *video_decoder_list(void)
return list;
}
+struct mp_decoder_list *audio_decoder_list(void)
+{
+ struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
+ ad_lavc.add_decoders(list);
+ return list;
+}
+
bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
{
struct priv *p = d->f->priv;
@@ -161,13 +170,36 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
reset_decoder(p);
p->has_broken_packet_pts = -10; // needs 10 packets to reach decision
- const struct mp_decoder_fns *driver = &vd_lavc;
+ const struct mp_decoder_fns *driver = NULL;
+ struct mp_decoder_list *list = NULL;
+ char *user_list = NULL;
+
+ if (p->codec->type == STREAM_VIDEO) {
+ driver = &vd_lavc;
+ user_list = opts->video_decoders;
+ } else if (p->codec->type == STREAM_AUDIO) {
+ driver = &ad_lavc;
+ user_list = opts->audio_decoders;
+
+ if (p->public.try_spdif && p->codec->codec) {
+ struct mp_decoder_list *spdif =
+ select_spdif_codec(p->codec->codec, opts->audio_spdif);
+ if (spdif->num_entries) {
+ driver = &ad_spdif;
+ list = spdif;
+ } else {
+ talloc_free(spdif);
+ }
+ }
+ }
- struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list);
- driver->add_decoders(full);
- struct mp_decoder_list *list =
- mp_select_decoders(p->log, full, p->codec->codec, opts->video_decoders);
- talloc_free(full);
+ if (!list) {
+ struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list);
+ if (driver)
+ driver->add_decoders(full);
+ list = mp_select_decoders(p->log, full, p->codec->codec, user_list);
+ talloc_free(full);
+ }
mp_print_decoders(p->log, MSGL_V, "Codec list:", list);
@@ -363,6 +395,29 @@ void mp_decoder_wrapper_get_video_dec_params(struct mp_decoder_wrapper *d,
*m = p->dec_format;
}
+static void process_audio_frame(struct priv *p, struct mp_aframe *aframe)
+{
+ double frame_pts = mp_aframe_get_pts(aframe);
+ if (frame_pts != MP_NOPTS_VALUE) {
+ if (p->pts != MP_NOPTS_VALUE)
+ MP_STATS(p, "value %f audio-pts-err", p->pts - frame_pts);
+
+ // Keep the interpolated timestamp if it doesn't deviate more
+ // than 1 ms from the real one. (MKV rounded timestamps.)
+ if (p->pts == MP_NOPTS_VALUE || fabs(p->pts - frame_pts) > 0.001)
+ p->pts = frame_pts;
+ }
+
+ if (p->pts == MP_NOPTS_VALUE && p->header->missing_timestamps)
+ p->pts = 0;
+
+ mp_aframe_set_pts(aframe, p->pts);
+
+ if (p->pts != MP_NOPTS_VALUE)
+ p->pts += mp_aframe_duration(aframe);
+}
+
+
// Frames before the start timestamp can be dropped. (Used for hr-seek.)
void mp_decoder_wrapper_set_start_pts(struct mp_decoder_wrapper *d, double pts)
{
@@ -470,6 +525,17 @@ static bool process_decoded_frame(struct priv *p, struct mp_frame *frame)
if ((p->start != MP_NOPTS_VALUE && vpts < p->start) || segment_ended)
mp_frame_unref(frame);
}
+ } else if (frame->type == MP_FRAME_AUDIO) {
+ struct mp_aframe *aframe = frame->data;
+
+ process_audio_frame(p, aframe);
+
+ mp_aframe_clip_timestamps(aframe, p->start, p->end);
+ double pts = mp_aframe_get_pts(aframe);
+ if (pts != MP_NOPTS_VALUE && p->start != MP_NOPTS_VALUE)
+ segment_ended = pts >= p->end;
+ if (mp_aframe_get_size(aframe) == 0)
+ mp_frame_unref(frame);
} else {
MP_ERR(p, "unknown frame type from decoder\n");
}
@@ -588,6 +654,8 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
MP_INFO(p, "FPS forced to %5.3f.\n", p->public.fps);
MP_INFO(p, "Use --no-correct-pts to force FPS based timing.\n");
}
+ } else if (p->header->type == STREAM_AUDIO) {
+ p->log = f->log = mp_log_new(f, parent->log, "!ad");
}
struct mp_filter *demux = mp_demux_in_create(f, p->header);
diff --git a/filters/f_decoder_wrapper.h b/filters/f_decoder_wrapper.h
index 4d970bd79a..e6601052a2 100644
--- a/filters/f_decoder_wrapper.h
+++ b/filters/f_decoder_wrapper.h
@@ -46,6 +46,11 @@ struct mp_decoder_wrapper {
// Framedrop control for playback (not used for hr seek etc.)
int attempt_framedrops; // try dropping this many frames
int dropped_frames; // total frames _probably_ dropped
+
+ // --- for STREAM_AUDIO
+
+ // Prefer spdif wrapper over real decoders.
+ bool try_spdif;
};
// Create the decoder wrapper for the given stream, plus underlying decoder.
@@ -55,6 +60,7 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
struct sh_stream *src);
struct mp_decoder_list *video_decoder_list(void);
+struct mp_decoder_list *audio_decoder_list(void);
// For precise seeking: if possible, try to drop frames up until the given PTS.
// This is automatically unset if the target is reached, or on reset.
@@ -96,9 +102,14 @@ struct mp_decoder_fns {
};
extern const struct mp_decoder_fns vd_lavc;
+extern const struct mp_decoder_fns ad_lavc;
+extern const struct mp_decoder_fns ad_spdif;
// Convenience wrapper for lavc based decoders. eof_flag must be set to false
// on init and resets.
void lavc_process(struct mp_filter *f, bool *eof_flag,
bool (*send)(struct mp_filter *f, struct demux_packet *pkt),
bool (*receive)(struct mp_filter *f, struct mp_frame *res));
+
+// ad_spdif.c
+struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref);
diff --git a/filters/f_output_chain.c b/filters/f_output_chain.c
index e53f9eafaa..ea6a0a3981 100644
--- a/filters/f_output_chain.c
+++ b/filters/f_output_chain.c
@@ -452,8 +452,13 @@ void mp_output_chain_reset_harder(struct mp_output_chain *c)
mp_filter_reset(p->f);
p->public.failed_output_conversion = false;
- for (int n = 0; n < p->num_all_filters; n++)
- p->all_filters[n]->failed = false;
+ for (int n = 0; n < p->num_all_filters; n++) {
+ struct mp_user_filter *u = p->all_filters[n];
+
+ u->failed = false;
+ u->last_out_params = (struct mp_image_params){0};
+ mp_aframe_reset(u->last_out_aformat);
+ }
}
static void destroy(struct mp_filter *f)
diff --git a/options/options.c b/options/options.c
index bce2bf3be6..2f4116299d 100644
--- a/options/options.c
+++ b/options/options.c
@@ -42,7 +42,6 @@
#include "video/hwdec.h"
#include "video/image_writer.h"
#include "sub/osd.h"
-#include "audio/decode/dec_audio.h"
#include "player/core.h"
#include "player/command.h"
#include "stream/stream.h"
diff --git a/player/audio.c b/player/audio.c
index ab53ab3b86..5b061efca1 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -33,21 +33,17 @@
#include "audio/audio_buffer.h"
#include "audio/format.h"
-#include "audio/decode/dec_audio.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
+#include "filters/f_decoder_wrapper.h"
#include "core.h"
#include "command.h"
enum {
AD_OK = 0,
- AD_ERR = -1,
AD_EOF = -2,
- AD_NEW_FMT = -3,
AD_WAIT = -4,
- AD_NO_PROGRESS = -5,
- AD_STARVE = -6,
};
// Try to reuse the existing filters to change playback speed. If it works,
@@ -183,17 +179,11 @@ void update_playback_speed(struct MPContext *mpctx)
static void ao_chain_reset_state(struct ao_chain *ao_c)
{
ao_c->last_out_pts = MP_NOPTS_VALUE;
- ao_c->pts = MP_NOPTS_VALUE;
ao_c->pts_reset = false;
- TA_FREEP(&ao_c->input_frame);
TA_FREEP(&ao_c->output_frame);
+ ao_c->out_eof = false;
mp_audio_buffer_clear(ao_c->ao_buffer);
-
- if (ao_c->audio_src)
- audio_reset_decoding(ao_c->audio_src);
-
- ao_c->filter_src_got_eof = false;
}
void reset_audio_state(struct MPContext *mpctx)
@@ -226,16 +216,16 @@ static void ao_chain_uninit(struct ao_chain *ao_c)
if (track) {
assert(track->ao_c == ao_c);
track->ao_c = NULL;
- assert(track->d_audio == ao_c->audio_src);
- track->d_audio = NULL;
- audio_uninit(ao_c->audio_src);
+ if (ao_c->dec_src)
+ assert(track->dec->f->pins[0] == ao_c->dec_src);
+ talloc_free(track->dec->f);
+ track->dec = NULL;
}
if (ao_c->filter_src)
mp_pin_disconnect(ao_c->filter_src);
talloc_free(ao_c->filter->f);
- talloc_free(ao_c->input_frame);
talloc_free(ao_c->output_frame);
talloc_free(ao_c->ao_buffer);
talloc_free(ao_c);
@@ -361,12 +351,12 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
if (!mpctx->ao) {
// If spdif was used, try to fallback to PCM.
- if (spdif_fallback && ao_c->audio_src) {
+ if (spdif_fallback && ao_c->track && ao_c->track->dec) {
MP_VERBOSE(mpctx, "Falling back to PCM output.\n");
ao_c->spdif_passthrough = false;
ao_c->spdif_failed = true;
- ao_c->audio_src->try_spdif = false;
- if (!audio_init_best_codec(ao_c->audio_src))
+ ao_c->track->dec->try_spdif = false;
+ if (!mp_decoder_wrapper_reinit(ao_c->track->dec))
goto init_error;
reset_audio_state(mpctx);
mp_output_chain_reset_harder(ao_c->filter);
@@ -408,21 +398,18 @@ init_error:
int init_audio_decoder(struct MPContext *mpctx, struct track *track)
{
- assert(!track->d_audio);
+ assert(!track->dec);
if (!track->stream)
goto init_error;
- track->d_audio = talloc_zero(NULL, struct dec_audio);
- struct dec_audio *d_audio = track->d_audio;
- d_audio->log = mp_log_new(d_audio, mpctx->log, "!ad");
- d_audio->global = mpctx->global;
- d_audio->opts = mpctx->opts;
- d_audio->header = track->stream;
- d_audio->codec = track->stream->codec;
+ track->dec = mp_decoder_wrapper_create(mpctx->filter_root, track->stream);
+ if (!track->dec)
+ goto init_error;
- d_audio->try_spdif = true;
+ if (track->ao_c)
+ track->dec->try_spdif = true;
- if (!audio_init_best_codec(d_audio))
+ if (!mp_decoder_wrapper_reinit(track->dec))
goto init_error;
return 1;
@@ -431,8 +418,6 @@ init_error:
if (track->sink)
mp_pin_disconnect(track->sink);
track->sink = NULL;
- audio_uninit(track->d_audio);
- track->d_audio = NULL;
error_on_track(mpctx, track);
return 0;
}
@@ -462,7 +447,7 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
ao_c->filter =
mp_output_chain_create(mpctx->filter_root, MP_OUTPUT_CHAIN_AUDIO);
ao_c->spdif_passthrough = true;
- ao_c->pts = MP_NOPTS_VALUE;
+ ao_c->last_out_pts = MP_NOPTS_VALUE;
ao_c->ao_buffer = mp_audio_buffer_create(NULL);
ao_c->ao = mpctx->ao;
@@ -471,7 +456,8 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
track->ao_c = ao_c;
if (!init_audio_decoder(mpctx, track))
goto init_error;
- ao_c->audio_src = track->d_audio;
+ ao_c->dec_src = track->dec->f->pins[0];
+ mp_pin_connect(ao_c->filter->f->pins[0], ao_c->dec_src);
}
reset_audio_state(mpctx);
@@ -643,7 +629,7 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
static bool copy_output(struct MPContext *mpctx, struct ao_chain *ao_c,
- int minsamples, double endpts, bool eof, bool *seteof)
+ int minsamples, double endpts, bool *seteof)
{
struct mp_audio_buffer *outbuf = ao_c->ao_buffer;
@@ -671,16 +657,39 @@ static bool copy_output(struct MPContext *mpctx, struct ao_chain *ao_c,
struct mp_frame frame = mp_pin_out_read(ao_c->filter->f->pins[1]);
if (frame.type == MP_FRAME_AUDIO) {
ao_c->output_frame = frame.data;
+ ao_c->out_eof = false;
+
+ double pts = mp_aframe_get_pts(ao_c->output_frame);
+ if (pts != MP_NOPTS_VALUE) {
+ // Attempt to detect jumps in PTS. Even for the lowest
+ // sample rates and with worst container rounded timestamp,
+ // this should be a margin more than enough.
+ double desync = pts - ao_c->last_out_pts;
+ if (ao_c->last_out_pts != MP_NOPTS_VALUE && fabs(desync) > 0.1)
+ {
+ MP_WARN(ao_c, "Invalid audio PTS: %f -> %f\n",
+ ao_c->last_out_pts, pts);
+ if (desync >= 5)
+ ao_c->pts_reset = true;
+ }
+ }
ao_c->last_out_pts = mp_aframe_end_pts(ao_c->output_frame);
} else if (frame.type == MP_FRAME_EOF) {
- *seteof = true;
+ ao_c->out_eof = true;
} else if (frame.type) {
MP_ERR(mpctx, "unknown frame type\n");
+ mp_frame_unref(&frame);
}
}
- if (!ao_c->output_frame)
- return false; // out of data
+ // out of data
+ if (!ao_c->output_frame) {
+ if (ao_c->out_eof) {
+ *seteof = true;
+ return true;
+ }
+ return false;
+ }
if (cursamples + mp_aframe_get_size(ao_c->output_frame) > maxsamples) {
if (cursamples < maxsamples) {
@@ -702,43 +711,6 @@ static bool copy_output(struct MPContext *mpctx, struct ao_chain *ao_c,
return true;
}
-static int decode_new_frame(struct ao_chain *ao_c)
-{
- if (ao_c->input_frame)
- return AD_OK;
-
- int res = DATA_EOF;
- if (ao_c->filter_src) {
- struct mp_frame frame = mp_pin_out_read(ao_c->filter_src);
- if (frame.type == MP_FRAME_EOF) {
- res = DATA_EOF;
- ao_c->filter_src_got_eof = true;
- } else if (frame.type == MP_FRAME_AUDIO) {
- res = DATA_OK;
- ao_c->input_frame = frame.data;
- ao_c->filter_src_got_eof = false;
- } else if (frame.type) {
- MP_ERR(ao_c, "unexpected frame type\n");
- mp_frame_unref(&frame);
- res = DATA_EOF;
- } else {
- res = ao_c->filter_src_got_eof ? DATA_EOF : DATA_WAIT;
- }
- } else if (ao_c->audio_src) {
- audio_work(ao_c->audio_src);
- res = audio_get_frame(ao_c->audio_src, &ao_c->input_frame);
- }
-
- switch (res) {
- case DATA_OK: return AD_OK;
- case DATA_WAIT: return AD_WAIT;
- case DATA_AGAIN: return AD_NO_PROGRESS;
- case DATA_STARVE: return AD_STARVE;
- case DATA_EOF: return AD_EOF;
- default: abort();
- }
-}
-
/* Try to get at least minsamples decoded+filtered samples in outbuf
* (total length including possible existing data).
* Return 0 on success, or negative AD_* error code.
@@ -749,64 +721,12 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
{
struct ao_chain *ao_c = mpctx->ao_chain;
- MP_STATS(ao_c, "start audio");
-
double endpts = get_play_end_pts(mpctx);
bool eof = false;
- int res;
- while (1) {
- res = 0;
-
- if (copy_output(mpctx, ao_c, minsamples, endpts, false, &eof))
- break;
-
- res = decode_new_frame(ao_c);
- if (res == AD_NO_PROGRESS)
- continue;
- if (res == AD_WAIT || res == AD_STARVE)
- break;
- if (res < 0) {
- // drain filters first (especially for true EOF case)
- if (!ao_c->filter->got_input_eof)
- mp_pin_in_write(ao_c->filter->f->pins[0], MP_EOF_FRAME);
- copy_output(mpctx, ao_c, minsamples, endpts, true, &eof);
- break;
- }
- assert(ao_c->input_frame);
-
- double pts = mp_aframe_get_pts(ao_c->input_frame);
- if (pts == MP_NOPTS_VALUE) {
- ao_c->pts = MP_NOPTS_VALUE;
- } else {
- // Attempt to detect jumps in PTS. Even for the lowest sample rates
- // and with worst container rounded timestamp, this should be a
- // margin more than enough.
- double desync = pts - ao_c->pts;
- if (ao_c->pts != MP_NOPTS_VALUE && fabs(desync) > 0.1) {
- MP_WARN(ao_c, "Invalid audio PTS: %f -> %f\n",
- ao_c->pts, pts);
- if (desync >= 5)
- ao_c->pts_reset = true;
- }
- ao_c->pts = mp_aframe_end_pts(ao_c->input_frame);
- }
-
- if (!mp_pin_in_needs_data(ao_c->filter->f->pins[0])) {
- res = AD_WAIT;
- break;
- }
- mp_pin_in_write(ao_c->filter->f->pins[0],
- MAKE_FRAME(MP_FRAME_AUDIO, ao_c->input_frame));
- ao_c->input_frame = NULL;
- }
-
- if (res == 0 && mp_audio_buffer_samples(outbuf) < minsamples && eof)
- res = AD_EOF;
-
- MP_STATS(ao_c, "end audio");
-
- return res;
+ if (!copy_output(mpctx, ao_c, minsamples, endpts, &eof))
+ return AD_WAIT;
+ return eof ? AD_EOF : AD_OK;
}
void reload_audio_output(struct MPContext *mpctx)
@@ -818,17 +738,23 @@ void reload_audio_output(struct MPContext *mpctx)
uninit_audio_out(mpctx);
reinit_audio_filters(mpctx); // mostly to issue refresh seek
+ struct ao_chain *ao_c = mpctx->ao_chain;
+
+ if (ao_c) {
+ reset_audio_state(mpctx);
+ mp_output_chain_reset_harder(ao_c->filter);
+ }
+
// Whether we can use spdif might have changed. If we failed to use spdif
// in the previous initialization, try it with spdif again (we'll fallback
// to PCM again if necessary).
- struct ao_chain *ao_c = mpctx->ao_chain;
- if (ao_c) {
- struct dec_audio *d_audio = ao_c->audio_src;
- if (d_audio && ao_c->spdif_failed) {
+ if (ao_c && ao_c->track) {
+ struct mp_decoder_wrapper *dec = ao_c->track->dec;
+ if (dec && ao_c->spdif_failed) {
ao_c->spdif_passthrough = true;
ao_c->spdif_failed = false;
- d_audio->try_spdif = true;
- if (!audio_init_best_codec(d_audio)) {
+ dec->try_spdif = true;
+ if (!mp_decoder_wrapper_reinit(dec)) {
MP_ERR(mpctx, "Error reinitializing audio.\n");
error_on_track(mpctx, ao_c->track);
}
@@ -857,29 +783,13 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
return;
}
- if (ao_c->input_frame && mp_pin_in_needs_data(ao_c->filter->f->pins[0])) {
- mp_pin_in_write(ao_c->filter->f->pins[0],
- MAKE_FRAME(MP_FRAME_AUDIO, ao_c->input_frame));
- ao_c->input_frame = NULL;
- }
-
// (if AO is set due to gapless from previous file, then we can try to
// filter normally until the filter tells us to change the AO)
if (!mpctx->ao) {
- mp_pin_out_request_data(ao_c->filter->f->pins[1]);
// Probe the initial audio format. Returns AD_OK (and does nothing) if
// the format is already known.
- int r = AD_NO_PROGRESS;
- while (r == AD_NO_PROGRESS)
- r = decode_new_frame(mpctx->ao_chain);
- if (r == AD_WAIT)
- return; // continue later when new data is available
- if (r == AD_EOF) {
- mpctx->audio_status = STATUS_EOF;
- return;
- }
+ mp_pin_out_request_data(ao_c->filter->f->pins[1]);
reinit_audio_filters_and_output(mpctx);
- mp_wakeup_core(mpctx);
return; // try again next iteration
}
@@ -949,12 +859,6 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
}
if (status == AD_WAIT)
return;
- if (status == AD_NO_PROGRESS || status == AD_STARVE) {
- mp_wakeup_core(mpctx);
- return;
- }
- if (status == AD_ERR)
- mp_wakeup_core(mpctx);
working = true;
}
diff --git a/player/command.c b/player/command.c
index d1de5a86ff..1b074b8767 100644
--- a/player/command.c
+++ b/player/command.c
@@ -57,7 +57,6 @@
#include "audio/aframe.h"
#include "audio/format.h"
#include "audio/out/ao.h"
-#include "audio/decode/dec_audio.h"
#include "video/out/bitmap_packer.h"
#include "options/path.h"
#include "screenshot.h"
@@ -2038,7 +2037,7 @@ static int mp_property_audio_codec(void *ctx, struct m_property *prop,
{
MPContext *mpctx = ctx;
struct track *track = mpctx->current_track[0][STREAM_AUDIO];
- const char *c = track && track->d_audio ? track->d_audio->decoder_desc : NULL;
+ const char *c = track && track->dec ? track->dec->decoder_desc : NULL;
return m_property_strdup_ro(action, arg, c);
}
@@ -2186,8 +2185,6 @@ static int get_track_entry(int item, int action, void *arg, void *ctx)
const char *decoder_desc = NULL;
if (track->dec)
decoder_desc = track->dec->decoder_desc;
- if (track->d_audio)
- decoder_desc = track->d_audio->decoder_desc;
bool has_rg = track->stream && track->stream->codec->replaygain_data;
struct replaygain_data rg = has_rg ? *track->stream->codec->replaygain_data
diff --git a/player/core.h b/player/core.h
index f27c30b145..8a77690de6 100644
--- a/player/core.h
+++ b/player/core.h
@@ -154,13 +154,11 @@ struct track {
// Current decoding state (NULL if selected==false)
struct mp_decoder_wrapper *dec;
- struct dec_audio *d_audio;
// Where the decoded result goes to (one of them is not NULL if active)
struct vo_chain *vo_c;
struct ao_chain *ao_c;
struct mp_pin *sink;
- bool sink_eof; // whether it got passed EOF
// For stream recording (remuxing mode).
struct mp_recorder_sink *remux_sink;
@@ -190,7 +188,6 @@ struct vo_chain {
struct ao_chain {
struct mp_log *log;
- double pts; // timestamp of first sample output by decoder
bool spdif_passthrough, spdif_failed;
bool pts_reset;
@@ -200,18 +197,15 @@ struct ao_chain {
struct mp_audio_buffer *ao_buffer;
double ao_resume_time;
- // 1-element input frame queue.
- struct mp_aframe *input_frame;
-
// 1-element output frame queue.
struct mp_aframe *output_frame;
+ bool out_eof;
double last_out_pts;
struct track *track;
struct mp_pin *filter_src;
- bool filter_src_got_eof; // whether this returned EOF last time
- struct dec_audio *audio_src;
+ struct mp_pin *dec_src;
};
/* Note that playback can be paused, stopped, etc. at any time. While paused,
diff --git a/player/loadfile.c b/player/loadfile.c
index d35ae6ad6b..44f0f970ac 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -43,7 +43,6 @@
#include "common/recorder.h"
#include "input/input.h"
-#include "audio/decode/dec_audio.h"
#include "audio/out/ao.h"
#include "filters/f_decoder_wrapper.h"
#include "filters/f_lavfi.h"
@@ -984,14 +983,10 @@ static void cleanup_deassociated_complex_filters(struct MPContext *mpctx)
for (int n = 0; n < mpctx->num_tracks; n++) {
struct track *track = mpctx->tracks[n];
if (!(track->sink || track->vo_c || track->ao_c)) {
- if (track->dec && !track->vo_c) {
+ if (track->dec && !track->vo_c && !track->ao_c) {
talloc_free(track->dec->f);
track->dec->f = NULL;
}
- if (track->d_audio && !track->ao_c) {
- audio_uninit(track->d_audio);
- track->d_audio = NULL;
- }
track->selected = false;
}
}
@@ -1001,7 +996,7 @@ static void cleanup_deassociated_complex_filters(struct MPContext *mpctx)
{
uninit_video_chain(mpctx);
}
- if (mpctx->ao_chain && !mpctx->ao_chain->audio_src &&
+ if (mpctx->ao_chain && !mpctx->ao_chain->dec_src &&
!mpctx->ao_chain->filter_src)
{
uninit_audio_chain(mpctx);
@@ -1094,17 +1089,16 @@ static int reinit_complex_filters(struct MPContext *mpctx, bool force_uninit)
pad = mp_filter_get_named_pin(mpctx->lavfi, "ao");
if (pad && mp_pin_get_dir(pad) == MP_PIN_OUT) {
if (mpctx->ao_chain) {
- if (mpctx->ao_chain->audio_src) {
- MP_ERR(mpctx, "Pad ao tries to connect to already used AO.\n");
- goto done;
- }
+ MP_ERR(mpctx, "Pad ao tries to connect to already used AO.\n");
+ goto done;
} else {
reinit_audio_chain_src(mpctx, NULL);
if (!mpctx->ao_chain)
goto done;
}
- mp_pin_set_manual_connection(pad, true);
- mpctx->ao_chain->filter_src = pad;
+ struct ao_chain *ao_c = mpctx->ao_chain;
+ ao_c->filter_src = pad;
+ mp_pin_connect(ao_c->filter->f->pins[0], ao_c->filter_src);
}
for (int n = 0; n < mpctx->num_tracks; n++) {
@@ -1115,8 +1109,9 @@ static int reinit_complex_filters(struct MPContext *mpctx, bool force_uninit)
mp_pin_connect(track->sink, track->dec->f->pins[0]);
}
if (track->sink && track->type == STREAM_AUDIO) {
- if (!track->d_audio && !init_audio_decoder(mpctx, track))
+ if (!track->dec && !init_audio_decoder(mpctx, track))
goto done;
+ mp_pin_connect(track->sink, track->dec->f->pins[0]);
}
}
@@ -1588,8 +1583,6 @@ static void set_track_recorder_sink(struct track *track,
sub_set_recorder_sink(track->d_sub, sink);
if (track->dec)
track->dec->recorder_sink = sink;
- if (track->d_audio)
- track->d_audio->recorder_sink = sink;
track->remux_sink = sink;
}
@@ -1631,11 +1624,8 @@ void open_recorder(struct MPContext *mpctx, bool on_init)
for (int n = 0; n < mpctx->num_tracks; n++) {
struct track *track = mpctx->tracks[n];
- if (track->stream && track->selected &&
- (track->d_sub || track->dec || track->d_audio))
- {
+ if (track->stream && track->selected && (track->d_sub || track->dec))
MP_TARRAY_APPEND(NULL, streams, num_streams, track->stream);
- }
}
mpctx->recorder = mp_recorder_create(mpctx->global, mpctx->opts->record_file,
diff --git a/player/main.c b/player/main.c
index 98abbc8e4f..711b413735 100644
--- a/player/main.c
+++ b/player/main.c
@@ -50,7 +50,6 @@
#include "options/path.h"
#include "input/input.h"
-#include "audio/decode/dec_audio.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "stream/stream.h"
diff --git a/player/playloop.c b/player/playloop.c
index 748469354d..e77200f2d7 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -39,7 +39,6 @@
#include "osdep/terminal.h"
#include "osdep/timer.h"
-#include "audio/decode/dec_audio.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "stream/stream.h"
@@ -212,12 +211,6 @@ void add_step_frame(struct MPContext *mpctx, int dir)
// Clear some playback-related fields on file loading or after seeks.
void reset_playback_state(struct MPContext *mpctx)
{
- for (int n = 0; n < mpctx->num_tracks; n++) {
- if (mpctx->tracks[n]->d_audio)
- audio_reset_decoding(mpctx->tracks[n]->d_audio);
- mpctx->tracks[n]->sink_eof = false;
- }
-
mp_filter_reset(mpctx->filter_root);
reset_video_state(mpctx);
@@ -1076,35 +1069,6 @@ static void handle_eof(struct MPContext *mpctx)
}
}
-static void handle_complex_filter_decoders(struct MPContext *mpctx)
-{
- if (!mpctx->lavfi)
- return;
-
- for (int n = 0; n < mpctx->num_tracks; n++) {
- struct track *track = mpctx->tracks[n];
- if (!track->selected)
- continue;
- if (track->d_audio) {
- if (!track->sink || !mp_pin_in_needs_data(track->sink))
- continue;
- audio_work(track->d_audio);
- struct mp_aframe *fr;
- int res = audio_get_frame(track->d_audio, &fr);
- if (res == DATA_OK) {
- mp_pin_in_write(track->sink, MAKE_FRAME(MP_FRAME_AUDIO, fr));
- track->sink_eof = false;
- } else if (res == DATA_EOF) {
- if (!track->sink_eof)
- mp_pin_in_write(track->sink, MP_EOF_FRAME);
- track->sink_eof = true;
- } else if (res == DATA_AGAIN) {
- mp_wakeup_core(mpctx);
- }
- }
- }
-}
-
void run_playloop(struct MPContext *mpctx)
{
#if HAVE_ENCODING
@@ -1116,8 +1080,6 @@ void run_playloop(struct MPContext *mpctx)
update_demuxer_properties(mpctx);
- handle_complex_filter_decoders(mpctx);
-
handle_cursor_autohide(mpctx);
handle_vo_events(mpctx);
handle_command_updates(mpctx);
diff --git a/player/video.c b/player/video.c
index 48b02ecec7..619c73e3f1 100644
--- a/player/video.c
+++ b/player/video.c
@@ -41,7 +41,6 @@
#include "video/hwdec.h"
#include "filters/f_decoder_wrapper.h"
#include "video/out/vo.h"
-#include "audio/decode/dec_audio.h"
#include "core.h"
#include "command.h"
diff --git a/wscript_build.py b/wscript_build.py
index 1e2b2f7b45..b2d61cf0be 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -180,7 +180,6 @@ def build(ctx):
( "audio/aframe.c" ),
( "audio/decode/ad_lavc.c" ),
( "audio/decode/ad_spdif.c" ),
- ( "audio/decode/dec_audio.c" ),
( "audio/filter/af_format.c" ),
( "audio/filter/af_lavcac3enc.c" ),
( "audio/filter/af_lavrresample.c" ),