[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