diff options
author | Nicolas George <nicola.george@normalesup.org> | 2010-10-18 21:47:15 +0000 |
---|---|---|
committer | Stefano Sabatini <stefano.sabatini-lala@poste.it> | 2010-10-18 21:47:15 +0000 |
commit | 4ad08021e8e81057d89c75fd63b97cd1f0757a23 (patch) | |
tree | 9ac4c2b056547e55a1e0f183bc3137d3e215098c | |
parent | 43945b2766befcb4b2a5eb9b57fd9c25d9f4c849 (diff) | |
download | ffmpeg-4ad08021e8e81057d89c75fd63b97cd1f0757a23.tar.gz |
Add a -force_key_frames option to ffmpeg.
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
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | doc/ffmpeg-doc.texi | 6 | ||||
-rw-r--r-- | ffmpeg.c | 41 |
3 files changed, 48 insertions, 0 deletions
@@ -48,6 +48,7 @@ version <next>: - cropdetect filter - ffmpeg -crop* options removed - transpose filter added +- ffmpeg -force_key_frames option added version 0.6: diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi index 875edde03c..21a9a662dd 100644 --- a/doc/ffmpeg-doc.texi +++ b/doc/ffmpeg-doc.texi @@ -495,6 +495,12 @@ Bitstream filters available are "dump_extra", "remove_extra", "noise", "h264_mp4 @example ffmpeg -i h264.mp4 -vcodec copy -vbsf h264_mp4toannexb -an out.h264 @end example +@item -force_key_frames @var{time}[,@var{time}...] +Force key frames at the specified timestamps, more precisely at the first +frames after each specified time. +This option can be useful to ensure that a seek point is present at a +chapter mark or any other designated place in the output file. +The timestamps must be specified in ascending order. @end table @section Audio Options @@ -225,6 +225,7 @@ static int nb_frames_drop = 0; static int input_sync; static uint64_t limit_filesize = 0; static int force_fps = 0; +static char *forced_key_frames = NULL; static int pgmyuv_compatibility_hack=0; static float dts_delta_threshold = 10; @@ -272,6 +273,11 @@ typedef struct AVOutputStream { int original_height; int original_width; + /* forced key frames */ + int64_t *forced_kf_pts; + int forced_kf_count; + int forced_kf_index; + /* audio only */ int audio_resample; ReSampleContext *resample; /* for audio resampling */ @@ -1189,6 +1195,11 @@ static void do_video_out(AVFormatContext *s, big_picture.pts= ost->sync_opts; // big_picture.pts= av_rescale(ost->sync_opts, AV_TIME_BASE*(int64_t)enc->time_base.num, enc->time_base.den); //av_log(NULL, AV_LOG_DEBUG, "%"PRId64" -> encoder\n", ost->sync_opts); + if (ost->forced_kf_index < ost->forced_kf_count && + big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) { + big_picture.pict_type = FF_I_TYPE; + ost->forced_kf_index++; + } ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, &big_picture); @@ -1837,6 +1848,29 @@ static int copy_chapters(int infile, int outfile) return 0; } +static void parse_forced_key_frames(char *kf, AVOutputStream *ost, + AVCodecContext *avctx) +{ + char *p; + int n = 1, i; + int64_t t; + + for (p = kf; *p; p++) + if (*p == ',') + n++; + ost->forced_kf_count = n; + ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n); + if (!ost->forced_kf_pts) { + av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); + ffmpeg_exit(1); + } + for (i = 0; i < n; i++) { + p = i ? strchr(p, ',') + 1 : kf; + t = parse_time_or_die("force_key_frames", p, 1); + ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base); + } +} + /* * The following code is the main loop of the file converter */ @@ -2578,6 +2612,7 @@ static int transcode(AVFormatContext **output_files, av_fifo_free(ost->fifo); /* works even if fifo is not initialized but set to zero */ av_free(ost->pict_tmp.data[0]); + av_free(ost->forced_kf_pts); if (ost->video_resample) sws_freeContext(ost->img_resample_ctx); if (ost->resample) @@ -3333,6 +3368,9 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) video_enc->flags |= CODEC_FLAG_PASS2; } } + + if (forced_key_frames) + parse_forced_key_frames(forced_key_frames, ost, video_enc); } if (video_language) { av_metadata_set2(&st->metadata, "language", video_language, 0); @@ -3342,6 +3380,7 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) /* reset some key parameters */ video_disable = 0; av_freep(&video_codec_name); + av_freep(&forced_key_frames); video_stream_copy = 0; frame_pix_fmt = PIX_FMT_NONE; } @@ -3644,6 +3683,7 @@ static void opt_output_file(const char *filename) set_context_opts(oc, avformat_opts, AV_OPT_FLAG_ENCODING_PARAM, NULL); nb_streamid_map = 0; + av_freep(&forced_key_frames); } /* same option as mencoder */ @@ -4094,6 +4134,7 @@ static const OptionDef options[] = { { "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" }, { "force_fps", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&force_fps}, "force the selected framerate, disable the best supported framerate selection" }, { "streamid", OPT_FUNC2 | HAS_ARG | OPT_EXPERT, {(void*)opt_streamid}, "set the value of an outfile streamid", "streamIndex:value" }, + { "force_key_frames", OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void *)&forced_key_frames}, "force key frames at specified timestamps", "timestamps" }, /* audio options */ { "ab", OPT_FUNC2 | HAS_ARG | OPT_AUDIO, {(void*)opt_bitrate}, "set bitrate (in bits/s)", "bitrate" }, |