diff options
author | Anton Khirnov <anton@khirnov.net> | 2022-11-17 14:22:58 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2022-11-28 10:28:14 +0100 |
commit | 334e52e09441213c9c391d7c0f5d0126eaa98396 (patch) | |
tree | 84bb74048a2e4c801404ee5b3f966a8be11db575 | |
parent | efe442362794abe3cef43eea6b4071919b0b2866 (diff) |
fftools/ffmpeg: parse forced keyframes in of_open()
Allows to remove the ugly of_get_chapters() wrapper.
-rw-r--r-- | fftools/ffmpeg.c | 89 | ||||
-rw-r--r-- | fftools/ffmpeg.h | 2 | ||||
-rw-r--r-- | fftools/ffmpeg_mux.c | 8 | ||||
-rw-r--r-- | fftools/ffmpeg_mux_init.c | 106 |
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"); |