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

Michael Niedermayer michaelni at gmx.at
Thu Aug 23 01:28:22 CEST 2012


On Mon, Aug 20, 2012 at 11:28:15PM +0200, Nicolas George wrote:
> 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--;
> +        }

i think the special casing of filter vs no filter all over the place
is bad in the long term


>      }
>  }
>  
> @@ -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;

this should not be needed, the buffer source should know when its
closed and do nothing / return some appropriate return value


> +        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) {

why is it needed to move this to a local variable ?

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

it is not once nor twice but times without number that the same ideas make
their appearance in the world. -- Aristotle
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120823/9cdce6a2/attachment.asc>


More information about the ffmpeg-devel mailing list