lavfi/movie: flush decoder frames on EOF

movie currently forwards EOF (or begins looping) immediately upon
reaching the last packet in the input stream, which can leave frames in
the decoder. This change first tries to read any remaining packets from
the decoder before forwarding EOF.

Signed-off-by: Steven Robertson <steven@strobe.cc>
Signed-off-by: Stefano Sabatini <stefasab@gmail.com>
pull/59/head
Steven Robertson 13 years ago committed by Stefano Sabatini
parent a5382b50f2
commit ac726a4f0c
  1. 34
      libavfilter/src_movie.c

@ -42,6 +42,12 @@
#include "internal.h" #include "internal.h"
#include "video.h" #include "video.h"
typedef enum {
STATE_DECODING,
STATE_FLUSHING,
STATE_DONE,
} MovieState;
typedef struct { typedef struct {
/* common A/V fields */ /* common A/V fields */
const AVClass *class; const AVClass *class;
@ -54,7 +60,7 @@ typedef struct {
AVFormatContext *format_ctx; AVFormatContext *format_ctx;
AVCodecContext *codec_ctx; AVCodecContext *codec_ctx;
int is_done; MovieState state;
AVFrame *frame; ///< video frame to store the decoded images in AVFrame *frame; ///< video frame to store the decoded images in
/* video-only fields */ /* video-only fields */
@ -236,13 +242,14 @@ static int movie_get_frame(AVFilterLink *outlink)
{ {
MovieContext *movie = outlink->src->priv; MovieContext *movie = outlink->src->priv;
AVPacket pkt; AVPacket pkt;
int ret, frame_decoded; int ret = 0, frame_decoded;
AVStream *st = movie->format_ctx->streams[movie->stream_index]; AVStream *st = movie->format_ctx->streams[movie->stream_index];
if (movie->is_done == 1) if (movie->state == STATE_DONE)
return 0; return 0;
while (1) { while (1) {
if (movie->state == STATE_DECODING) {
ret = av_read_frame(movie->format_ctx, &pkt); ret = av_read_frame(movie->format_ctx, &pkt);
if (ret == AVERROR_EOF) { if (ret == AVERROR_EOF) {
int64_t timestamp; int64_t timestamp;
@ -251,20 +258,19 @@ static int movie_get_frame(AVFilterLink *outlink)
if (movie->format_ctx->start_time != AV_NOPTS_VALUE) if (movie->format_ctx->start_time != AV_NOPTS_VALUE)
timestamp += movie->format_ctx->start_time; timestamp += movie->format_ctx->start_time;
if (av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD) < 0) { if (av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD) < 0) {
movie->is_done = 1; movie->state = STATE_FLUSHING;
break;
} else if (movie->loop_count>1) } else if (movie->loop_count>1)
movie->loop_count--; movie->loop_count--;
continue; continue;
} else { } else {
movie->is_done = 1; movie->state = STATE_FLUSHING;
break;
} }
} else if (ret < 0) } else if (ret < 0)
break; break;
}
// Is this a packet from the video stream? // Is this a packet from the video stream?
if (pkt.stream_index == movie->stream_index) { if (pkt.stream_index == movie->stream_index || movie->state == STATE_FLUSHING) {
avcodec_decode_video2(movie->codec_ctx, movie->frame, &frame_decoded, &pkt); avcodec_decode_video2(movie->codec_ctx, movie->frame, &frame_decoded, &pkt);
if (frame_decoded) { if (frame_decoded) {
@ -295,6 +301,10 @@ static int movie_get_frame(AVFilterLink *outlink)
av_free_packet(&pkt); av_free_packet(&pkt);
return 0; return 0;
} else if (movie->state == STATE_FLUSHING) {
movie->state = STATE_DONE;
av_free_packet(&pkt);
return AVERROR_EOF;
} }
} }
// Free the packet that was allocated by av_read_frame // Free the packet that was allocated by av_read_frame
@ -310,7 +320,7 @@ static int movie_request_frame(AVFilterLink *outlink)
MovieContext *movie = outlink->src->priv; MovieContext *movie = outlink->src->priv;
int ret; int ret;
if (movie->is_done) if (movie->state == STATE_DONE)
return AVERROR_EOF; return AVERROR_EOF;
if ((ret = movie_get_frame(outlink)) < 0) if ((ret = movie_get_frame(outlink)) < 0)
return ret; return ret;
@ -391,7 +401,7 @@ static int amovie_get_samples(AVFilterLink *outlink)
AVPacket pkt; AVPacket pkt;
int ret, got_frame = 0; int ret, got_frame = 0;
if (!movie->pkt.size && movie->is_done == 1) if (!movie->pkt.size && movie->state == STATE_DONE)
return AVERROR_EOF; return AVERROR_EOF;
/* check for another frame, in case the previous one was completely consumed */ /* check for another frame, in case the previous one was completely consumed */
@ -408,7 +418,7 @@ static int amovie_get_samples(AVFilterLink *outlink)
} }
if (ret == AVERROR_EOF) { if (ret == AVERROR_EOF) {
movie->is_done = 1; movie->state = STATE_DONE;
return ret; return ret;
} }
} }
@ -451,7 +461,7 @@ static int amovie_request_frame(AVFilterLink *outlink)
MovieContext *movie = outlink->src->priv; MovieContext *movie = outlink->src->priv;
int ret; int ret;
if (movie->is_done) if (movie->state == STATE_DONE)
return AVERROR_EOF; return AVERROR_EOF;
do { do {
if ((ret = amovie_get_samples(outlink)) < 0) if ((ret = amovie_get_samples(outlink)) < 0)

Loading…
Cancel
Save