1
mirror of https://git.videolan.org/git/ffmpeg.git synced 2024-10-06 02:05:36 +02:00

ffmpeg: accept "chapters" as forced key frames.

Allow to force a key frame at the beginning of each chapter.
This commit is contained in:
Nicolas George 2013-01-02 19:08:08 +01:00
parent 9381521968
commit beb5d8f07d
2 changed files with 54 additions and 8 deletions

View File

@ -555,9 +555,17 @@ Deprecated see -bsf
@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream}) @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 Force key frames at the specified timestamps, more precisely at the first
frames after each specified time. 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 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. 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}) @item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
When doing stream copy, copy also non-key frames found at the When doing stream copy, copy also non-key frames found at the

View File

@ -1931,19 +1931,25 @@ static InputStream *get_input_stream(OutputStream *ost)
return NULL; 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, static void parse_forced_key_frames(char *kf, OutputStream *ost,
AVCodecContext *avctx) AVCodecContext *avctx)
{ {
char *p; char *p;
int n = 1, i; int n = 1, i, size, index = 0;
int64_t t; int64_t t, *pts;
for (p = kf; *p; p++) for (p = kf; *p; p++)
if (*p == ',') if (*p == ',')
n++; n++;
ost->forced_kf_count = n; size = n;
ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n); pts = av_malloc(sizeof(*pts) * size);
if (!ost->forced_kf_pts) { if (!pts) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
exit(1); exit(1);
} }
@ -1955,11 +1961,43 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
if (next) if (next)
*next++ = 0; *next++ = 0;
t = parse_time_or_die("force_key_frames", p, 1); if (!memcmp(p, "chapters", 8)) {
ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
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; 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) static void report_new_stream(int input_index, AVPacket *pkt)