summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-01-21 22:10:15 +0100
committerwm4 <wm4@nowhere>2016-01-22 00:25:44 +0100
commitfef8b7984be5a6244612d346bd60d2badd4a2e63 (patch)
tree9a9c4ef4b3cbe9d8ee0854a77913df8ce00dab8f /audio
parent27ecc417fedf25b2408e49fafdae4421d5115532 (diff)
downloadmpv-fef8b7984be5a6244612d346bd60d2badd4a2e63.tar.bz2
mpv-fef8b7984be5a6244612d346bd60d2badd4a2e63.tar.xz
audio: refactor: work towards unentangling audio decoding and filtering
Similar to the video path. dec_audio.c now handles decoding only. It also looks very similar to dec_video.c, and actually contains some of the rewritten code from it. (A further goal might be unifying the decoders, I guess.) High potential for regressions.
Diffstat (limited to 'audio')
-rw-r--r--audio/decode/ad_lavc.c8
-rw-r--r--audio/decode/ad_spdif.c8
-rw-r--r--audio/decode/dec_audio.c193
-rw-r--r--audio/decode/dec_audio.h41
4 files changed, 102 insertions, 148 deletions
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index f7304353af..3c17d0d9bb 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -196,21 +196,21 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
// LATM may need many packets to find mux info
if (ret == AVERROR(EAGAIN)) {
mpkt->len = 0;
- return AD_OK;
+ return 0;
}
}
if (ret < 0) {
MP_ERR(da, "Error decoding audio.\n");
- return AD_ERR;
+ return -1;
}
if (!got_frame)
- return mpkt ? AD_OK : AD_EOF;
+ return 0;
double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, NULL);
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
if (!mpframe)
- return AD_ERR;
+ return -1;
struct mp_chmap lavc_chmap = mpframe->channels;
if (lavc_chmap.num != avctx->channels)
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index 54e52a9566..7298d9e7d7 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -251,7 +251,7 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
spdif_ctx->out_buffer_len = 0;
if (!mpkt)
- return AD_EOF;
+ return 0;
double pts = mpkt->pts;
@@ -261,17 +261,17 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
pkt.pts = pkt.dts = 0;
if (!spdif_ctx->lavf_ctx) {
if (init_filter(da, &pkt) < 0)
- return AD_ERR;
+ return -1;
}
int ret = av_write_frame(spdif_ctx->lavf_ctx, &pkt);
avio_flush(spdif_ctx->lavf_ctx->pb);
if (ret < 0)
- return AD_ERR;
+ return -1;
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)
- return AD_ERR;
+ return -1;
memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
(*out)->pts = pts;
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index f97636e475..9fe09ae89f 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -61,8 +61,6 @@ static void uninit_decoder(struct dec_audio *d_audio)
d_audio->ad_driver = NULL;
talloc_free(d_audio->priv);
d_audio->priv = NULL;
- d_audio->afilter->initialized = -1;
- d_audio->decode_format = (struct mp_audio){0};
}
static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
@@ -93,7 +91,7 @@ static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio)
struct mp_decoder_list *list = audio_decoder_list();
struct mp_decoder_list *new =
mp_select_decoders(list, codec, opts->audio_decoders);
- if (d_audio->spdif_passthrough) {
+ if (d_audio->try_spdif) {
struct mp_decoder_list *spdif =
mp_select_decoder_list(list, codec, "spdif", opts->audio_spdif);
mp_append_decoders(spdif, new);
@@ -159,144 +157,101 @@ void audio_uninit(struct dec_audio *d_audio)
return;
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
uninit_decoder(d_audio);
- af_destroy(d_audio->afilter);
- talloc_free(d_audio->waiting);
+ talloc_free(d_audio->current_frame);
talloc_free(d_audio->packet);
talloc_free(d_audio);
}
-static int decode_new_frame(struct dec_audio *da)
+void audio_reset_decoding(struct dec_audio *d_audio)
{
- while (!da->waiting) {
- if (!da->packet) {
- if (demux_read_packet_async(da->header, &da->packet) == 0)
- return AD_WAIT;
- }
+ if (d_audio->ad_driver)
+ d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
+ d_audio->pts = MP_NOPTS_VALUE;
+ d_audio->pts_reset = false;
+ talloc_free(d_audio->current_frame);
+ d_audio->current_frame = NULL;
+ talloc_free(d_audio->packet);
+ d_audio->packet = NULL;
+}
- int ret = da->ad_driver->decode_packet(da, da->packet, &da->waiting);
- if (ret < 0 || (da->packet && da->packet->len == 0)) {
- talloc_free(da->packet);
- da->packet = NULL;
- }
- if (ret < 0)
- return ret;
-
- if (da->waiting) {
- if (da->waiting->pts != MP_NOPTS_VALUE) {
- if (da->pts != MP_NOPTS_VALUE) {
- da->pts += da->pts_offset / (double)da->waiting->rate;
- da->pts_offset = 0;
- }
- double newpts = da->waiting->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 || da->pts_offset != 0 ||
- fabs(da->pts - newpts) > 0.001)
- {
- // 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.
- if (da->pts != MP_NOPTS_VALUE && fabs(newpts - da->pts) > 0.1)
- {
- MP_WARN(da, "Invalid audio PTS: %f -> %f\n",
- da->pts, newpts);
- da->pts_reset = true;
- }
- da->pts = da->waiting->pts;
- da->pts_offset = 0;
- }
+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;
+ // 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) {
+ // 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.
+ if (da->pts != MP_NOPTS_VALUE && fabs(newpts - da->pts) > 0.1) {
+ MP_WARN(da, "Invalid audio PTS: %f -> %f\n",
+ da->pts, newpts);
+ da->pts_reset = true;
}
- da->pts_offset += da->waiting->samples;
- da->decode_format = *da->waiting;
- mp_audio_set_null_data(&da->decode_format);
+ da->pts = da->current_frame->pts;
}
-
- if (da->pts == MP_NOPTS_VALUE && da->header->missing_timestamps)
- da->pts = 0;
}
- return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR;
-}
-/* Decode packets until we know the audio format. Then reinit the buffer.
- * Returns AD_OK on success, negative AD_* code otherwise.
- * Also returns AD_OK if already initialized (and does nothing).
- */
-int initial_audio_decode(struct dec_audio *da)
-{
- return decode_new_frame(da);
-}
+ if (da->pts == MP_NOPTS_VALUE && da->header->missing_timestamps)
+ da->pts = 0;
-static bool copy_output(struct af_stream *afs, struct mp_audio_buffer *outbuf,
- int minsamples, bool eof)
-{
- while (mp_audio_buffer_samples(outbuf) < minsamples) {
- if (af_output_frame(afs, eof) < 0)
- return true; // error, stop doing stuff
- struct mp_audio *mpa = af_read_output_frame(afs);
- if (!mpa)
- return false; // out of data
- mp_audio_buffer_append(outbuf, mpa);
- talloc_free(mpa);
- }
- return true;
+ da->current_frame->pts = da->pts;
+
+ if (da->pts != MP_NOPTS_VALUE)
+ da->pts += da->current_frame->samples / (double)da->current_frame->rate;
}
-/* 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.
- * In the former case outbuf has at least minsamples buffered on return.
- * In case of EOF/error it might or might not be. */
-int audio_decode(struct dec_audio *da, struct mp_audio_buffer *outbuf,
- int minsamples)
+void audio_work(struct dec_audio *da)
{
- struct af_stream *afs = da->afilter;
- if (afs->initialized < 1)
- return AD_ERR;
-
- MP_STATS(da, "start audio");
-
- int res;
- while (1) {
- res = 0;
+ if (da->current_frame)
+ return;
- if (copy_output(afs, outbuf, minsamples, false))
- break;
+ if (!da->packet && demux_read_packet_async(da->header, &da->packet) == 0) {
+ da->current_state = AUDIO_WAIT;
+ return;
+ }
- res = decode_new_frame(da);
- if (res < 0) {
- // drain filters first (especially for true EOF case)
- copy_output(afs, outbuf, minsamples, true);
- break;
- }
+ bool had_packet = !!da->packet;
- // On format change, make sure to drain the filter chain.
- if (!mp_audio_config_equals(&afs->input, da->waiting)) {
- copy_output(afs, outbuf, minsamples, true);
- res = AD_NEW_FMT;
- break;
- }
+ int ret = da->ad_driver->decode_packet(da, da->packet, &da->current_frame);
+ if (ret < 0 || (da->packet && da->packet->len == 0)) {
+ talloc_free(da->packet);
+ da->packet = NULL;
+ }
- struct mp_audio *mpa = da->waiting;
- da->waiting = NULL;
- if (af_filter_frame(afs, mpa) < 0)
- return AD_ERR;
+ if (da->current_frame && !mp_audio_config_valid(da->current_frame)) {
+ talloc_free(da->current_frame);
+ da->current_frame = NULL;
}
- MP_STATS(da, "end audio");
+ da->current_state = AUDIO_OK;
+ if (!da->current_frame) {
+ da->current_state = AUDIO_EOF;
+ if (had_packet)
+ da->current_state = AUDIO_SKIP;
+ }
- return res;
+ fix_audio_pts(da);
}
-void audio_reset_decoding(struct dec_audio *d_audio)
+// Fetch an audio frame decoded with audio_work(). Returns one of:
+// AUDIO_OK: *out_frame is set to a new image
+// AUDIO_WAIT: waiting for demuxer; will receive a wakeup signal
+// AUDIO_EOF: end of file, no more frames to be expected
+// AUDIO_SKIP: dropped frame or something similar
+int audio_get_frame(struct dec_audio *da, struct mp_audio **out_frame)
{
- if (d_audio->ad_driver)
- d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
- af_seek_reset(d_audio->afilter);
- d_audio->pts = MP_NOPTS_VALUE;
- d_audio->pts_offset = 0;
- d_audio->pts_reset = false;
- talloc_free(d_audio->waiting);
- d_audio->waiting = NULL;
- talloc_free(d_audio->packet);
- d_audio->packet = NULL;
+ *out_frame = NULL;
+ if (da->current_frame) {
+ *out_frame = da->current_frame;
+ da->current_frame = NULL;
+ return AUDIO_OK;
+ }
+ if (da->current_state == AUDIO_OK)
+ return AUDIO_SKIP;
+ return da->current_state;
}
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index d88d8bfaea..27752f7be1 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -30,39 +30,38 @@ struct dec_audio {
struct mp_log *log;
struct MPOpts *opts;
struct mpv_global *global;
- bool spdif_passthrough, spdif_failed;
const struct ad_functions *ad_driver;
struct sh_stream *header;
- struct af_stream *afilter;
char *decoder_desc;
- struct mp_audio decode_format;
- struct mp_audio *waiting; // used on format-change
- // last known pts value in output from decoder
- double pts;
- // number of samples output by decoder after last known pts
- int pts_offset;
+
+ bool try_spdif;
+
// set every time a jump in timestamps is encountered
bool pts_reset;
+
// For free use by the ad_driver
void *priv;
- // Strictly internal to dec_audio.c
- struct demux_packet *packet;
-};
-enum {
- AD_OK = 0,
- AD_ERR = -1,
- AD_EOF = -2,
- AD_NEW_FMT = -3,
- AD_WAIT = -4,
+ // Strictly internal (dec_audio.c).
+
+ double pts; // endpts of previous frame
+ struct demux_packet *packet;
+ struct mp_audio *current_frame;
+ int current_state;
};
struct mp_decoder_list *audio_decoder_list(void);
int audio_init_best_codec(struct dec_audio *d_audio);
-int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
- int minsamples);
-int initial_audio_decode(struct dec_audio *d_audio);
-void audio_reset_decoding(struct dec_audio *d_audio);
void audio_uninit(struct dec_audio *d_audio);
+void audio_work(struct dec_audio *d_audio);
+
+#define AUDIO_OK 1
+#define AUDIO_WAIT 0
+#define AUDIO_EOF -1
+#define AUDIO_SKIP -2
+int audio_get_frame(struct dec_audio *d_audio, struct mp_audio **out_frame);
+
+void audio_reset_decoding(struct dec_audio *d_audio);
+
#endif /* MPLAYER_DEC_AUDIO_H */