diff options
author | Nicolas George <nicolas.george@normalesup.org> | 2013-01-02 19:08:08 +0100 |
---|---|---|
committer | Nicolas George <nicolas.george@normalesup.org> | 2013-01-19 15:22:34 +0100 |
commit | beb5d8f07d2aec4da88456f9e21e14d95a38f377 (patch) | |
tree | cc2b5a4b607a58622c7282180199d2bca240f40c | |
parent | 938152196871be80d2dfa6cf9728ee0873132604 (diff) | |
download | ffmpeg-beb5d8f07d2aec4da88456f9e21e14d95a38f377.tar.gz |
ffmpeg: accept "chapters" as forced key frames.
Allow to force a key frame at the beginning of each chapter.
-rw-r--r-- | doc/ffmpeg.texi | 10 | ||||
-rw-r--r-- | ffmpeg.c | 52 |
2 files changed, 54 insertions, 8 deletions
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 8a29d5e14b..5aa45629d4 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -555,9 +555,17 @@ Deprecated see -bsf @item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream}) Force key frames at the specified timestamps, more precisely at the first frames after each specified time. +If one of the times is "@code{chapters}[@var{delta}]", it is expanded into +the time of the beginning of all chapters in the file, shifted by +@var{delta}, expressed as a time in seconds. 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. + +For example, to insert a key frame at 5 minutes, plus key frames 0.1 second +before the beginning of every chapter: +@example +-force_key_frames 0:05:00,chapters-0.1 +@end example @item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream}) When doing stream copy, copy also non-key frames found at the @@ -1931,19 +1931,25 @@ static InputStream *get_input_stream(OutputStream *ost) return NULL; } +static int compare_int64(const void *a, const void *b) +{ + int64_t va = *(int64_t *)a, vb = *(int64_t *)b; + return va < vb ? -1 : va > vb ? +1 : 0; +} + static void parse_forced_key_frames(char *kf, OutputStream *ost, AVCodecContext *avctx) { char *p; - int n = 1, i; - int64_t t; + int n = 1, i, size, index = 0; + int64_t t, *pts; 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) { + size = n; + pts = av_malloc(sizeof(*pts) * size); + if (!pts) { av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); exit(1); } @@ -1955,11 +1961,43 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost, if (next) *next++ = 0; - 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); + if (!memcmp(p, "chapters", 8)) { + + AVFormatContext *avf = output_files[ost->file_index]->ctx; + int j; + + if (avf->nb_chapters > INT_MAX - size || + !(pts = av_realloc_f(pts, size += avf->nb_chapters - 1, + sizeof(*pts)))) { + av_log(NULL, AV_LOG_FATAL, + "Could not allocate forced key frames array.\n"); + exit(1); + } + t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0; + t = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base); + + for (j = 0; j < avf->nb_chapters; j++) { + AVChapter *c = avf->chapters[j]; + av_assert1(index < size); + pts[index++] = av_rescale_q(c->start, c->time_base, + avctx->time_base) + t; + } + + } else { + + t = parse_time_or_die("force_key_frames", p, 1); + av_assert1(index < size); + pts[index++] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base); + + } p = next; } + + av_assert0(index == size); + qsort(pts, size, sizeof(*pts), compare_int64); + ost->forced_kf_count = size; + ost->forced_kf_pts = pts; } static void report_new_stream(int input_index, AVPacket *pkt) |