From 98c7729c133e801889adc3f6527ff271b2df73b5 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Wed, 19 Nov 2014 12:41:16 +0100 Subject: ffmpeg: last frame duplication heuristic This improves the last frames duration with CFR and when the input durations are inaccurate or missing Fixes Ticket4119 Signed-off-by: Michael Niedermayer --- ffmpeg.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'ffmpeg.c') diff --git a/ffmpeg.c b/ffmpeg.c index 8bf507a30e..84ad3092d2 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -60,6 +60,7 @@ #include "libavutil/bprint.h" #include "libavutil/time.h" #include "libavutil/threadmessage.h" +#include "libavcodec/mathops.h" #include "libavformat/os_support.h" # include "libavfilter/avcodec.h" @@ -914,6 +915,12 @@ static void do_video_out(AVFormatContext *s, duration = lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)); } + if (!next_picture) { + //end, flushing + nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0], + ost->last_nb0_frames[1], + ost->last_nb0_frames[2]); + } else { delta0 = sync_ipts - ost->sync_opts; delta = delta0 + duration; @@ -985,9 +992,16 @@ static void do_video_out(AVFormatContext *s, default: av_assert0(0); } + } nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); nb0_frames = FFMIN(nb0_frames, nb_frames); + + memmove(ost->last_nb0_frames + 1, + ost->last_nb0_frames, + sizeof(ost->last_nb0_frames[0]) * (FF_ARRAY_ELEMS(ost->last_nb0_frames) - 1)); + ost->last_nb0_frames[0] = nb0_frames; + if (nb0_frames == 0 && ost->last_droped) { nb_frames_drop++; av_log(NULL, AV_LOG_VERBOSE, @@ -1003,7 +1017,7 @@ static void do_video_out(AVFormatContext *s, nb_frames_dup += nb_frames - (nb0_frames && ost->last_droped) - (nb_frames > nb0_frames); av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1); } - ost->last_droped = nb_frames == nb0_frames; + ost->last_droped = nb_frames == nb0_frames && next_picture; /* duplicates frame if needed */ for (i = 0; i < nb_frames; i++) { @@ -1156,6 +1170,7 @@ static void do_video_out(AVFormatContext *s, if (!ost->last_frame) ost->last_frame = av_frame_alloc(); av_frame_unref(ost->last_frame); + if (next_picture) av_frame_ref(ost->last_frame, next_picture); } @@ -1219,7 +1234,7 @@ static void finish_output_stream(OutputStream *ost) * * @return 0 for success, <0 for severe errors */ -static int reap_filters(void) +static int reap_filters(int flush) { AVFrame *filtered_frame = NULL; int i; @@ -1249,6 +1264,9 @@ static int reap_filters(void) if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { av_log(NULL, AV_LOG_WARNING, "Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret)); + } else if (flush) { + if (filter->inputs[0]->type == AVMEDIA_TYPE_VIDEO) + do_video_out(of->ctx, ost, NULL, AV_NOPTS_VALUE); } break; } @@ -3741,10 +3759,10 @@ static int transcode_from_filter(FilterGraph *graph, InputStream **best_ist) *best_ist = NULL; ret = avfilter_graph_request_oldest(graph->graph); if (ret >= 0) - return reap_filters(); + return reap_filters(0); if (ret == AVERROR_EOF) { - ret = reap_filters(); + ret = reap_filters(1); for (i = 0; i < graph->nb_outputs; i++) close_output_stream(graph->outputs[i]->ost); return ret; @@ -3810,10 +3828,11 @@ static int transcode_step(void) ost->unavailable = 1; return 0; } + if (ret < 0) return ret == AVERROR_EOF ? 0 : ret; - return reap_filters(); + return reap_filters(0); } /* -- cgit v1.2.3