diff --git a/ffmpeg/decoder.c b/ffmpeg/decoder.c index 2d04505365..c19ff7f446 100755 --- a/ffmpeg/decoder.c +++ b/ffmpeg/decoder.c @@ -28,6 +28,7 @@ static int send_flush_pkt(struct input_ctx *ictx) if (!ictx->flush_pkt) return lpms_ERR_INPUT_NOKF; int ret = avcodec_send_packet(ictx->vc, ictx->flush_pkt); + if (ret == AVERROR(EAGAIN)) return ret; // decoder is mid-reset ictx->sentinel_count++; if (ret < 0) { LPMS_ERR(packet_cleanup, "Error sending flush packet"); @@ -79,7 +80,14 @@ int decode_in(struct input_ctx *ictx, AVPacket *pkt, AVFrame *frame, int *stream } ret = lpms_send_packet(ictx, decoder, pkt); - if (ret < 0) { + if (ret == AVERROR(EAGAIN)) { + // Usually means the decoder needs to drain itself - block demuxing until then + // Seems to happen during mid-stream resolution changes + if (ictx->blocked_pkt) LPMS_ERR_RETURN("unexpectedly got multiple blocked packets"); + ictx->blocked_pkt = av_packet_clone(pkt); + if (!ictx->blocked_pkt) LPMS_ERR_RETURN("could not clone packet for blocking"); + // continue in an attempt to drain the decoder + } else if (ret < 0) { LPMS_ERR_RETURN("Error sending packet to decoder"); } ret = lpms_receive_frame(ictx, decoder, frame); @@ -110,7 +118,9 @@ int flush_in(struct input_ctx *ictx, AVFrame *frame, int *stream_index) if (ictx->vc && !ictx->flushed && ictx->pkt_diff > 0) { ictx->flushing = 1; ret = send_flush_pkt(ictx); - if (ret < 0) { + if (ret == AVERROR(EAGAIN)) { + // do nothing; decoder recently reset and needs to drain so let it + } else if (ret < 0) { ictx->flushed = 1; return ret; } @@ -142,7 +152,10 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt, av_packet_unref(pkt); // Demux next packet - ret = demux_in(ictx, pkt); + if (ictx->blocked_pkt) { + av_packet_move_ref(pkt, ictx->blocked_pkt); + av_packet_free(&ictx->blocked_pkt); + } else ret = demux_in(ictx, pkt); // See if we got anything if (ret == AVERROR_EOF) { // no more packets, flush the decoder(s) @@ -381,5 +394,6 @@ void free_input(struct input_ctx *inctx) if (inctx->hw_device_ctx) av_buffer_unref(&inctx->hw_device_ctx); if (inctx->last_frame_v) av_frame_free(&inctx->last_frame_v); if (inctx->last_frame_a) av_frame_free(&inctx->last_frame_a); + if (inctx->blocked_pkt) av_packet_free(&inctx->blocked_pkt); } diff --git a/ffmpeg/decoder.h b/ffmpeg/decoder.h index 2dd85a5f25..4088682242 100755 --- a/ffmpeg/decoder.h +++ b/ffmpeg/decoder.h @@ -33,6 +33,9 @@ struct input_ctx { #define SENTINEL_MAX 8 uint16_t sentinel_count; + // Packet held while decoder is blocked and needs to drain + AVPacket *blocked_pkt; + // Filter flush AVFrame *last_frame_v, *last_frame_a;