[FFmpeg-devel] [PATCH 4/6] ffmpeg: flush and drain video filters.

Nicolas George nicolas.george at normalesup.org
Sun Mar 11 00:29:48 CET 2012


When EOF is reached on the input stream, ffmpeg must
ensure that the graph input returns EOF instead of EAGAIN
and request frames once more until exhaustion.

Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 ffmpeg.c |   38 ++++++++++++++++++++++++++++----------
 1 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/ffmpeg.c b/ffmpeg.c
index 4714b61..abcf328 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -2082,7 +2082,7 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
     return ret;
 }
 
-static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *pkt_pts)
+static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *pkt_pts, int flush)
 {
     AVFrame *decoded_frame;
     void *buffer_to_free = NULL;
@@ -2105,10 +2105,14 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
         return ret;
 
     if (!*got_output) {
-        /* no picture yet */
+#if CONFIG_AVFILTER
+        if (!flush)
+#endif
         return ret;
     }
 
+    if (*got_output) {
+    /* TODO reindent */
     best_effort_timestamp= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "best_effort_timestamp");
     if(*best_effort_timestamp != AV_NOPTS_VALUE)
         ist->next_pts = ist->pts = decoded_frame->pts = *best_effort_timestamp;
@@ -2116,12 +2120,15 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
     pkt->size = 0;
 
     pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free);
+    }
 
 #if CONFIG_AVFILTER
     frame_sample_aspect= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "sample_aspect_ratio");
     for(i=0;i<nb_output_streams;i++) {
         OutputStream *ost = ost = &output_streams[i];
         if(check_output_constraints(ist, ost) && ost->encoding_needed){
+            if (*got_output) {
+            /* TODO reindent */
             if (!frame_sample_aspect->num)
                 *frame_sample_aspect = ist->st->sample_aspect_ratio;
             decoded_frame->pts = ist->pts;
@@ -2144,6 +2151,9 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
                 av_log(NULL, AV_LOG_FATAL, "Failed to inject frame into filter network\n");
                 exit_program(1);
             }
+            } else {
+                av_vsrc_buffer_set_return_value(ost->input_video_filter, AVERROR_EOF);
+            }
         }
     }
 #endif
@@ -2157,13 +2167,21 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
             continue;
 
 #if CONFIG_AVFILTER
-        while (av_buffersink_poll_frame(ost->output_video_filter)) {
+        while (1) {
             AVRational ist_pts_tb = ost->output_video_filter->inputs[0]->time_base;
             AVFrame *filtered_frame;
 
-            if (av_buffersink_get_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0){
-                av_log(NULL, AV_LOG_WARNING, "AV Filter told us it has a frame available but failed to output one\n");
-                goto cont;
+            ret = av_buffersink_get_buffer_ref(ost->output_video_filter, &ost->picref, 0);
+            if (ret < 0){
+                if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
+                    char errbuf[128];
+                    av_strerror(ret, errbuf, sizeof(errbuf));
+                    av_log(NULL, AV_LOG_WARNING,
+                           "Error filtering video frame: %s\n", errbuf);
+                } else {
+                    ret = 0;
+                }
+                break;
             }
             if (!ist->filtered_frame && !(ist->filtered_frame = avcodec_alloc_frame())) {
                 ret = AVERROR(ENOMEM);
@@ -2176,7 +2194,6 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
             if (ost->picref->video && !ost->frame_aspect_ratio)
                 ost->st->codec->sample_aspect_ratio = ost->picref->video->sample_aspect_ratio;
             do_video_out(output_files[ost->file_index].ctx, ost, ist, filtered_frame);
-            cont:
             avfilter_unref_buffer(ost->picref);
         }
 #else
@@ -2219,7 +2236,7 @@ static int output_packet(InputStream *ist,
                          OutputStream *ost_table, int nb_ostreams,
                          const AVPacket *pkt)
 {
-    int ret = 0, i;
+    int ret = 0, i, flush;
     int got_output;
     int64_t pkt_pts = AV_NOPTS_VALUE;
 
@@ -2230,7 +2247,8 @@ static int output_packet(InputStream *ist,
     if (ist->next_pts == AV_NOPTS_VALUE)
         ist->next_pts = ist->pts;
 
-    if (pkt == NULL) {
+    flush = pkt == NULL;
+    if (flush) {
         /* EOF handling */
         av_init_packet(&avpkt);
         avpkt.data = NULL;
@@ -2267,7 +2285,7 @@ static int output_packet(InputStream *ist,
             ret = transcode_audio    (ist, &avpkt, &got_output);
             break;
         case AVMEDIA_TYPE_VIDEO:
-            ret = transcode_video    (ist, &avpkt, &got_output, &pkt_pts);
+            ret = transcode_video    (ist, &avpkt, &got_output, &pkt_pts, flush);
             if (avpkt.duration) {
                 duration = av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
             } else if(ist->st->codec->time_base.num != 0 && ist->st->codec->time_base.den != 0) {
-- 
1.7.9.1



More information about the ffmpeg-devel mailing list