[FFmpeg-devel] [PATCH 7/7] ffmpeg: stop decoding and filtering frames for finished streams.

Nicolas George nicolas.george at normalesup.org
Mon Aug 20 23:28:15 CEST 2012


Add a finished field to InputFilter.
If filtering fails with AVERROR_EOF, set the finished field
and decrement the needs_decoding counter.

For non-filtered streams (subtitles), decrement needs_decoding
directly.

Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 ffmpeg.c |   69 +++++++++++++++++++++++++++++++++++++++++++++-----------------
 ffmpeg.h |    1 +
 2 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/ffmpeg.c b/ffmpeg.c
index 4e8d32d..de17a96 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -572,15 +572,33 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
     }
 }
 
+static void close_input_to_filter(InputStream *ist, int index)
+{
+    ist->filters[index]->finished = 1;
+    ist->decoding_needed--;
+}
+
 static void close_output_stream(OutputStream *ost)
 {
     OutputFile *of = output_files[ost->file_index];
+    int ost_min = of->ost_index + ost->index, ost_max = ost_min, i;
 
-    ost->finished = 1;
     if (of->shortest) {
-        int i;
-        for (i = 0; i < of->ctx->nb_streams; i++)
-            output_streams[of->ost_index + i]->finished = 1;
+        ost_min = of->ost_index;
+        ost_max = of->ost_index + of->ctx->nb_streams - 1;
+    }
+    for (i = ost_min; i <= ost_max; i++) {
+        ost = output_streams[i];
+        if (ost->finished)
+            continue;
+        ost->finished = 1;
+        if (ost->filter) {
+            avfilter_link_set_closed(ost->filter->filter->inputs[0], 1);
+        } else {
+            av_assert0(ost->source_index >= 0);
+            if (ost->encoding_needed)
+                input_streams[ost->source_index]->decoding_needed--;
+        }
     }
 }
 
@@ -1411,7 +1429,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
 {
     AVFrame *decoded_frame;
     AVCodecContext *avctx = ist->st->codec;
-    int i, ret, resample_changed;
+    int i, ret, ret_filter, resample_changed;
     AVRational decoded_frame_tb;
 
     if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
@@ -1520,9 +1538,14 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
         decoded_frame->pts = av_rescale_q(decoded_frame->pts,
                                           decoded_frame_tb,
                                           (AVRational){1, ist->st->codec->sample_rate});
-    for (i = 0; i < ist->nb_filters; i++)
-        av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame,
-                               AV_BUFFERSRC_FLAG_PUSH);
+    for (i = 0; i < ist->nb_filters; i++) {
+        if (ist->filters[i]->finished)
+            continue;
+        ret_filter = av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame,
+                                            AV_BUFFERSRC_FLAG_PUSH);
+        if (ret_filter == AVERROR_EOF)
+            close_input_to_filter(ist, i);
+    }
 
     decoded_frame->pts = AV_NOPTS_VALUE;
 
@@ -1533,7 +1556,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
 {
     AVFrame *decoded_frame;
     void *buffer_to_free = NULL;
-    int i, ret = 0, resample_changed;
+    int i, ret = 0, ret_filter, resample_changed;
     int64_t best_effort_timestamp;
     AVRational *frame_sample_aspect;
     float quality;
@@ -1611,6 +1634,9 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
         int changed =      ist->st->codec->width   != ist->filters[i]->filter->outputs[0]->w
                         || ist->st->codec->height  != ist->filters[i]->filter->outputs[0]->h
                         || ist->st->codec->pix_fmt != ist->filters[i]->filter->outputs[0]->format;
+        if (ist->filters[i]->finished)
+            continue;
+
         // XXX what an ugly hack
         if (ist->filters[i]->graph->nb_outputs == 1)
             ist->filters[i]->graph->outputs[0]->ost->last_quality = quality;
@@ -1631,12 +1657,16 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
 
             av_assert0(buf->refcount>0);
             buf->refcount++;
-            av_buffersrc_add_ref(ist->filters[i]->filter, fb,
-                                 AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT |
-                                 AV_BUFFERSRC_FLAG_NO_COPY |
-                                 AV_BUFFERSRC_FLAG_PUSH);
-        } else
-        if(av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, AV_BUFFERSRC_FLAG_PUSH)<0) {
+            ret_filter = av_buffersrc_add_ref(ist->filters[i]->filter, fb,
+                                              AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT |
+                                              AV_BUFFERSRC_FLAG_NO_COPY |
+                                              AV_BUFFERSRC_FLAG_PUSH);
+        } else {
+            ret_filter = av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, AV_BUFFERSRC_FLAG_PUSH);
+        }
+        if (ret_filter == AVERROR_EOF) {
+            close_input_to_filter(ist, i--);
+        } else if (ret_filter < 0) {
             av_log(NULL, AV_LOG_FATAL, "Failed to inject frame into filter network\n");
             exit_program(1);
         }
@@ -1701,12 +1731,13 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
 {
     int ret = 0, i;
     int got_output;
+    int decoding_needed = ist->decoding_needed;
 
     AVPacket avpkt;
     if (!ist->saw_first_ts) {
         ist->dts = ist->st->avg_frame_rate.num ? - ist->st->codec->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
         ist->pts = 0;
-        if (pkt != NULL && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) {
+        if (pkt != NULL && pkt->pts != AV_NOPTS_VALUE && !decoding_needed) {
             ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
             ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong
         }
@@ -1730,12 +1761,12 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
 
     if (pkt->dts != AV_NOPTS_VALUE) {
         ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
-        if (ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)
+        if (ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO || !decoding_needed)
             ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
     }
 
     // while we have more to decode or while the decoder did output something on EOF
-    while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
+    while (decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
         int duration;
     handle_eof:
 
@@ -1798,7 +1829,7 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
     }
 
     /* handle stream copy */
-    if (!ist->decoding_needed) {
+    if (!decoding_needed) {
         rate_emu_sleep(ist);
         ist->dts = ist->next_dts;
         switch (ist->st->codec->codec_type) {
diff --git a/ffmpeg.h b/ffmpeg.h
index a2ba198..593280f 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -168,6 +168,7 @@ typedef struct InputFilter {
     struct InputStream *ist;
     struct FilterGraph *graph;
     uint8_t            *name;
+    int                 finished;
 } InputFilter;
 
 typedef struct OutputFilter {
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list