diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2014-11-19 12:41:16 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2015-04-03 19:09:31 +0200 |
commit | 98c7729c133e801889adc3f6527ff271b2df73b5 (patch) | |
tree | 33b1963b243b0c65babee41711e5f1df5d814739 | |
parent | af5fec9538d88540af5bb2dd0e4b91162ce6fa13 (diff) | |
download | ffmpeg-98c7729c133e801889adc3f6527ff271b2df73b5.tar.gz |
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 <michaelni@gmx.at>
-rw-r--r-- | ffmpeg.c | 29 | ||||
-rw-r--r-- | ffmpeg.h | 1 |
2 files changed, 25 insertions, 5 deletions
@@ -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); } /* @@ -394,6 +394,7 @@ typedef struct OutputStream { AVFrame *filtered_frame; AVFrame *last_frame; int last_droped; + int last_nb0_frames[3]; /* video only */ AVRational frame_rate; |