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; - if (!mpkt) - return 0; + spdif_ctx->queued_packet = mpkt ? demux_copy_packet(mpkt) : NULL; + spdif_ctx->got_eof = !mpkt; + return true; +} - double pts = mpkt->pts; +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 (!spdif_ctx->queued_packet) + return true; + + 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);