From patchwork Sat Nov 26 08:19:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 39456 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:999a:b0:a4:2148:650a with SMTP id ve26csp6013330pzb; Sat, 26 Nov 2022 00:20:32 -0800 (PST) X-Google-Smtp-Source: AA0mqf6jfKWtk9VX5XjLaOsE6fRaKaH2gGI6NpD97vaaTqEr2rVb/q6hycyO7XQ1kqcqXrHoIYGp X-Received: by 2002:a05:6402:1118:b0:467:a8cb:10c9 with SMTP id u24-20020a056402111800b00467a8cb10c9mr24495955edv.123.1669450831820; Sat, 26 Nov 2022 00:20:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669450831; cv=none; d=google.com; s=arc-20160816; b=fMuA1naOkYhD90pmrNc0WLxgYG+Yv17BHJ0mzflYhaQSNOisHbLsvYGS1mJjwosQ6o S8joz+ECDcD+i2CwkEP0LBwmfTOiPb6mp9vqAcZuTVoMCyN97giWKuQxt8kiMY4R/6Tj qaamq56c1W95aYjwKKP8PkV23LIyDSoeO4KUH4/Y0Lq/DggX2DwrFRse9cfHAJ3Z6TkC 96YJ9aZV+pb/CQUlkzzga09plGqRVS3Oggz7/V4Z+26mK5KCV3HktVZ1lQEk6pAFS40/ G4tZ6DPefbL0fJ9TmufAP9QWkhkXSH0RwawVleNDtIXoTr1FCAjAbShYWtdNyiJVgMnq wf3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:delivered-to; bh=a4c0JLJJRpb7LGD2IdG1SNQNAwXJ0VjfvhCDdFp8DNU=; b=Dh1JzsSL7lqjj2/iOMk7SVpVkiuMxOKayEbyul37xB8NDiTliSJG9oB7R/PVOESQvk im+GqNUwIJ9494xb/uhw8WmD5ib0w//LmsFhspNqv5hDM0eyiLIlZCjdlq22MI1CqfaL Xy/+ZcqOyw8bXfp0WP0/r8+wo+SRO4ABkPxmgXmqrt5tvw+UiWP+JoVu1iEAzcfCTKVi +WXnYZmcUvcNgpTcjyajaDseN+S3cyb59BGElL1vMJvmOiZyyoQLhCyciNj+YtzDCjFz iTx5cM27J0bX8F8dzOR+DhHtJTsQE7pteL221tGNqjchrmrKoqS3EYZYRb8+dM3/1cVF Ji4Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id nd39-20020a17090762a700b0078dce2b1985si5762808ejc.134.2022.11.26.00.20.31; Sat, 26 Nov 2022 00:20:31 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4016C68B929; Sat, 26 Nov 2022 10:19:37 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E3F8668A929 for ; Sat, 26 Nov 2022 10:19:29 +0200 (EET) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id DB2DF2405EC for ; Sat, 26 Nov 2022 09:19:25 +0100 (CET) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id 6r8khqjEor27 for ; Sat, 26 Nov 2022 09:19:25 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:2a00:c500:561:201::7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "libav.khirnov.net", Issuer "smtp.khirnov.net SMTP CA" (verified OK)) by mail0.khirnov.net (Postfix) with ESMTPS id 9D2D5240591 for ; Sat, 26 Nov 2022 09:19:23 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 6DB223A066C for ; Sat, 26 Nov 2022 09:19:23 +0100 (CET) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Sat, 26 Nov 2022 09:19:02 +0100 Message-Id: <20221126081911.31275-4-anton@khirnov.net> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221126081911.31275-1-anton@khirnov.net> References: <20221126081911.31275-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 04/13] fftools/ffmpeg: parse forced keyframes in of_open() X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: oWw083Ei7xuS Allows to remove the ugly of_get_chapters() wrapper. --- fftools/ffmpeg.c | 89 -------------------------------- fftools/ffmpeg.h | 2 - fftools/ffmpeg_mux.c | 8 --- 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");