* [FFmpeg-devel] [PATCH 1/2] avformat/tee: refactor option processing
@ 2025-06-24 22:08 Marvin Scholz
2025-06-24 22:08 ` [FFmpeg-devel] [PATCH 2/2] avformat/tee: fix multiple bsfs in tee Marvin Scholz
0 siblings, 1 reply; 3+ messages in thread
From: Marvin Scholz @ 2025-06-24 22:08 UTC (permalink / raw)
To: ffmpeg-devel
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".
^ permalink raw reply [flat|nested] 3+ messages in thread
* [FFmpeg-devel] [PATCH 2/2] avformat/tee: fix multiple bsfs in tee
2025-06-24 22:08 [FFmpeg-devel] [PATCH 1/2] avformat/tee: refactor option processing Marvin Scholz
@ 2025-06-24 22:08 ` Marvin Scholz
2025-06-25 9:56 ` Nicolas George
0 siblings, 1 reply; 3+ messages in thread
From: Marvin Scholz @ 2025-06-24 22:08 UTC (permalink / raw)
To: ffmpeg-devel
Since 155508c6e925f4f2f5e77087a7e1925b3de735ff specifying multiple
bsfs for different streams was broken:
"[bsfs/a=h264_metadata:bsfs/v=h264_metadata]out.mp4|..."
This incorrectly only parsed the first bsfs specification. The reason
for this is that the dictionary is modified in the iterator, hence
invalidating the iterator. The simplest fix for this is to simply
iterate from the beginning in each loop given that the previous entry
is removed.
---
libavformat/tee.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavformat/tee.c b/libavformat/tee.c
index 0a6e9d0c82..94a8fcb395 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -231,7 +231,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
goto end;
entry = NULL;
- while ((entry = av_dict_get(options, "bsfs", entry, AV_DICT_IGNORE_SUFFIX))) {
+ while ((entry = av_dict_get(options, "bsfs", NULL, AV_DICT_IGNORE_SUFFIX))) {
/* trim out strlen("bsfs") characters from key */
av_dict_set(&bsf_options, entry->key + 4, entry->value, 0);
av_dict_set(&options, entry->key, NULL, 0);
--
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".
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/2] avformat/tee: fix multiple bsfs in tee
2025-06-24 22:08 ` [FFmpeg-devel] [PATCH 2/2] avformat/tee: fix multiple bsfs in tee Marvin Scholz
@ 2025-06-25 9:56 ` Nicolas George
0 siblings, 0 replies; 3+ messages in thread
From: Nicolas George @ 2025-06-25 9:56 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Marvin Scholz (HE12025-06-25):
> Since 155508c6e925f4f2f5e77087a7e1925b3de735ff specifying multiple
> bsfs for different streams was broken:
>
> "[bsfs/a=h264_metadata:bsfs/v=h264_metadata]out.mp4|..."
>
> This incorrectly only parsed the first bsfs specification. The reason
> for this is that the dictionary is modified in the iterator, hence
> invalidating the iterator. The simplest fix for this is to simply
> iterate from the beginning in each loop given that the previous entry
> is removed.
> ---
> libavformat/tee.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Sould be ok, thanks.
Regards,
--
Nicolas George
_______________________________________________
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".
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-06-25 9:56 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-24 22:08 [FFmpeg-devel] [PATCH 1/2] avformat/tee: refactor option processing Marvin Scholz
2025-06-24 22:08 ` [FFmpeg-devel] [PATCH 2/2] avformat/tee: fix multiple bsfs in tee Marvin Scholz
2025-06-25 9:56 ` Nicolas George
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