From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id B0986485EA for ; Mon, 11 Dec 2023 15:07:58 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1F63A68D195; Mon, 11 Dec 2023 17:07:37 +0200 (EET) Received: from shout01.mail.de (shout01.mail.de [62.201.172.24]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 65A4D68D129 for ; Mon, 11 Dec 2023 17:07:28 +0200 (EET) Received: from postfix03.mail.de (postfix03.bt.mail.de [10.0.121.127]) by shout01.mail.de (Postfix) with ESMTP id 0ED74240E26 for ; Mon, 11 Dec 2023 16:07:28 +0100 (CET) Received: from smtp01.mail.de (smtp02.bt.mail.de [10.0.121.212]) by postfix03.mail.de (Postfix) with ESMTP id E00CB80171 for ; Mon, 11 Dec 2023 16:07:27 +0100 (CET) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp01.mail.de (Postfix) with ESMTPSA id A8822240CCF for ; Mon, 11 Dec 2023 16:07:27 +0100 (CET) To: ffmpeg-devel@ffmpeg.org Date: Mon, 11 Dec 2023 16:07:22 +0100 Message-Id: <20231211150725.46473-3-thilo.borgmann@mail.de> In-Reply-To: <20231211150725.46473-1-thilo.borgmann@mail.de> References: <20231211150725.46473-1-thilo.borgmann@mail.de> MIME-Version: 1.0 X-purgate: clean X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate-type: clean X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-purgate-size: 18386 X-purgate-ID: 154282::1702307247-9252C878-5F7EE840/0/0 Subject: [FFmpeg-devel] [PATCH 2/5] fftools/ffmpeg: move parsing of -stats_* specifiers to lavu/parseutils 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: , From: Thilo Borgmann via ffmpeg-devel Reply-To: FFmpeg development discussions and patches Cc: Thilo Borgmann Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: --- fftools/ffmpeg.h | 31 +------ fftools/ffmpeg_enc.c | 3 +- fftools/ffmpeg_mux_init.c | 152 +++----------------------------- libavutil/parseutils.c | 176 ++++++++++++++++++++++++++++++++++++++ libavutil/parseutils.h | 102 ++++++++++++++++++++++ libavutil/version.h | 2 +- 6 files changed, 296 insertions(+), 170 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 1f11a2f002..cb4d90c7b2 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -42,6 +42,7 @@ #include "libavutil/eval.h" #include "libavutil/fifo.h" #include "libavutil/hwcontext.h" +#include "libavutil/parseutils.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" #include "libavutil/thread.h" @@ -437,36 +438,8 @@ enum forced_keyframes_const { #define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0) #define ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM (1 << 1) -enum EncStatsType { - ENC_STATS_LITERAL = 0, - ENC_STATS_FILE_IDX, - ENC_STATS_STREAM_IDX, - ENC_STATS_FRAME_NUM, - ENC_STATS_FRAME_NUM_IN, - ENC_STATS_TIMEBASE, - ENC_STATS_TIMEBASE_IN, - ENC_STATS_PTS, - ENC_STATS_PTS_TIME, - ENC_STATS_PTS_IN, - ENC_STATS_PTS_TIME_IN, - ENC_STATS_DTS, - ENC_STATS_DTS_TIME, - ENC_STATS_SAMPLE_NUM, - ENC_STATS_NB_SAMPLES, - ENC_STATS_PKT_SIZE, - ENC_STATS_BITRATE, - ENC_STATS_AVG_BITRATE, -}; - -typedef struct EncStatsComponent { - enum EncStatsType type; - - uint8_t *str; - size_t str_len; -} EncStatsComponent; - typedef struct EncStats { - EncStatsComponent *components; + AVEncStatsComponent *components; int nb_components; AVIOContext *io; diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c index fa4539664f..a499bc0c81 100644 --- a/fftools/ffmpeg_enc.c +++ b/fftools/ffmpeg_enc.c @@ -30,6 +30,7 @@ #include "libavutil/frame.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/timestamp.h" @@ -499,7 +500,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es, } for (size_t i = 0; i < es->nb_components; i++) { - const EncStatsComponent *c = &es->components[i]; + const AVEncStatsComponent *c = &es->components[i]; switch (c->type) { case ENC_STATS_LITERAL: avio_write (io, c->str, c->str_len); continue; diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 6c473a8f09..6acdf92c2c 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -242,152 +242,26 @@ void of_enc_stats_close(void) nb_enc_stats_files = 0; } -static int unescape(char **pdst, size_t *dst_len, - const char **pstr, char delim) -{ - const char *str = *pstr; - char *dst; - size_t len, idx; - - *pdst = NULL; - - len = strlen(str); - if (!len) - return 0; - - dst = av_malloc(len + 1); - if (!dst) - return AVERROR(ENOMEM); - - for (idx = 0; *str; idx++, str++) { - if (str[0] == '\\' && str[1]) - str++; - else if (*str == delim) - break; - - dst[idx] = *str; - } - if (!idx) { - av_freep(&dst); - return 0; - } - - dst[idx] = 0; - - *pdst = dst; - *dst_len = idx; - *pstr = str; - - return 0; -} - static int enc_stats_init(OutputStream *ost, EncStats *es, int pre, const char *path, const char *fmt_spec) { - static const struct { - enum EncStatsType type; - const char *str; - int pre_only:1; - int post_only:1; - int need_input_data:1; - } fmt_specs[] = { - { ENC_STATS_FILE_IDX, "fidx" }, - { ENC_STATS_STREAM_IDX, "sidx" }, - { ENC_STATS_FRAME_NUM, "n" }, - { ENC_STATS_FRAME_NUM_IN, "ni", 0, 0, 1 }, - { ENC_STATS_TIMEBASE, "tb" }, - { ENC_STATS_TIMEBASE_IN, "tbi", 0, 0, 1 }, - { ENC_STATS_PTS, "pts" }, - { ENC_STATS_PTS_TIME, "t" }, - { ENC_STATS_PTS_IN, "ptsi", 0, 0, 1 }, - { ENC_STATS_PTS_TIME_IN, "ti", 0, 0, 1 }, - { ENC_STATS_DTS, "dts", 0, 1 }, - { ENC_STATS_DTS_TIME, "dt", 0, 1 }, - { ENC_STATS_SAMPLE_NUM, "sn", 1 }, - { ENC_STATS_NB_SAMPLES, "samp", 1 }, - { ENC_STATS_PKT_SIZE, "size", 0, 1 }, - { ENC_STATS_BITRATE, "br", 0, 1 }, - { ENC_STATS_AVG_BITRATE, "abr", 0, 1 }, - }; - const char *next = fmt_spec; - int ret; - while (*next) { - EncStatsComponent *c; - char *val; - size_t val_len; - - // get the sequence up until next opening brace - ret = unescape(&val, &val_len, &next, '{'); - if (ret < 0) - return ret; - - if (val) { - ret = GROW_ARRAY(es->components, es->nb_components); - if (ret < 0) { - av_freep(&val); - return ret; - } - - c = &es->components[es->nb_components - 1]; - c->type = ENC_STATS_LITERAL; - c->str = val; - c->str_len = val_len; - } - - if (!*next) - break; - next++; - - // get the part inside braces - ret = unescape(&val, &val_len, &next, '}'); - if (ret < 0) - return ret; - - if (!val) { - av_log(NULL, AV_LOG_ERROR, - "Empty formatting directive in: %s\n", fmt_spec); - return AVERROR(EINVAL); - } - - if (!*next) { - av_log(NULL, AV_LOG_ERROR, - "Missing closing brace in: %s\n", fmt_spec); - ret = AVERROR(EINVAL); - goto fail; - } - next++; - - ret = GROW_ARRAY(es->components, es->nb_components); - if (ret < 0) - goto fail; - - c = &es->components[es->nb_components - 1]; - - for (size_t i = 0; i < FF_ARRAY_ELEMS(fmt_specs); i++) { - if (!strcmp(val, fmt_specs[i].str)) { - c->type = fmt_specs[i].type; - c->str = val; - c->str_len = val_len; - break; - } - } - - if (!c->type) { - av_log(NULL, AV_LOG_ERROR, "Invalid format directive: %s\n", val); - ret = AVERROR(EINVAL); - goto fail; - } - } + ret = av_parse_enc_stats_components(&es->components, &es->nb_components, fmt_spec); + if (ret < 0) + goto fail; for (int j = 0; j < es->nb_components; j++) { - EncStatsComponent *c = &es->components[j]; + AVEncStatsComponent *c = &es->components[j]; char *val = c->str; - for (size_t i = 0; i < FF_ARRAY_ELEMS(fmt_specs); i++) { - if (!strcmp(val, fmt_specs[i].str)) { - if ((pre && fmt_specs[i].post_only) || (!pre && fmt_specs[i].pre_only)) { + for (size_t i = 0; i < av_get_nb_stats_fmt_specs(); i++) { + AVEncStatsFormatSpecifier f; + if (av_get_stats_fmt_spec(&f, i)) + goto fail; + + if (!strcmp(val, f.str)) { + if ((pre && f.post_only) || (!pre && f.pre_only)) { av_log(NULL, AV_LOG_ERROR, "Format directive '%s' may only be used %s-encoding\n", val, pre ? "post" : "pre"); @@ -395,7 +269,7 @@ static int enc_stats_init(OutputStream *ost, EncStats *es, int pre, goto fail; } - if (fmt_specs[i].need_input_data && !ost->ist) { + if (f.need_input_data && !ost->ist) { av_log(ost, AV_LOG_WARNING, "Format directive '%s' is unavailable, because " "this output stream has no associated input stream\n", @@ -410,7 +284,7 @@ static int enc_stats_init(OutputStream *ost, EncStats *es, int pre, ret = enc_stats_get_file(&es->io, path); fail: for (int j = 0; j < es->nb_components; j++) { - EncStatsComponent *c = &es->components[j]; + AVEncStatsComponent *c = &es->components[j]; if (c->type != ENC_STATS_LITERAL) { av_freep(&c->str); } diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c index 94e88e0a79..796811aa6e 100644 --- a/libavutil/parseutils.c +++ b/libavutil/parseutils.c @@ -788,3 +788,179 @@ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info } return 0; } + +static const AVEncStatsFormatSpecifier fmt_specs[] = { + { ENC_STATS_FILE_IDX, "fidx" }, + { ENC_STATS_STREAM_IDX, "sidx" }, + { ENC_STATS_FRAME_NUM, "n" }, + { ENC_STATS_FRAME_NUM_IN, "ni", 0, 0, 1 }, + { ENC_STATS_TIMEBASE, "tb" }, + { ENC_STATS_TIMEBASE_IN, "tbi", 0, 0, 1 }, + { ENC_STATS_PTS, "pts" }, + { ENC_STATS_PTS_TIME, "t" }, + { ENC_STATS_PTS_IN, "ptsi", 0, 0, 1 }, + { ENC_STATS_PTS_TIME_IN, "ti", 0, 0, 1 }, + { ENC_STATS_DTS, "dts", 0, 1 }, + { ENC_STATS_DTS_TIME, "dt", 0, 1 }, + { ENC_STATS_SAMPLE_NUM, "sn", 1 }, + { ENC_STATS_NB_SAMPLES, "samp", 1 }, + { ENC_STATS_PKT_SIZE, "size", 0, 1 }, + { ENC_STATS_BITRATE, "br", 0, 1 }, + { ENC_STATS_AVG_BITRATE, "abr", 0, 1 }, +}; + +size_t av_get_nb_stats_fmt_specs(void) +{ + return sizeof(fmt_specs) / sizeof(*fmt_specs); +} + +int av_get_stats_fmt_spec(AVEncStatsFormatSpecifier *fmt_spec, int idx) +{ + if (!fmt_spec || idx >= av_get_nb_stats_fmt_specs()) + return AVERROR(EINVAL); + + *fmt_spec = fmt_specs[idx]; + return 0; +} + +static int unescape(char **pdst, size_t *dst_len, + const char **pstr, char delim) +{ + const char *str = *pstr; + char *dst; + size_t len, idx; + + *pdst = NULL; + + len = strlen(str); + if (!len) + return 0; + + dst = av_malloc(len + 1); + if (!dst) + return AVERROR(ENOMEM); + + for (idx = 0; *str; idx++, str++) { + if (str[0] == '\\' && str[1]) + str++; + else if (*str == delim) + break; + + dst[idx] = *str; + } + if (!idx) { + av_freep(&dst); + return 0; + } + + dst[idx] = 0; + + *pdst = dst; + *dst_len = idx; + *pstr = str; + + return 0; +} + +static int grow_array(void **array, int elem_size, int *size, int new_size) +{ + if (new_size >= INT_MAX / elem_size) { + av_log(NULL, AV_LOG_ERROR, "Array too big.\n"); + return AVERROR(ERANGE); + } + if (*size < new_size) { + uint8_t *tmp = av_realloc_array(*array, new_size, elem_size); + if (!tmp) + return AVERROR(ENOMEM); + memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size); + *size = new_size; + *array = tmp; + return 0; + } + return 0; +} + +#define GROW_ARRAY(array, nb_elems)\ + grow_array((void**)&array, sizeof(*array), &nb_elems, nb_elems + 1) + +int av_parse_enc_stats_components(AVEncStatsComponent **components, int *nb_components, const char *fmt_spec) +{ + const char *next = fmt_spec; + int ret; + + while (*next) { + AVEncStatsComponent *c; + char *val; + size_t val_len; + + // get the sequence up until next opening brace + ret = unescape(&val, &val_len, &next, '{'); + if (ret < 0) + return ret; + + if (val) { + ret = GROW_ARRAY(*components, *nb_components); + if (ret < 0) { + av_freep(&val); + return ret; + } + + c = &((*components)[*nb_components - 1]); + c->type = ENC_STATS_LITERAL; + c->str = val; + c->str_len = val_len; + } + + if (!*next) + break; + next++; + + // get the part inside braces + ret = unescape(&val, &val_len, &next, '}'); + if (ret < 0) + return ret; + + if (!val) { + av_log(NULL, AV_LOG_ERROR, + "Empty formatting directive in: %s\n", fmt_spec); + return AVERROR(EINVAL); + } + + if (!*next) { + av_log(NULL, AV_LOG_ERROR, + "Missing closing brace in: %s\n", fmt_spec); + ret = AVERROR(EINVAL); + goto fail; + } + next++; + + ret = GROW_ARRAY(*components, *nb_components); + if (ret < 0) + goto fail; + + c = &(*components)[*nb_components - 1]; + + for (int i = 0; i < FF_ARRAY_ELEMS(fmt_specs); i++) { + if (!strcmp(val, fmt_specs[i].str)) { + c->type = fmt_specs[i].type; + c->str = val; + c->str_len = val_len; + break; + } + } + + if (!c->type) { + av_log(NULL, AV_LOG_ERROR, "Invalid format directive: %s\n", val); + ret = AVERROR(EINVAL); + goto fail; + } + + continue; +fail: + av_freep(&val); + if (ret < 0) + return ret; + } + + return 0; +} diff --git a/libavutil/parseutils.h b/libavutil/parseutils.h index dad5c2775b..d546d77de0 100644 --- a/libavutil/parseutils.h +++ b/libavutil/parseutils.h @@ -22,6 +22,7 @@ #include #include "rational.h" +#include "mem.h" /** * @file @@ -194,4 +195,105 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); */ time_t av_timegm(struct tm *tm); +typedef enum AVEncStatsType { + ENC_STATS_LITERAL = 0, + ENC_STATS_FILE_IDX, + ENC_STATS_STREAM_IDX, + ENC_STATS_FRAME_NUM, + ENC_STATS_FRAME_NUM_IN, + ENC_STATS_TIMEBASE, + ENC_STATS_TIMEBASE_IN, + ENC_STATS_PTS, + ENC_STATS_PTS_TIME, + ENC_STATS_PTS_IN, + ENC_STATS_PTS_TIME_IN, + ENC_STATS_DTS, + ENC_STATS_DTS_TIME, + ENC_STATS_SAMPLE_NUM, + ENC_STATS_NB_SAMPLES, + ENC_STATS_PKT_SIZE, + ENC_STATS_BITRATE, + ENC_STATS_AVG_BITRATE, +} AVEncStatsType; + +/** + * Structure describing an encoding stats component. + */ +typedef struct AVEncStatsComponent { + /** + * The type of this component. + */ + AVEncStatsType type; + /** + * The string representation of this component. + */ + uint8_t *str; + /** + * The length of the string. + */ + size_t str_len; +} AVEncStatsComponent; + +/** + * Structure describing an encoding stats format specifier. + */ +typedef struct AVEncStatsFormatSpecifier { + /** + * The type of this format specifier. + */ + enum AVEncStatsType type; + /** + * The string representation of this format specifier. + */ + const char *str; + /** + * Flag if this format specifier is only valid before encoding. + */ + int pre_only:1; + /** + * Flag if this format specifier is only valid after encoding. + */ + int post_only:1; + /** + * Flag if this format specifier requires an associated input + * stream for it to be processed. + */ + int need_input_data:1; +} AVEncStatsFormatSpecifier; + +/** + * Get the number of available enc stats format specifiers. + */ +size_t av_get_nb_stats_fmt_specs(void); + +/** + * Get a copy of an enc stats format specifier. + * + * @param *fmt_spec Destination for the copy of the format specifier. + * Has to be previously allocated. + * + * @param idx Index to the table of format specifiers. + * + * @return Return 0 on success, a negative value corresponding + * to an AVERROR code otherwise. + */ +int av_get_stats_fmt_spec(AVEncStatsFormatSpecifier *fmt_spec, int idx); + +/** + * Parse an enc stats format string into an array of AVEncStatsComponent. + * + * @param components Pointer to the array of AVEncStatsComponent to store + * the parsed elements. The arrary will be reallocated + * in the process if any elements are found. + * + * @param nb_components Pointer to the number of components in the array. + * + * @param fmt_spec The format string to parse for components. + * + * @return Return 0 on success, a negative value corresponding + * to an AVERROR code otherwise. + * + */ +int av_parse_enc_stats_components(AVEncStatsComponent **components, int *nb_components, const char *fmt_spec); + #endif /* AVUTIL_PARSEUTILS_H */ diff --git a/libavutil/version.h b/libavutil/version.h index c5fa7c3692..0684996bf2 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 58 -#define LIBAVUTIL_VERSION_MINOR 32 +#define LIBAVUTIL_VERSION_MINOR 33 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ -- 2.37.1 (Apple Git-137.1) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".