mirror of
https://github.com/livepeer/lpms
synced 2025-09-26 19:51:36 +08:00
ffmpeg: Reset the flush packet after each keyframe.
This handles cases where the packet may contain a frame that triggers a decoder reset - we do not want to cause a reset during the flushing process.
This commit is contained in:
@@ -22,12 +22,12 @@ static int lpms_receive_frame(struct input_ctx *ictx, AVCodecContext *dec, AVFra
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int send_first_pkt(struct input_ctx *ictx)
|
||||
static int send_flush_pkt(struct input_ctx *ictx)
|
||||
{
|
||||
if (ictx->flushed) return 0;
|
||||
if (!ictx->first_pkt) return lpms_ERR_INPUT_NOKF;
|
||||
if (!ictx->flush_pkt) return lpms_ERR_INPUT_NOKF;
|
||||
|
||||
int ret = avcodec_send_packet(ictx->vc, ictx->first_pkt);
|
||||
int ret = avcodec_send_packet(ictx->vc, ictx->flush_pkt);
|
||||
ictx->sentinel_count++;
|
||||
if (ret < 0) {
|
||||
LPMS_ERR(packet_cleanup, "Error sending flush packet");
|
||||
@@ -68,9 +68,14 @@ int decode_in(struct input_ctx *ictx, AVPacket *pkt, AVFrame *frame, int *stream
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ictx->first_pkt && pkt->flags & AV_PKT_FLAG_KEY && decoder == ictx->vc) {
|
||||
ictx->first_pkt = av_packet_clone(pkt);
|
||||
ictx->first_pkt->pts = -1;
|
||||
// Set up flush packet. Do this every keyframe in case the underlying frame changes
|
||||
if (pkt->flags & AV_PKT_FLAG_KEY && decoder == ictx->vc) {
|
||||
if (!ictx->flush_pkt) ictx->flush_pkt = av_packet_clone(pkt);
|
||||
else {
|
||||
av_packet_unref(ictx->flush_pkt);
|
||||
av_packet_ref(ictx->flush_pkt, pkt);
|
||||
}
|
||||
ictx->flush_pkt->pts = -1;
|
||||
}
|
||||
|
||||
ret = lpms_send_packet(ictx, decoder, pkt);
|
||||
@@ -104,7 +109,7 @@ int flush_in(struct input_ctx *ictx, AVFrame *frame, int *stream_index)
|
||||
// TODO this is unnecessary for SW decoding! SW process should match audio
|
||||
if (ictx->vc && !ictx->flushed && ictx->pkt_diff > 0) {
|
||||
ictx->flushing = 1;
|
||||
ret = send_first_pkt(ictx);
|
||||
ret = send_flush_pkt(ictx);
|
||||
if (ret < 0) {
|
||||
ictx->flushed = 1;
|
||||
return ret;
|
||||
|
@@ -20,7 +20,7 @@ struct input_ctx {
|
||||
char *xcoderParams;
|
||||
|
||||
// Decoder flush
|
||||
AVPacket *first_pkt;
|
||||
AVPacket *flush_pkt;
|
||||
int flushed;
|
||||
int flushing;
|
||||
// The diff of `packets sent - frames recv` serves as an estimate of
|
||||
|
@@ -43,7 +43,7 @@ const int lpms_ERR_UNRECOVERABLE = FFERRTAG('U', 'N', 'R', 'V');
|
||||
|
||||
// MOVED TO decoder.[ch]
|
||||
// Decoder: For audio, we pay the price of closing and re-opening the decoder.
|
||||
// For video, we cache the first packet we read (input_ctx.first_pkt).
|
||||
// For video, we cache the last keyframe read (input_ctx.flush_pkt).
|
||||
// The pts is set to a sentinel value and fed to the decoder. Once we
|
||||
// receive all frames from the decoder OR have sent too many sentinel
|
||||
// pkts without receiving anything, then we know the decoder has been
|
||||
@@ -133,7 +133,7 @@ int transcode_shutdown(struct transcode_thread *h, int ret)
|
||||
ictx->flushing = 0;
|
||||
ictx->pkt_diff = 0;
|
||||
ictx->sentinel_count = 0;
|
||||
if (ictx->first_pkt) av_packet_free(&ictx->first_pkt);
|
||||
if (ictx->flush_pkt) av_packet_free(&ictx->flush_pkt);
|
||||
if (ictx->ac) avcodec_free_context(&ictx->ac);
|
||||
if (ictx->vc && (AV_HWDEVICE_TYPE_NONE == ictx->hw_type)) avcodec_free_context(&ictx->vc);
|
||||
for (int i = 0; i < nb_outputs; i++) {
|
||||
|
Reference in New Issue
Block a user