summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2022-11-28 12:07:01 +0100
committerAnton Khirnov <anton@khirnov.net>2022-11-28 14:37:42 +0100
commitb34ccb4323d4ece11e6d98ceb35194a94f1ae6b3 (patch)
treeca31ed6f4c0822352661174bb4a3a2c55b05f7da
parent86c1efb7695126ed727851d6647d0de037c76c75 (diff)
fftools/ffmpeg: move video frame dup/drop logic into its own function
-rw-r--r--fftools/ffmpeg.c137
1 files changed, 75 insertions, 62 deletions
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 86cf1e36ef..cfe295c0dc 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1030,6 +1030,79 @@ static void do_subtitle_out(OutputFile *of,
}
}
+/* Convert frame timestamps to the encoder timebase and decide how many times
+ * should this (and possibly previous) frame be repeated in order to conform to
+ * desired target framerate (if any).
+ */
+static void video_sync_process(OutputFile *of, OutputStream *ost,
+ AVFrame *next_picture, double duration,
+ int64_t *nb_frames, int64_t *nb_frames_prev)
+{
+ double delta0, delta;
+
+ double sync_ipts = adjust_frame_pts_to_encoder_tb(of, ost, next_picture);
+ /* delta0 is the "drift" between the input frame (next_picture) and
+ * where it would fall in the output. */
+ delta0 = sync_ipts - ost->next_pts;
+ delta = delta0 + duration;
+
+ // tracks the number of times the PREVIOUS frame should be duplicated,
+ // mostly for variable framerate (VFR)
+ *nb_frames_prev = 0;
+ /* by default, we output a single frame */
+ *nb_frames = 1;
+
+ if (delta0 < 0 &&
+ delta > 0 &&
+ ost->vsync_method != VSYNC_PASSTHROUGH &&
+ ost->vsync_method != VSYNC_DROP) {
+ if (delta0 < -0.6) {
+ av_log(NULL, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0);
+ } else
+ av_log(NULL, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0);
+ sync_ipts = ost->next_pts;
+ duration += delta0;
+ delta0 = 0;
+ }
+
+ switch (ost->vsync_method) {
+ case VSYNC_VSCFR:
+ if (ost->vsync_frame_number == 0 && delta0 >= 0.5) {
+ av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0));
+ delta = duration;
+ delta0 = 0;
+ ost->next_pts = llrint(sync_ipts);
+ }
+ case VSYNC_CFR:
+ // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
+ if (frame_drop_threshold && delta < frame_drop_threshold && ost->vsync_frame_number) {
+ *nb_frames = 0;
+ } else if (delta < -1.1)
+ *nb_frames = 0;
+ else if (delta > 1.1) {
+ *nb_frames = llrintf(delta);
+ if (delta0 > 1.1)
+ *nb_frames_prev = llrintf(delta0 - 0.6);
+ }
+ next_picture->duration = 1;
+ break;
+ case VSYNC_VFR:
+ if (delta <= -0.6)
+ *nb_frames = 0;
+ else if (delta > 0.6)
+ ost->next_pts = llrint(sync_ipts);
+ next_picture->duration = duration;
+ break;
+ case VSYNC_DROP:
+ case VSYNC_PASSTHROUGH:
+ next_picture->duration = duration;
+ ost->next_pts = llrint(sync_ipts);
+ break;
+ default:
+ av_assert0(0);
+ }
+}
+
static enum AVPictureType forced_kf_apply(KeyframeForceCtx *kf, AVRational tb,
const AVFrame *in_picture, int dup_idx)
{
@@ -1089,7 +1162,6 @@ static void do_video_out(OutputFile *of,
AVCodecContext *enc = ost->enc_ctx;
AVRational frame_rate;
int64_t nb_frames, nb_frames_prev, i;
- double delta, delta0;
double duration = 0;
InputStream *ist = ost->ist;
AVFilterContext *filter = ost->filter->filter;
@@ -1118,67 +1190,8 @@ static void do_video_out(OutputFile *of,
ost->last_nb0_frames[1],
ost->last_nb0_frames[2]);
} else {
- double sync_ipts = adjust_frame_pts_to_encoder_tb(of, ost, next_picture);
- /* delta0 is the "drift" between the input frame (next_picture) and
- * where it would fall in the output. */
- delta0 = sync_ipts - ost->next_pts;
- delta = delta0 + duration;
-
- // tracks the number of times the PREVIOUS frame should be duplicated,
- // mostly for variable framerate (VFR)
- nb_frames_prev = 0;
- /* by default, we output a single frame */
- nb_frames = 1;
-
- if (delta0 < 0 &&
- delta > 0 &&
- ost->vsync_method != VSYNC_PASSTHROUGH &&
- ost->vsync_method != VSYNC_DROP) {
- if (delta0 < -0.6) {
- av_log(NULL, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0);
- } else
- av_log(NULL, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0);
- sync_ipts = ost->next_pts;
- duration += delta0;
- delta0 = 0;
- }
-
- switch (ost->vsync_method) {
- case VSYNC_VSCFR:
- if (ost->vsync_frame_number == 0 && delta0 >= 0.5) {
- av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0));
- delta = duration;
- delta0 = 0;
- ost->next_pts = llrint(sync_ipts);
- }
- case VSYNC_CFR:
- // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
- if (frame_drop_threshold && delta < frame_drop_threshold && ost->vsync_frame_number) {
- nb_frames = 0;
- } else if (delta < -1.1)
- nb_frames = 0;
- else if (delta > 1.1) {
- nb_frames = llrintf(delta);
- if (delta0 > 1.1)
- nb_frames_prev = llrintf(delta0 - 0.6);
- }
- next_picture->duration = 1;
- break;
- case VSYNC_VFR:
- if (delta <= -0.6)
- nb_frames = 0;
- else if (delta > 0.6)
- ost->next_pts = llrint(sync_ipts);
- next_picture->duration = duration;
- break;
- case VSYNC_DROP:
- case VSYNC_PASSTHROUGH:
- next_picture->duration = duration;
- ost->next_pts = llrint(sync_ipts);
- break;
- default:
- av_assert0(0);
- }
+ video_sync_process(of, ost, next_picture, duration,
+ &nb_frames, &nb_frames_prev);
}
memmove(ost->last_nb0_frames + 1,