summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-01-11 11:58:26 +0100
committerwm4 <wm4@nowhere>2017-01-11 11:58:32 +0100
commitcbd8abcbff83624c20460cc05bf33d72c5148d67 (patch)
tree03df0420a2e1722d6eb4d85738d8210ba3931cc8
parentf8baae585451bb072e8ef606bafd7c0d5e369bf7 (diff)
downloadmpv-cbd8abcbff83624c20460cc05bf33d72c5148d67.tar.bz2
mpv-cbd8abcbff83624c20460cc05bf33d72c5148d67.tar.xz
audio: restructure decode loop
Same deal as with video. Including the EOF handling. (It would be nice if this code were not duplicated, but right now we're not even close to unifying the audio and video code paths.)
-rw-r--r--audio/decode/ad.h7
-rw-r--r--audio/decode/ad_lavc.c60
-rw-r--r--audio/decode/ad_spdif.c56
-rw-r--r--audio/decode/dec_audio.c19
4 files changed, 85 insertions, 57 deletions
diff --git a/audio/decode/ad.h b/audio/decode/ad.h
index 771ceb7e88..bbb050eb4c 100644
--- a/audio/decode/ad.h
+++ b/audio/decode/ad.h
@@ -35,8 +35,11 @@ struct ad_functions {
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);
- int (*decode_packet)(struct dec_audio *da, struct demux_packet *pkt,
- struct mp_audio **out);
+ // 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_audio **out);
};
enum ad_ctrl {
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index c4d3a2ae7b..073d363122 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -45,7 +45,6 @@ struct priv {
uint32_t skip_samples, trim_samples;
bool preroll_done;
double next_pts;
- bool needs_reset;
AVRational codec_timebase;
};
@@ -177,14 +176,12 @@ static int control(struct dec_audio *da, int cmd, void *arg)
ctx->trim_samples = 0;
ctx->preroll_done = false;
ctx->next_pts = MP_NOPTS_VALUE;
- ctx->needs_reset = false;
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
-static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
- struct mp_audio **out)
+static bool send_packet(struct dec_audio *da, struct demux_packet *mpkt)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
@@ -195,41 +192,43 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
if (mpkt && priv->next_pts == MP_NOPTS_VALUE)
priv->next_pts = mpkt->pts;
- int in_len = mpkt ? mpkt->len : 0;
-
AVPacket pkt;
mp_set_av_packet(&pkt, mpkt, &priv->codec_timebase);
- int got_frame = 0;
- av_frame_unref(priv->avframe);
+ int ret = avcodec_send_packet(avctx, mpkt ? &pkt : NULL);
- if (priv->needs_reset)
- control(da, ADCTRL_RESET, NULL);
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ return false;
- int ret = avcodec_send_packet(avctx, &pkt);
- if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
- if (ret >= 0 && mpkt)
- mpkt->len = 0;
- ret = avcodec_receive_frame(avctx, priv->avframe);
- if (ret >= 0)
- got_frame = 1;
- if (ret == AVERROR_EOF)
- priv->needs_reset = true;
- if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
- ret = 0;
- }
- if (ret < 0) {
+ if (ret < 0)
+ MP_ERR(da, "Error decoding audio.\n");
+ return true;
+}
+
+static bool receive_frame(struct dec_audio *da, struct mp_audio **out)
+{
+ struct priv *priv = da->priv;
+ AVCodecContext *avctx = priv->avctx;
+
+ int ret = avcodec_receive_frame(avctx, priv->avframe);
+
+ 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);
+ return false;
+ } else if (ret < 0 && ret != AVERROR(EAGAIN)) {
MP_ERR(da, "Error decoding audio.\n");
- return -1;
}
- if (!got_frame)
- return 0;
+
+ if (!priv->avframe->buf[0])
+ return true;
double out_pts = mp_pts_from_av(priv->avframe->pts, &priv->codec_timebase);
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
if (!mpframe)
- return -1;
+ return true;
struct mp_chmap lavc_chmap = mpframe->channels;
if (lavc_chmap.num != avctx->channels)
@@ -279,8 +278,8 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
av_frame_unref(priv->avframe);
- MP_DBG(da, "Decoded %d -> %d samples\n", in_len, mpframe->samples);
- return 0;
+ MP_DBG(da, "Decoded %d samples\n", mpframe->samples);
+ return true;
}
static void add_decoders(struct mp_decoder_list *list)
@@ -294,5 +293,6 @@ const struct ad_functions ad_lavc = {
.init = init,
.uninit = uninit,
.control = control,
- .decode_packet = decode_packet,
+ .send_packet = send_packet,
+ .receive_frame = receive_frame,
};
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index 30c7883bf4..5ab76e677a 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -42,6 +42,8 @@ struct spdifContext {
bool use_dts_hd;
struct mp_audio fmt;
struct mp_audio_pool *pool;
+ bool got_eof;
+ struct demux_packet *queued_packet;
};
static int write_packet(void *p, uint8_t *buf, int buf_size)
@@ -71,6 +73,7 @@ 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;
}
}
@@ -243,44 +246,70 @@ fail:
return -1;
}
-static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
- struct mp_audio **out)
+
+static bool send_packet(struct dec_audio *da, struct demux_packet *mpkt)
{
struct spdifContext *spdif_ctx = da->priv;
- spdif_ctx->out_buffer_len = 0;
+ 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_audio **out)
+{
+ struct spdifContext *spdif_ctx = da->priv;
+
+ if (spdif_ctx->got_eof) {
+ spdif_ctx->got_eof = false;
+ return false;
+ }
- if (!mpkt)
- return 0;
+ if (!spdif_ctx->queued_packet)
+ return true;
- double pts = mpkt->pts;
+ double pts = spdif_ctx->queued_packet->pts;
AVPacket pkt;
- mp_set_av_packet(&pkt, mpkt, NULL);
- mpkt->len = 0; // will be fully consumed
+ mp_set_av_packet(&pkt, spdif_ctx->queued_packet, NULL);
pkt.pts = pkt.dts = 0;
if (!spdif_ctx->lavf_ctx) {
if (init_filter(da, &pkt) < 0)
- return -1;
+ goto done;
}
+ spdif_ctx->out_buffer_len = 0;
int ret = av_write_frame(spdif_ctx->lavf_ctx, &pkt);
avio_flush(spdif_ctx->lavf_ctx->pb);
if (ret < 0)
- return -1;
+ 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)
- return -1;
+ goto done;
memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
(*out)->pts = pts;
- return 0;
+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;
+ }
return CONTROL_UNKNOWN;
}
@@ -344,5 +373,6 @@ const struct ad_functions ad_spdif = {
.init = init,
.uninit = uninit,
.control = control,
- .decode_packet = decode_packet,
+ .send_packet = send_packet,
+ .receive_frame = receive_frame,
};
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 9f28302bd5..56f0fe59ad 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -201,7 +201,7 @@ static void fix_audio_pts(struct dec_audio *da)
void audio_work(struct dec_audio *da)
{
- if (da->current_frame)
+ if (da->current_frame || !da->ad_driver)
return;
if (!da->packet && !da->new_segment &&
@@ -217,30 +217,25 @@ void audio_work(struct dec_audio *da)
da->packet = NULL;
}
- bool had_input_packet = !!da->packet;
- bool had_packet = da->packet || da->new_segment;
-
- int ret = da->ad_driver->decode_packet(da, da->packet, &da->current_frame);
- if (ret < 0 || (da->packet && da->packet->len == 0)) {
+ if (da->ad_driver->send_packet(da, da->packet)) {
talloc_free(da->packet);
da->packet = NULL;
}
+ 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 = DATA_OK;
- if (!da->current_frame) {
+ da->current_state = da->current_frame ? DATA_OK : DATA_AGAIN;
+ if (!progress)
da->current_state = DATA_EOF;
- if (had_packet)
- da->current_state = DATA_AGAIN;
- }
fix_audio_pts(da);
- bool segment_end = !da->current_frame && !had_input_packet;
+ bool segment_end = da->current_state == DATA_EOF;
if (da->current_frame) {
mp_audio_clip_timestamps(da->current_frame, da->start, da->end);