The option is useful to ensure that there is a seek point exactly at a
place the user will probably want to jump precisely sometime, the
major example would be the end of an opening and the beginning of a
chapter. The scene change detection system will often make it happen,
but not always for example if there is a fade-in.
See the thread:
Subject: [FFmpeg-devel] [PATCH] -force_key_frames option
Date: Tue, 12 Oct 2010 15:16:26 +0200
Patch by Nicolas George -mail nicolas,george,normalesup,org.
Originally committed as revision 25526 to svn://svn.ffmpeg.org/ffmpeg/trunk
... | ... |
@@ -495,6 +495,12 @@ Bitstream filters available are "dump_extra", "remove_extra", "noise", "h264_mp4 |
495 | 495 |
@example |
496 | 496 |
ffmpeg -i h264.mp4 -vcodec copy -vbsf h264_mp4toannexb -an out.h264 |
497 | 497 |
@end example |
498 |
+@item -force_key_frames @var{time}[,@var{time}...] |
|
499 |
+Force key frames at the specified timestamps, more precisely at the first |
|
500 |
+frames after each specified time. |
|
501 |
+This option can be useful to ensure that a seek point is present at a |
|
502 |
+chapter mark or any other designated place in the output file. |
|
503 |
+The timestamps must be specified in ascending order. |
|
498 | 504 |
@end table |
499 | 505 |
|
500 | 506 |
@section Audio Options |
... | ... |
@@ -225,6 +225,7 @@ static int nb_frames_drop = 0; |
225 | 225 |
static int input_sync; |
226 | 226 |
static uint64_t limit_filesize = 0; |
227 | 227 |
static int force_fps = 0; |
228 |
+static char *forced_key_frames = NULL; |
|
228 | 229 |
|
229 | 230 |
static int pgmyuv_compatibility_hack=0; |
230 | 231 |
static float dts_delta_threshold = 10; |
... | ... |
@@ -272,6 +273,11 @@ typedef struct AVOutputStream { |
272 | 272 |
int original_height; |
273 | 273 |
int original_width; |
274 | 274 |
|
275 |
+ /* forced key frames */ |
|
276 |
+ int64_t *forced_kf_pts; |
|
277 |
+ int forced_kf_count; |
|
278 |
+ int forced_kf_index; |
|
279 |
+ |
|
275 | 280 |
/* audio only */ |
276 | 281 |
int audio_resample; |
277 | 282 |
ReSampleContext *resample; /* for audio resampling */ |
... | ... |
@@ -1189,6 +1195,11 @@ static void do_video_out(AVFormatContext *s, |
1189 | 1189 |
big_picture.pts= ost->sync_opts; |
1190 | 1190 |
// big_picture.pts= av_rescale(ost->sync_opts, AV_TIME_BASE*(int64_t)enc->time_base.num, enc->time_base.den); |
1191 | 1191 |
//av_log(NULL, AV_LOG_DEBUG, "%"PRId64" -> encoder\n", ost->sync_opts); |
1192 |
+ if (ost->forced_kf_index < ost->forced_kf_count && |
|
1193 |
+ big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) { |
|
1194 |
+ big_picture.pict_type = FF_I_TYPE; |
|
1195 |
+ ost->forced_kf_index++; |
|
1196 |
+ } |
|
1192 | 1197 |
ret = avcodec_encode_video(enc, |
1193 | 1198 |
bit_buffer, bit_buffer_size, |
1194 | 1199 |
&big_picture); |
... | ... |
@@ -1837,6 +1848,29 @@ static int copy_chapters(int infile, int outfile) |
1837 | 1837 |
return 0; |
1838 | 1838 |
} |
1839 | 1839 |
|
1840 |
+static void parse_forced_key_frames(char *kf, AVOutputStream *ost, |
|
1841 |
+ AVCodecContext *avctx) |
|
1842 |
+{ |
|
1843 |
+ char *p; |
|
1844 |
+ int n = 1, i; |
|
1845 |
+ int64_t t; |
|
1846 |
+ |
|
1847 |
+ for (p = kf; *p; p++) |
|
1848 |
+ if (*p == ',') |
|
1849 |
+ n++; |
|
1850 |
+ ost->forced_kf_count = n; |
|
1851 |
+ ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n); |
|
1852 |
+ if (!ost->forced_kf_pts) { |
|
1853 |
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); |
|
1854 |
+ ffmpeg_exit(1); |
|
1855 |
+ } |
|
1856 |
+ for (i = 0; i < n; i++) { |
|
1857 |
+ p = i ? strchr(p, ',') + 1 : kf; |
|
1858 |
+ t = parse_time_or_die("force_key_frames", p, 1); |
|
1859 |
+ ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base); |
|
1860 |
+ } |
|
1861 |
+} |
|
1862 |
+ |
|
1840 | 1863 |
/* |
1841 | 1864 |
* The following code is the main loop of the file converter |
1842 | 1865 |
*/ |
... | ... |
@@ -2578,6 +2612,7 @@ static int transcode(AVFormatContext **output_files, |
2578 | 2578 |
av_fifo_free(ost->fifo); /* works even if fifo is not |
2579 | 2579 |
initialized but set to zero */ |
2580 | 2580 |
av_free(ost->pict_tmp.data[0]); |
2581 |
+ av_free(ost->forced_kf_pts); |
|
2581 | 2582 |
if (ost->video_resample) |
2582 | 2583 |
sws_freeContext(ost->img_resample_ctx); |
2583 | 2584 |
if (ost->resample) |
... | ... |
@@ -3333,6 +3368,9 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) |
3333 | 3333 |
video_enc->flags |= CODEC_FLAG_PASS2; |
3334 | 3334 |
} |
3335 | 3335 |
} |
3336 |
+ |
|
3337 |
+ if (forced_key_frames) |
|
3338 |
+ parse_forced_key_frames(forced_key_frames, ost, video_enc); |
|
3336 | 3339 |
} |
3337 | 3340 |
if (video_language) { |
3338 | 3341 |
av_metadata_set2(&st->metadata, "language", video_language, 0); |
... | ... |
@@ -3342,6 +3380,7 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) |
3342 | 3342 |
/* reset some key parameters */ |
3343 | 3343 |
video_disable = 0; |
3344 | 3344 |
av_freep(&video_codec_name); |
3345 |
+ av_freep(&forced_key_frames); |
|
3345 | 3346 |
video_stream_copy = 0; |
3346 | 3347 |
frame_pix_fmt = PIX_FMT_NONE; |
3347 | 3348 |
} |
... | ... |
@@ -3644,6 +3683,7 @@ static void opt_output_file(const char *filename) |
3644 | 3644 |
set_context_opts(oc, avformat_opts, AV_OPT_FLAG_ENCODING_PARAM, NULL); |
3645 | 3645 |
|
3646 | 3646 |
nb_streamid_map = 0; |
3647 |
+ av_freep(&forced_key_frames); |
|
3647 | 3648 |
} |
3648 | 3649 |
|
3649 | 3650 |
/* same option as mencoder */ |
... | ... |
@@ -4094,6 +4134,7 @@ static const OptionDef options[] = { |
4094 | 4094 |
{ "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" }, |
4095 | 4095 |
{ "force_fps", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&force_fps}, "force the selected framerate, disable the best supported framerate selection" }, |
4096 | 4096 |
{ "streamid", OPT_FUNC2 | HAS_ARG | OPT_EXPERT, {(void*)opt_streamid}, "set the value of an outfile streamid", "streamIndex:value" }, |
4097 |
+ { "force_key_frames", OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void *)&forced_key_frames}, "force key frames at specified timestamps", "timestamps" }, |
|
4097 | 4098 |
|
4098 | 4099 |
/* audio options */ |
4099 | 4100 |
{ "ab", OPT_FUNC2 | HAS_ARG | OPT_AUDIO, {(void*)opt_bitrate}, "set bitrate (in bits/s)", "bitrate" }, |