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>
This commit is contained in:
Michael Niedermayer 2014-11-19 12:41:16 +01:00
parent af5fec9538
commit 98c7729c13
2 changed files with 25 additions and 5 deletions

View File

@ -60,6 +60,7 @@
#include "libavutil/bprint.h" #include "libavutil/bprint.h"
#include "libavutil/time.h" #include "libavutil/time.h"
#include "libavutil/threadmessage.h" #include "libavutil/threadmessage.h"
#include "libavcodec/mathops.h"
#include "libavformat/os_support.h" #include "libavformat/os_support.h"
# include "libavfilter/avcodec.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)); 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; delta0 = sync_ipts - ost->sync_opts;
delta = delta0 + duration; delta = delta0 + duration;
@ -985,9 +992,16 @@ static void do_video_out(AVFormatContext *s,
default: default:
av_assert0(0); av_assert0(0);
} }
}
nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
nb0_frames = FFMIN(nb0_frames, nb_frames); 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) { if (nb0_frames == 0 && ost->last_droped) {
nb_frames_drop++; nb_frames_drop++;
av_log(NULL, AV_LOG_VERBOSE, 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); 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); 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 */ /* duplicates frame if needed */
for (i = 0; i < nb_frames; i++) { for (i = 0; i < nb_frames; i++) {
@ -1156,6 +1170,7 @@ static void do_video_out(AVFormatContext *s,
if (!ost->last_frame) if (!ost->last_frame)
ost->last_frame = av_frame_alloc(); ost->last_frame = av_frame_alloc();
av_frame_unref(ost->last_frame); av_frame_unref(ost->last_frame);
if (next_picture)
av_frame_ref(ost->last_frame, 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 * @return 0 for success, <0 for severe errors
*/ */
static int reap_filters(void) static int reap_filters(int flush)
{ {
AVFrame *filtered_frame = NULL; AVFrame *filtered_frame = NULL;
int i; int i;
@ -1249,6 +1264,9 @@ static int reap_filters(void)
if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
av_log(NULL, AV_LOG_WARNING, av_log(NULL, AV_LOG_WARNING,
"Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret)); "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; break;
} }
@ -3741,10 +3759,10 @@ static int transcode_from_filter(FilterGraph *graph, InputStream **best_ist)
*best_ist = NULL; *best_ist = NULL;
ret = avfilter_graph_request_oldest(graph->graph); ret = avfilter_graph_request_oldest(graph->graph);
if (ret >= 0) if (ret >= 0)
return reap_filters(); return reap_filters(0);
if (ret == AVERROR_EOF) { if (ret == AVERROR_EOF) {
ret = reap_filters(); ret = reap_filters(1);
for (i = 0; i < graph->nb_outputs; i++) for (i = 0; i < graph->nb_outputs; i++)
close_output_stream(graph->outputs[i]->ost); close_output_stream(graph->outputs[i]->ost);
return ret; return ret;
@ -3810,10 +3828,11 @@ static int transcode_step(void)
ost->unavailable = 1; ost->unavailable = 1;
return 0; return 0;
} }
if (ret < 0) if (ret < 0)
return ret == AVERROR_EOF ? 0 : ret; return ret == AVERROR_EOF ? 0 : ret;
return reap_filters(); return reap_filters(0);
} }
/* /*

View File

@ -394,6 +394,7 @@ typedef struct OutputStream {
AVFrame *filtered_frame; AVFrame *filtered_frame;
AVFrame *last_frame; AVFrame *last_frame;
int last_droped; int last_droped;
int last_nb0_frames[3];
/* video only */ /* video only */
AVRational frame_rate; AVRational frame_rate;