summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2022-11-17 14:22:58 +0100
committerAnton Khirnov <anton@khirnov.net>2022-11-28 10:28:14 +0100
commit334e52e09441213c9c391d7c0f5d0126eaa98396 (patch)
tree84bb74048a2e4c801404ee5b3f966a8be11db575
parentefe442362794abe3cef43eea6b4071919b0b2866 (diff)
fftools/ffmpeg: parse forced keyframes in of_open()
Allows to remove the ugly of_get_chapters() wrapper.
-rw-r--r--fftools/ffmpeg.c89
-rw-r--r--fftools/ffmpeg.h2
-rw-r--r--fftools/ffmpeg_mux.c8
-rw-r--r--fftools/ffmpeg_mux_init.c106
4 files changed, 106 insertions, 99 deletions
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 5d39d8f69b..12ce108cc6 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -113,15 +113,6 @@ const int program_birth_year = 2000;
static FILE *vstats_file;
-const char *const forced_keyframes_const_names[] = {
- "n",
- "n_forced",
- "prev_forced_n",
- "prev_forced_t",
- "t",
- NULL
-};
-
typedef struct BenchmarkTimeStamps {
int64_t real_usec;
int64_t user_usec;
@@ -2590,11 +2581,6 @@ static int init_input_stream(InputStream *ist, char *error, int error_len)
return 0;
}
-static int compare_int64(const void *a, const void *b)
-{
- return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
-}
-
static int init_output_stream_streamcopy(OutputStream *ost)
{
OutputFile *of = output_files[ost->file_index];
@@ -2748,61 +2734,6 @@ static void set_encoder_id(OutputFile *of, OutputStream *ost)
AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
}
-static void parse_forced_key_frames(KeyframeForceCtx *kf, OutputFile *of)
-{
- const char *p;
- int n = 1, i, size, index = 0;
- int64_t t, *pts;
-
- for (p = kf->forced_keyframes; *p; p++)
- if (*p == ',')
- n++;
- size = n;
- pts = av_malloc_array(size, sizeof(*pts));
- if (!pts)
- report_and_exit(AVERROR(ENOMEM));
-
- p = kf->forced_keyframes;
- for (i = 0; i < n; i++) {
- char *next = strchr(p, ',');
-
- if (next)
- *next++ = 0;
-
- if (!memcmp(p, "chapters", 8)) {
- AVChapter * const *ch;
- unsigned int nb_ch;
- int j;
-
- ch = of_get_chapters(of, &nb_ch);
-
- if (nb_ch > INT_MAX - size ||
- !(pts = av_realloc_f(pts, size += nb_ch - 1,
- sizeof(*pts))))
- report_and_exit(AVERROR(ENOMEM));
- t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
-
- for (j = 0; j < nb_ch; j++) {
- const AVChapter *c = ch[j];
- av_assert1(index < size);
- pts[index++] = av_rescale_q(c->start, c->time_base,
- AV_TIME_BASE_Q) + t;
- }
-
- } else {
- av_assert1(index < size);
- pts[index++] = parse_time_or_die("force_key_frames", p, 1);
- }
-
- p = next;
- }
-
- av_assert0(index == size);
- qsort(pts, size, sizeof(*pts), compare_int64);
- kf->nb_pts = size;
- kf->pts = pts;
-}
-
static void init_encoder_time_base(OutputStream *ost, AVRational default_time_base)
{
InputStream *ist = ost->ist;
@@ -2949,26 +2880,6 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame)
enc_ctx->field_order = AV_FIELD_TT;
}
- if (ost->kf.forced_keyframes) {
- if (!strncmp(ost->kf.forced_keyframes, "expr:", 5)) {
- ret = av_expr_parse(&ost->kf.pexpr, ost->kf.forced_keyframes+5,
- forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR,
- "Invalid force_key_frames expression '%s'\n", ost->kf.forced_keyframes+5);
- return ret;
- }
- ost->kf.expr_const_values[FKF_N] = 0;
- ost->kf.expr_const_values[FKF_N_FORCED] = 0;
- ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN;
- ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN;
-
- // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
- // parse it only for static kf timings
- } else if(strncmp(ost->kf.forced_keyframes, "source", 6)) {
- parse_forced_key_frames(&ost->kf, of);
- }
- }
break;
case AVMEDIA_TYPE_SUBTITLE:
enc_ctx->time_base = AV_TIME_BASE_Q;
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index f5d51b90ec..bf2abf55ee 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -757,8 +757,6 @@ void of_close(OutputFile **pof);
*/
void of_output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof);
int64_t of_filesize(OutputFile *of);
-AVChapter * const *
-of_get_chapters(OutputFile *of, unsigned int *nb_chapters);
int ifile_open(const OptionsContext *o, const char *filename);
void ifile_close(InputFile **f);
diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index 7da29db8f4..de5facbdc0 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -736,11 +736,3 @@ int64_t of_filesize(OutputFile *of)
Muxer *mux = mux_from_of(of);
return atomic_load(&mux->last_filesize);
}
-
-AVChapter * const *
-of_get_chapters(OutputFile *of, unsigned int *nb_chapters)
-{
- Muxer *mux = mux_from_of(of);
- *nb_chapters = mux->fc->nb_chapters;
- return mux->fc->chapters;
-}
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index bdec0744a9..25e2ab8631 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -1745,6 +1745,104 @@ finish:
return ret;
}
+const char *const forced_keyframes_const_names[] = {
+ "n",
+ "n_forced",
+ "prev_forced_n",
+ "prev_forced_t",
+ "t",
+ NULL
+};
+
+static int compare_int64(const void *a, const void *b)
+{
+ return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
+}
+
+static void parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux)
+{
+ const char *p;
+ int n = 1, i, size, index = 0;
+ int64_t t, *pts;
+
+ for (p = kf->forced_keyframes; *p; p++)
+ if (*p == ',')
+ n++;
+ size = n;
+ pts = av_malloc_array(size, sizeof(*pts));
+ if (!pts)
+ report_and_exit(AVERROR(ENOMEM));
+
+ p = kf->forced_keyframes;
+ for (i = 0; i < n; i++) {
+ char *next = strchr(p, ',');
+
+ if (next)
+ *next++ = 0;
+
+ if (!memcmp(p, "chapters", 8)) {
+ AVChapter * const *ch = mux->fc->chapters;
+ unsigned int nb_ch = mux->fc->nb_chapters;
+ int j;
+
+ if (nb_ch > INT_MAX - size ||
+ !(pts = av_realloc_f(pts, size += nb_ch - 1,
+ sizeof(*pts))))
+ report_and_exit(AVERROR(ENOMEM));
+ t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
+
+ for (j = 0; j < nb_ch; j++) {
+ const AVChapter *c = ch[j];
+ av_assert1(index < size);
+ pts[index++] = av_rescale_q(c->start, c->time_base,
+ AV_TIME_BASE_Q) + t;
+ }
+
+ } else {
+ av_assert1(index < size);
+ pts[index++] = parse_time_or_die("force_key_frames", p, 1);
+ }
+
+ p = next;
+ }
+
+ av_assert0(index == size);
+ qsort(pts, size, sizeof(*pts), compare_int64);
+ kf->nb_pts = size;
+ kf->pts = pts;
+}
+
+static int process_forced_keyframes(Muxer *mux)
+{
+ for (int i = 0; i < mux->of.nb_streams; i++) {
+ OutputStream *ost = mux->of.streams[i];
+
+ if (!ost->kf.forced_keyframes)
+ continue;
+
+ if (!strncmp(ost->kf.forced_keyframes, "expr:", 5)) {
+ int ret = av_expr_parse(&ost->kf.pexpr, ost->kf.forced_keyframes+5,
+ forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid force_key_frames expression '%s'\n", ost->kf.forced_keyframes+5);
+ return ret;
+ }
+ ost->kf.expr_const_values[FKF_N] = 0;
+ ost->kf.expr_const_values[FKF_N_FORCED] = 0;
+ ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN;
+ ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN;
+
+ // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
+ // parse it only for static kf timings
+ } else if (strncmp(ost->kf.forced_keyframes, "source", 6)) {
+ parse_forced_key_frames(&ost->kf, mux);
+ }
+ }
+
+ return 0;
+}
+
static void validate_enc_avopt(const Muxer *mux, const AVDictionary *codec_avopt)
{
const AVClass *class = avcodec_get_class();
@@ -1961,6 +2059,14 @@ int of_open(const OptionsContext *o, const char *filename)
exit_program(1);
}
+ // parse forced keyframe specifications;
+ // must be done after chapters are created
+ err = process_forced_keyframes(mux);
+ if (err < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error processing forced keyframes\n");
+ exit_program(1);
+ }
+
err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE);
if (err < 0) {
av_log(NULL, AV_LOG_FATAL, "Error setting up output sync queues\n");