From: Marvin Scholz <epirat07-at-gmail.com@ffmpeg.org> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH 1/2] avformat/tee: refactor option processing Date: Wed, 25 Jun 2025 00:08:04 +0200 Message-ID: <20250624220805.50371-1-epirat07@gmail.com> (raw) Instead of the convoluted nested macros, use a convenience helper function. While this makes the code slightly longer, it is now much clearer what is happening without running the file through a preprocessor first. Additionally do not mess with the internals of the dictionary, just to save two string copies. --- libavformat/tee.c | 98 +++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/libavformat/tee.c b/libavformat/tee.c index 0150ee9f22..0a6e9d0c82 100644 --- a/libavformat/tee.c +++ b/libavformat/tee.c @@ -80,8 +80,9 @@ static const AVClass tee_muxer_class = { .version = LIBAVUTIL_VERSION_INT, }; -static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave) +static inline int parse_slave_failure_policy_option(const char *opt, void *ctx) { + TeeSlave *tee_slave = ctx; if (!opt) { tee_slave->on_fail = DEFAULT_SLAVE_FAILURE_POLICY; return 0; @@ -97,8 +98,9 @@ static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *t return AVERROR(EINVAL); } -static int parse_slave_fifo_policy(const char *use_fifo, TeeSlave *tee_slave) +static int parse_slave_fifo_policy(const char *use_fifo, void *ctx) { + TeeSlave *tee_slave = ctx; /*TODO - change this to use proper function for parsing boolean * options when there is one */ if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) { @@ -111,8 +113,9 @@ static int parse_slave_fifo_policy(const char *use_fifo, TeeSlave *tee_slave) return 0; } -static int parse_slave_fifo_options(const char *fifo_options, TeeSlave *tee_slave) +static int parse_slave_fifo_options(const char *fifo_options, void *ctx) { + TeeSlave *tee_slave = ctx; return av_dict_parse_string(&tee_slave->fifo_options, fifo_options, "=", ":", 0); } @@ -152,6 +155,46 @@ static void close_slaves(AVFormatContext *avf) av_freep(&tee->slaves); } +typedef int (*OptionParserFunc)(const char *value, void *context); + +/** + * Retrieve and optionally copy or process the given dict key's value + * + * The dictionary value for \p key is retrieved, if it exists the + * value is passed to the \p handler function together with the + * \c context, if any. If the handler returns an error, it is returned + * to the caller. + * + * If \c out_value is not NULL, the value is also copied and assigned + * to that. + * + * After processing, the key is removed from the dictionary. + */ +static int dict_consume_value(AVDictionary **dict, const char *key, char **out_value, + OptionParserFunc handler, void *context) +{ + const AVDictionaryEntry *entry = av_dict_get(*dict, key, NULL, 0); + if (!entry) + return 0; + + if (handler) { + int ret = handler(entry->value, context); + if (ret < 0) + return ret; + } + + if (out_value) { + char *value_copy = av_strdup(entry->value); + if (!value_copy) + return AVERROR(ENOMEM); + + *out_value = value_copy; + } + + av_dict_set(dict, key, NULL, 0); + return 0; +} + static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) { int ret; @@ -167,35 +210,26 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) if ((ret = ff_tee_parse_slave_options(avf, slave, &options, &filename)) < 0) return ret; -#define CONSUME_OPTION(option, field, action) do { \ - AVDictionaryEntry *en = av_dict_get(options, option, NULL, 0); \ - if (en) { \ - field = en->value; \ - { action } \ - av_dict_set(&options, option, NULL, 0); \ - } \ - } while (0) -#define STEAL_OPTION(option, field) \ - CONSUME_OPTION(option, field, \ - en->value = NULL; /* prevent it from being freed */) -#define PROCESS_OPTION(option, function, on_error) do { \ - const char *value; \ - CONSUME_OPTION(option, value, if ((ret = function) < 0) \ - { { on_error } goto end; }); \ - } while (0) - - STEAL_OPTION("f", format); - STEAL_OPTION("select", select); - PROCESS_OPTION("onfail", - parse_slave_failure_policy_option(value, tee_slave), - av_log(avf, AV_LOG_ERROR, "Invalid onfail option value, " - "valid options are 'abort' and 'ignore'\n");); - PROCESS_OPTION("use_fifo", - parse_slave_fifo_policy(value, tee_slave), - av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n", - av_err2str(ret));); - PROCESS_OPTION("fifo_options", - parse_slave_fifo_options(value, tee_slave), ;); + if ((ret = dict_consume_value(&options, "f", &format, NULL, NULL)) < 0) + goto end; + if ((ret = dict_consume_value(&options, "select", &select, NULL, NULL)) < 0) + goto end; + if ((ret = dict_consume_value(&options, "onfail", NULL, + parse_slave_failure_policy_option, tee_slave)) < 0) { + av_log(avf, AV_LOG_ERROR, "Invalid onfail option value, " + "valid options are 'abort' and 'ignore'\n"); + goto end; + } + if ((ret = dict_consume_value(&options, "use_fifo", NULL, + parse_slave_fifo_policy, tee_slave)) < 0) { + av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n", + av_err2str(ret)); + goto end; + } + if ((ret = dict_consume_value(&options, "fifo_options", NULL, + parse_slave_fifo_options, tee_slave)) < 0) + goto end; + entry = NULL; while ((entry = av_dict_get(options, "bsfs", entry, AV_DICT_IGNORE_SUFFIX))) { /* trim out strlen("bsfs") characters from key */ -- 2.39.5 (Apple Git-154) _______________________________________________ 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".
next reply other threads:[~2025-06-24 22:08 UTC|newest] Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top 2025-06-24 22:08 Marvin Scholz [this message] 2025-06-24 22:08 ` [FFmpeg-devel] [PATCH 2/2] avformat/tee: fix multiple bsfs in tee Marvin Scholz
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20250624220805.50371-1-epirat07@gmail.com \ --to=epirat07-at-gmail.com@ffmpeg.org \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git