Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 0/2] [RFC-NotForMerge] fftools/graphprint: The "bad" patch
@ 2025-05-28 15:24 ffmpegagent
  2025-05-28 15:24 ` [FFmpeg-devel] [PATCH 1/2] " softworkz
  2025-05-28 15:24 ` [FFmpeg-devel] [PATCH 2/2] [RFC-NotForMerge] fftools/graphprint: Inline glibc system() implementation softworkz
  0 siblings, 2 replies; 3+ messages in thread
From: ffmpegagent @ 2025-05-28 15:24 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: softworkz

This is the "bad" patch from the graphprint patchset. It is largely
unchanged, except:

 * The method to determine the temp folder has been revised
 * Only xdg-open is called for Linux
   (no alternate aliases)
 * An additional check is added for illustration
   (but not actually necessary)

A second patch is included which replaces the system() with the original
source code from glibc 2.31. This is for being able to actually discuss the
code rather than a "black box".

Please see my accompanying e-mail: The "bad" Patch

.

softworkz (2):
  [RFC-NotForMerge] fftools/graphprint: The "bad" patch
  [RFC-NotForMerge] fftools/graphprint: Inline glibc system()
    implementation

 doc/ffmpeg.texi                 |   4 +
 fftools/Makefile                |   2 +
 fftools/ffmpeg.c                |   2 +-
 fftools/ffmpeg.h                |   1 +
 fftools/ffmpeg_filter.c         |   2 +-
 fftools/ffmpeg_opt.c            |   4 +
 fftools/graph/_system.c         | 213 ++++++++++++++++++++++++++++++++
 fftools/graph/_system.h         |  27 ++++
 fftools/graph/_system_support.h | 199 +++++++++++++++++++++++++++++
 fftools/graph/filelauncher.c    | 201 ++++++++++++++++++++++++++++++
 fftools/graph/graphprint.c      |  48 ++++++-
 fftools/graph/graphprint.h      |  32 +++++
 12 files changed, 732 insertions(+), 3 deletions(-)
 create mode 100644 fftools/graph/_system.c
 create mode 100644 fftools/graph/_system.h
 create mode 100644 fftools/graph/_system_support.h
 create mode 100644 fftools/graph/filelauncher.c


base-commit: 96d4bcbcd81f18e4538f139fb86d52d41981c4be
Published-As: https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-89%2Fsoftworkz%2Fkillerfeature_system-v1
Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-89/softworkz/killerfeature_system-v1
Pull-Request: https://github.com/ffstaging/FFmpeg/pull/89
-- 
ffmpeg-codebot
_______________________________________________
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 1/2] [RFC-NotForMerge] fftools/graphprint: The "bad" patch
  2025-05-28 15:24 [FFmpeg-devel] [PATCH 0/2] [RFC-NotForMerge] fftools/graphprint: The "bad" patch ffmpegagent
@ 2025-05-28 15:24 ` softworkz
  2025-05-28 15:24 ` [FFmpeg-devel] [PATCH 2/2] [RFC-NotForMerge] fftools/graphprint: Inline glibc system() implementation softworkz
  1 sibling, 0 replies; 3+ messages in thread
From: softworkz @ 2025-05-28 15:24 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: softworkz

From: softworkz <softworkz@hotmail.com>

---
 doc/ffmpeg.texi              |   4 +
 fftools/Makefile             |   1 +
 fftools/ffmpeg.c             |   2 +-
 fftools/ffmpeg.h             |   1 +
 fftools/ffmpeg_filter.c      |   2 +-
 fftools/ffmpeg_opt.c         |   4 +
 fftools/graph/filelauncher.c | 200 +++++++++++++++++++++++++++++++++++
 fftools/graph/graphprint.c   |  48 ++++++++-
 fftools/graph/graphprint.h   |  32 ++++++
 9 files changed, 291 insertions(+), 3 deletions(-)
 create mode 100644 fftools/graph/filelauncher.c

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 35675b5309..4bcb6d6a01 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1404,6 +1404,10 @@ Writes execution graph details to the specified file in the format set via -prin
 Sets the output format (available formats are: default, compact, csv, flat, ini, json, xml, mermaid, mermaidhtml)
 The default format is json.
 
+@item -sg (@emph{global})
+Writes the execution graph to a temporary html file (mermaidhtml format) and
+tries to launch it in the default browser.
+
 @item -progress @var{url} (@emph{global})
 Send program-friendly progress information to @var{url}.
 
diff --git a/fftools/Makefile b/fftools/Makefile
index c1eba733da..f6492cb1d7 100644
--- a/fftools/Makefile
+++ b/fftools/Makefile
@@ -22,6 +22,7 @@ OBJS-ffmpeg +=                  \
     fftools/ffmpeg_opt.o        \
     fftools/ffmpeg_sched.o      \
     fftools/graph/graphprint.o        \
+    fftools/graph/filelauncher.o      \
     fftools/sync_queue.o        \
     fftools/thread_queue.o      \
     fftools/textformat/avtextformat.o \
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index de607cac93..0a7675fee0 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -309,7 +309,7 @@ const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
 
 static void ffmpeg_cleanup(int ret)
 {
-    if ((print_graphs || print_graphs_file) && nb_output_files > 0)
+    if ((print_graphs || print_graphs_file || show_graph) && nb_output_files > 0)
         print_filtergraphs(filtergraphs, nb_filtergraphs, input_files, nb_input_files, output_files, nb_output_files);
 
     if (do_benchmark) {
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 7fbf0ad532..49fea0307d 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -721,6 +721,7 @@ extern int print_graphs;
 extern char *print_graphs_file;
 extern char *print_graphs_format;
 extern int auto_conversion_filters;
+extern int show_graph;
 
 extern const AVIOInterruptCB int_cb;
 
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index b774606562..e82e333b7f 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -2985,7 +2985,7 @@ read_frames:
 
 finish:
 
-    if (print_graphs || print_graphs_file)
+    if (print_graphs || print_graphs_file || show_graph)
         print_filtergraph(fg, fgt.graph);
 
     // EOF is normal termination
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 3d1efe32f9..24713d640f 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -79,6 +79,7 @@ int vstats_version = 2;
 int print_graphs = 0;
 char *print_graphs_file = NULL;
 char *print_graphs_format = NULL;
+int show_graph = 0;
 int auto_conversion_filters = 1;
 int64_t stats_period = 500000;
 
@@ -1748,6 +1749,9 @@ const OptionDef options[] = {
     { "print_graphs_format", OPT_TYPE_STRING, 0,
         { &print_graphs_format },
       "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml, mermaid, mermaidhtml)", "format" },
+    { "sg",   OPT_TYPE_BOOL, 0,
+        { &show_graph },
+        "create execution graph as temporary html file and try to launch it in the default browser" },
     { "auto_conversion_filters", OPT_TYPE_BOOL, OPT_EXPERT,
         { &auto_conversion_filters },
         "enable automatic conversion filters globally" },
diff --git a/fftools/graph/filelauncher.c b/fftools/graph/filelauncher.c
new file mode 100644
index 0000000000..b46967e334
--- /dev/null
+++ b/fftools/graph/filelauncher.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2025 - softworkz
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32)
+#  include <windows.h>
+#  include <shellapi.h>
+#else
+#  include <sys/time.h>
+#  include <time.h>
+#  include <errno.h>
+#  include <sys/stat.h>
+#  include <sys/types.h>
+#  include <unistd.h>
+#endif
+#include "graphprint.h"
+#include "libavutil/bprint.h"
+
+int ff_open_html_in_browser(const char *html_path)
+{
+    if (!html_path || !*html_path)
+        return -1;
+
+#if defined(_WIN32)
+
+    {
+        HINSTANCE rc = ShellExecuteA(NULL, "open", html_path, NULL, NULL, SW_SHOWNORMAL);
+        if ((UINT_PTR)rc <= 32) {
+            // Fallback: system("start ...")
+            char cmd[1024];
+            _snprintf_s(cmd, sizeof(cmd), _TRUNCATE, "start \"\" \"%s\"", html_path);
+            if (system(cmd) != 0)
+                return -1;
+        }
+        return 0;
+    }
+
+#elif defined(__APPLE__)
+
+    {
+        av_log(NULL, AV_LOG_WARNING, "Browser launch not implemented...\n");
+        return 0;
+    }
+
+#else
+
+    // --- Linux / Unix-like -----------------------
+    {
+        static const char safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/-._";
+        AVBPrint buf;
+
+        // Due to the way how the temp path and file name are constructed, this check is not
+        // actually required and just for illustration of which chars can even occur in the path.
+        for (const char *p = html_path; *p; ++p) {
+            if (strchr(safe_chars, (unsigned char)*p) == NULL) {
+                av_log(NULL, AV_LOG_ERROR, "Invalid file path: '%s'.\n", html_path);
+                return -1;
+            }
+        }
+
+        av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+        av_bprintf(&buf, "xdg-open '%s' </dev/null 1>/dev/null 2>&1 &", html_path);
+
+        int ret = system(buf.str);
+
+        if (ret != -1 && WIFEXITED(ret) && WEXITSTATUS(ret) == 0)
+            return 0;
+
+        av_log(NULL, AV_LOG_WARNING, "Could not open '%s' in a browser.\n", html_path);
+        return -1;
+    }
+
+#endif
+}
+
+
+int ff_get_temp_dir(char *buf, size_t size)
+{
+#if defined(_WIN32)
+
+    // --- Windows ------------------------------------
+    {
+        // GetTempPathA returns length of the string (including trailing backslash).
+        // If the return value is greater than buffer size, it's an error.
+        DWORD len = GetTempPathA((DWORD)size, buf);
+        if (len == 0 || len > size) {
+            // Could not retrieve or buffer is too small
+            return -1;
+        }
+        return 0;
+    }
+
+#else
+
+    static const char *bases[] = { "/tmp", "/var/tmp", NULL };
+    AVBPrint bp;
+
+    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+
+    uid_t uid = getuid();
+
+    for (int i = 0; bases[i]; i++) {
+        av_bprint_clear(&bp);
+        av_bprintf(&bp, "%s/ffmpeg-%u", bases[i], uid);
+
+        if (mkdir(bp.str, 0700) == -1 && errno != EEXIST)
+            continue;
+
+        av_bprint_chars(&bp, '/', 1);
+
+        if (bp.len > size - 1)
+            return -1;
+
+        snprintf(buf, size, "%s", bp.str);
+        return 0;
+    }
+
+    av_log(NULL, AV_LOG_ERROR, "Unable to determine temp directory.\n");
+    av_bprint_clear(&bp);
+    return -1;
+
+#endif
+}
+
+int ff_make_timestamped_html_name(char *buf, size_t size)
+{
+#if defined(_WIN32)
+
+    /*----------- Windows version -----------*/
+    SYSTEMTIME st;
+    GetLocalTime(&st);
+    /*
+      st.wYear, st.wMonth, st.wDay,
+      st.wHour, st.wMinute, st.wSecond, st.wMilliseconds
+    */
+    int written = _snprintf_s(buf, size, _TRUNCATE,
+                              "ffmpeg_graph_%04d-%02d-%02d_%02d-%02d-%02d_%03d.html",
+                              st.wYear,
+                              st.wMonth,
+                              st.wDay,
+                              st.wHour,
+                              st.wMinute,
+                              st.wSecond,
+                              st.wMilliseconds);
+    if (written < 0)
+        return -1; /* Could not write into buffer */
+    return 0;
+
+#else
+
+    /*----------- macOS / Linux / Unix version -----------*/
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) != 0) {
+        return -1; /* gettimeofday failed */
+    }
+
+    struct tm local_tm;
+    localtime_r(&tv.tv_sec, &local_tm);
+
+    int ms = (int)(tv.tv_usec / 1000); /* convert microseconds to milliseconds */
+
+    /*
+       local_tm.tm_year is years since 1900,
+       local_tm.tm_mon  is 0-based (0=Jan, 11=Dec)
+    */
+    int written = snprintf(buf, size,
+                           "ffmpeg_graph_%04d-%02d-%02d_%02d-%02d-%02d_%03d.html",
+                           local_tm.tm_year + 1900,
+                           local_tm.tm_mon + 1,
+                           local_tm.tm_mday,
+                           local_tm.tm_hour,
+                           local_tm.tm_min,
+                           local_tm.tm_sec,
+                           ms);
+    if (written < 0 || (size_t)written >= size) {
+        return -1; /* Buffer too small or formatting error */
+    }
+    return 0;
+
+#endif
+}
diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index 852a8f6c0c..346e139494 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -884,6 +884,11 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
 
     av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
 
+    if (show_graph) {
+        if (!print_graphs_format || strcmp(print_graphs_format, "mermaidhtml") != 0)
+            print_graphs_format = av_strdup("mermaidhtml");
+    }
+
     if (!print_graphs_format)
         print_graphs_format = av_strdup("json");
     if (!print_graphs_format) {
@@ -1108,7 +1113,48 @@ cleanup:
 
 int print_filtergraphs(FilterGraph **graphs, int nb_graphs, InputFile **ifiles, int nb_ifiles, OutputFile **ofiles, int nb_ofiles)
 {
-    int ret = print_filtergraphs_priv(graphs, nb_graphs, ifiles, nb_ifiles, ofiles, nb_ofiles);
+    int ret;
+
+    if (show_graph) {
+        char buf[2048];
+        AVBPrint bp;
+
+        av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+        print_graphs = 0;
+
+        ret = ff_get_temp_dir(buf, sizeof(buf));
+        if (ret) {
+            av_log(NULL, AV_LOG_ERROR, "Error getting temp directory path for graph output file\n");
+            goto fail;
+        }
+
+        av_bprint_append_data(&bp, buf, strlen(buf));
+
+        ret = ff_make_timestamped_html_name(buf, sizeof(buf));
+        if (ret) {
+            av_log(NULL, AV_LOG_ERROR, "Error creating temp file name for graph output file\n");
+            goto fail;
+        }
+
+        av_bprint_append_data(&bp, buf, strlen(buf));
+
+        av_bprint_finalize(&bp, &print_graphs_file);
+    }
+
+    ret = print_filtergraphs_priv(graphs, nb_graphs, ifiles, nb_ifiles, ofiles, nb_ofiles);
+
+    if (!ret && show_graph) {
+        av_log(NULL, AV_LOG_INFO, "Execution graph saved as: %s\n", print_graphs_file);
+        av_log(NULL, AV_LOG_INFO, "Trying to launch graph in browser...\n");
+
+        ret = ff_open_html_in_browser(print_graphs_file);
+        if (ret) {
+            av_log(NULL, AV_LOG_ERROR, "Browser could not be launched for execution graph display\nPlease open manually: %s\n", print_graphs_file);
+        }
+    }
+
+fail:
     ff_resman_uninit();
     return ret;
 }
diff --git a/fftools/graph/graphprint.h b/fftools/graph/graphprint.h
index 9f043cc273..43f769870b 100644
--- a/fftools/graph/graphprint.h
+++ b/fftools/graph/graphprint.h
@@ -27,4 +27,36 @@ int print_filtergraphs(FilterGraph **graphs, int nb_graphs, InputFile **ifiles,
 
 int print_filtergraph(FilterGraph *fg, AVFilterGraph *graph);
 
+/**
+ * Open an HTML file in the default browser (Windows, macOS, Linux/Unix).
+ *
+ * @param html_path Absolute or relative path to the HTML file.
+ * @return 0 on success, -1 on failure.
+ *
+ * NOTE: This uses system() calls for non-Windows, and ShellExecute on Windows.
+ *       Exercise caution if 'html_path' is untrusted (possible command injection).
+ */
+int ff_open_html_in_browser(const char *html_path);
+
+/**
+ * Retrieve the system's temporary directory.
+ *
+ * @param buf  Output buffer to store the temp directory path (including trailing slash)
+ * @param size Size of the output buffer in bytes
+ * @return 0 on success, -1 on failure (buffer too small or other errors)
+ *
+ * Note: On most platforms, the path will include a trailing slash (e.g. "C:\\Users\\...\\Temp\\" on Windows, "/tmp/" on Unix).
+ */
+int ff_get_temp_dir(char *buf, size_t size);
+
+/**
+ * Create a timestamped HTML filename, e.g.:
+ *   ffmpeg_graph_2024-01-01_22-12-59_123.html
+ *
+ * @param buf  Pointer to buffer where the result is stored
+ * @param size Size of the buffer in bytes
+ * @return 0 on success, -1 on error (e.g. buffer too small)
+ */
+int ff_make_timestamped_html_name(char *buf, size_t size);
+
 #endif /* FFTOOLS_GRAPH_GRAPHPRINT_H */
-- 
ffmpeg-codebot

_______________________________________________
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] [RFC-NotForMerge] fftools/graphprint: Inline glibc system() implementation
  2025-05-28 15:24 [FFmpeg-devel] [PATCH 0/2] [RFC-NotForMerge] fftools/graphprint: The "bad" patch ffmpegagent
  2025-05-28 15:24 ` [FFmpeg-devel] [PATCH 1/2] " softworkz
@ 2025-05-28 15:24 ` softworkz
  1 sibling, 0 replies; 3+ messages in thread
From: softworkz @ 2025-05-28 15:24 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: softworkz

From: softworkz <softworkz@hotmail.com>

---
 fftools/Makefile                |   1 +
 fftools/graph/_system.c         | 213 ++++++++++++++++++++++++++++++++
 fftools/graph/_system.h         |  27 ++++
 fftools/graph/_system_support.h | 199 +++++++++++++++++++++++++++++
 fftools/graph/filelauncher.c    |   3 +-
 5 files changed, 442 insertions(+), 1 deletion(-)
 create mode 100644 fftools/graph/_system.c
 create mode 100644 fftools/graph/_system.h
 create mode 100644 fftools/graph/_system_support.h

diff --git a/fftools/Makefile b/fftools/Makefile
index f6492cb1d7..dba96d3740 100644
--- a/fftools/Makefile
+++ b/fftools/Makefile
@@ -23,6 +23,7 @@ OBJS-ffmpeg +=                  \
     fftools/ffmpeg_sched.o      \
     fftools/graph/graphprint.o        \
     fftools/graph/filelauncher.o      \
+    fftools/graph/_system.o      \
     fftools/sync_queue.o        \
     fftools/thread_queue.o      \
     fftools/textformat/avtextformat.o \
diff --git a/fftools/graph/_system.c b/fftools/graph/_system.c
new file mode 100644
index 0000000000..d1568611ff
--- /dev/null
+++ b/fftools/graph/_system.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1991-2018 - Free Software Foundation, Inc.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+ /* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+
+#if defined(_WIN32)
+#elif defined(__APPLE__)
+#else
+
+#include <errno.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "_system_support.h"
+#include <sys/types.h> // Add this include to define pid_t
+#include "_system.h"
+
+
+#define	SHELL_PATH	"/bin/sh"	/* Path of the shell.  */
+#define	SHELL_NAME	"sh"		/* Name to give it.  */
+
+
+#ifdef _LIBC_REENTRANT
+static struct sigaction intr, quit;
+static int sa_refcntr;
+__libc_lock_define_initialized (static, lock);
+
+# define DO_LOCK() __libc_lock_lock (lock)
+# define DO_UNLOCK() __libc_lock_unlock (lock)
+# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
+# define ADD_REF() sa_refcntr++
+# define SUB_REF() --sa_refcntr
+#else
+# define DO_LOCK()
+# define DO_UNLOCK()
+# define INIT_LOCK()
+# define ADD_REF() 0
+# define SUB_REF() 0
+#endif
+
+
+/* Execute LINE as a shell command, returning its status.  */
+static int
+do_system (const char *line)
+{
+  int status, save;
+  pid_t pid;
+  struct sigaction sa;
+#ifndef _LIBC_REENTRANT
+  struct sigaction intr, quit;
+#endif
+  sigset_t omask;
+
+  sa.sa_handler = SIG_IGN;
+  sa.sa_flags = 0;
+  __sigemptyset (&sa.sa_mask);
+
+  DO_LOCK ();
+  if (ADD_REF () == 0)
+    {
+      if (__sigaction (SIGINT, &sa, &intr) < 0)
+	{
+	  (void) SUB_REF ();
+	  goto out;
+	}
+      if (__sigaction (SIGQUIT, &sa, &quit) < 0)
+	{
+	  save = errno;
+	  (void) SUB_REF ();
+	  goto out_restore_sigint;
+	}
+    }
+  DO_UNLOCK ();
+
+  /* We reuse the bitmap in the 'sa' structure.  */
+  __sigaddset (&sa.sa_mask, SIGCHLD);
+  save = errno;
+  if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
+    {
+#ifndef _LIBC
+      if (errno == ENOSYS)
+	__set_errno (save);
+      else
+#endif
+	{
+	  DO_LOCK ();
+	  if (SUB_REF () == 0)
+	    {
+	      save = errno;
+	      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+	    out_restore_sigint:
+	      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+	      __set_errno (save);
+	    }
+	out:
+	  DO_UNLOCK ();
+	  return -1;
+	}
+    }
+
+#ifdef CLEANUP_HANDLER
+  CLEANUP_HANDLER;
+#endif
+
+#ifdef FORK
+  pid = FORK ();
+#else
+  pid = __fork ();
+#endif
+  if (pid == (pid_t) 0)
+    {
+      /* Child side.  */
+      const char *new_argv[4];
+      new_argv[0] = SHELL_NAME;
+      new_argv[1] = "-c";
+      new_argv[2] = line;
+      new_argv[3] = NULL;
+
+    /* Restore the signals.  */
+    (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+    (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+    (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
+    pthread_mutex_init(&(lock), NULL);
+    sa_refcntr = 0;
+    /* Exec the shell.  */
+    (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
+    _exit (127);
+    }
+  else if (pid < (pid_t) 0)
+    /* The fork failed.  */
+    status = -1;
+  else
+    /* Parent side.  */
+    {
+      /* Note the system() is a cancellation point.  But since we call
+	 waitpid() which itself is a cancellation point we do not
+	 have to do anything here.  */
+      if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
+	status = -1;
+    }
+
+#ifdef CLEANUP_HANDLER
+  CLEANUP_RESET;
+#endif
+
+  save = errno;
+  DO_LOCK ();
+  if ((SUB_REF () == 0
+       && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
+	   | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
+      || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
+    {
+#ifndef _LIBC
+      /* glibc cannot be used on systems without waitpid.  */
+      if (errno == ENOSYS)
+	__set_errno (save);
+      else
+#endif
+	status = -1;
+    }
+  DO_UNLOCK ();
+
+  return status;
+}
+
+int
+__libc_system (const char *line)
+{
+  if (line == NULL)
+    /* Check that we have a command processor available.  It might
+       not be available after a chroot(), for example.  */
+    return do_system ("exit 0") == 0;
+
+  return do_system (line);
+}
+////weak_alias (__libc_system, system)
+
+#endif
\ No newline at end of file
diff --git a/fftools/graph/_system.h b/fftools/graph/_system.h
new file mode 100644
index 0000000000..2780f234e0
--- /dev/null
+++ b/fftools/graph/_system.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 - softworkz
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_GRAPH_SYSTEM_H
+#define FFTOOLS_GRAPH_SYSTEM_H
+
+
+int __libc_system (const char *line);
+
+#endif /* FFTOOLS_GRAPH_SYSTEM_H */
diff --git a/fftools/graph/_system_support.h b/fftools/graph/_system_support.h
new file mode 100644
index 0000000000..6121c9bf2e
--- /dev/null
+++ b/fftools/graph/_system_support.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2025 - softworkz
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFTOOLS_GRAPH_SYSTEM_SUPPORT_H
+#define FFTOOLS_GRAPH_SYSTEM_SUPPORT_H
+
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* Platform-specific includes */
+#ifdef _WIN32
+#include <windows.h>
+#include "../../compat/w32pthreads.h"
+
+/* Windows doesn't have these POSIX headers - provide minimal compatibility */
+/* Visual Studio doesn't define pid_t, so define it ourselves */
+////#ifndef _PID_T_DEFINED
+////typedef int pid_t;
+////#define _PID_T_DEFINED
+////#endif
+
+typedef unsigned int sigset_t;
+
+/* Windows signal compatibility */
+#ifndef SIGQUIT
+#define SIGQUIT 3
+#endif
+#ifndef SIGCHLD
+#define SIGCHLD 0  /* Not used on Windows */
+#endif
+#define SIG_BLOCK 0
+#define SIG_SETMASK 1
+
+/* Windows sigaction compatibility */
+struct sigaction {
+    void (*sa_handler)(int);
+    sigset_t sa_mask;
+    int sa_flags;
+};
+
+/* Windows signal function stubs */
+static inline int sigemptyset(sigset_t *set) { *set = 0; return 0; }
+static inline int sigaddset(sigset_t *set, int sig) { *set |= (1 << sig); return 0; }
+static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { 
+    if (oldset) *oldset = 0; 
+    return 0; 
+}
+static inline int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
+    if (oldact) {
+        oldact->sa_handler = SIG_DFL;
+        oldact->sa_mask = 0;
+        oldact->sa_flags = 0;
+    }
+    return 0;
+}
+
+/* Windows process function stubs */
+static inline pid_t fork(void) { 
+    errno = ENOSYS; 
+    return -1; 
+}
+
+/* Don't redefine execve if it already exists - use a wrapper name instead */
+static inline int __execve_wrapper(const char *path, char *const argv[], char *const envp[]) {
+    /* Use Windows system() as fallback - argv[2] should be the command */
+    if (argv && argv[2]) {
+        return system(argv[2]);
+    }
+    return -1;
+}
+
+static inline pid_t waitpid(pid_t pid, int *status, int options) {
+    if (status) *status = 0;
+    return pid;
+}
+
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <pthread.h>
+#endif
+
+/* Ensure environ is declared - but don't conflict with existing declarations */
+#ifndef _WIN32
+extern char **environ;
+#endif
+
+/* glibc compatibility: TEMP_FAILURE_RETRY macro */
+#ifndef TEMP_FAILURE_RETRY
+#ifdef _MSC_VER
+/* Visual Studio compatible version - Windows doesn't have EINTR, so no retry needed */
+#define TEMP_FAILURE_RETRY(expression) (expression)
+#elif defined(__GNUC__)
+/* GCC version with statement expressions */
+#define TEMP_FAILURE_RETRY(expression) \
+  (__extension__                       \
+    ({ long int __result;              \
+       do __result = (long int) (expression); \
+       while (__result == -1L && errno == EINTR); \
+       __result; }))
+#else
+/* Fallback for other compilers */
+#define TEMP_FAILURE_RETRY(expression) (expression)
+#endif
+#endif
+
+/* glibc compatibility: libc-lock macros */
+#define __libc_lock_define_initialized(CLASS, NAME) \
+  CLASS pthread_mutex_t NAME = PTHREAD_MUTEX_INITIALIZER
+
+#define __libc_lock_lock(NAME) pthread_mutex_lock(&(NAME))
+#define __libc_lock_unlock(NAME) pthread_mutex_unlock(&(NAME))
+#define __libc_lock_init(NAME) pthread_mutex_init(&(NAME), NULL)
+
+/* glibc compatibility: signal functions */
+#define __sigemptyset(set) sigemptyset(set)
+#define __sigaddset(set, sig) sigaddset(set, sig)
+#define __sigprocmask(how, set, oldset) sigprocmask(how, set, oldset)
+#define __sigaction(sig, act, oldact) sigaction(sig, act, oldact)
+
+/* glibc compatibility: process functions */
+#define __fork fork
+#ifdef _WIN32
+#define __execve __execve_wrapper
+#define __environ _environ
+#else
+#define __execve execve
+#define __environ environ
+#endif
+#define __waitpid waitpid
+
+/* glibc compatibility: errno setting */
+#define __set_errno(val) (errno = (val))
+
+/* glibc compatibility: weak alias macro - simplified for Windows */
+#ifdef _WIN32
+#define weak_alias(name, aliasname) \
+    int aliasname(const char *line) { return name(line); }
+#else
+#define weak_alias(name, aliasname) \
+    extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)))
+#endif
+
+/* Threading and cancellation support */
+#ifndef _LIBC_REENTRANT
+#define _LIBC_REENTRANT 1
+#endif
+
+/* Optional cleanup handler support - can be defined by user if needed */
+#ifndef CLEANUP_HANDLER
+#define CLEANUP_HANDLER
+#endif
+
+#ifndef CLEANUP_RESET
+#define CLEANUP_RESET
+#endif
+
+/* Optional fork override - can be defined by user if needed */
+#ifndef FORK
+#define FORK __fork
+#endif
+
+/* Legacy wrappers for compatibility (keeping existing interface) */
+typedef pthread_mutex_t simple_lock_t;
+#define SIMPLE_LOCK_INIT PTHREAD_MUTEX_INITIALIZER
+static inline void simple_lock_lock(simple_lock_t *lock)   { pthread_mutex_lock(lock); }
+static inline void simple_lock_unlock(simple_lock_t *lock) { pthread_mutex_unlock(lock); }
+static inline void simple_lock_init(simple_lock_t *lock)   { pthread_mutex_init(lock, NULL); }
+
+static inline int sigaction_wrap(int sig, const struct sigaction *act, struct sigaction *oact) {
+    return sigaction(sig, act, oact);
+}
+static inline int sigprocmask_wrap(int how, const sigset_t *set, sigset_t *oldset) {
+    return sigprocmask(how, set, oldset);
+}
+static inline pid_t waitpid_wrap(pid_t pid, int *status, int options) {
+    return waitpid(pid, status, options);
+}
+
+#endif // FFTOOLS_GRAPH_SYSTEM_SUPPORT_H
\ No newline at end of file
diff --git a/fftools/graph/filelauncher.c b/fftools/graph/filelauncher.c
index b46967e334..2214338183 100644
--- a/fftools/graph/filelauncher.c
+++ b/fftools/graph/filelauncher.c
@@ -31,6 +31,7 @@
 #  include <sys/stat.h>
 #  include <sys/types.h>
 #  include <unistd.h>
+#  include "_system.h"
 #endif
 #include "graphprint.h"
 #include "libavutil/bprint.h"
@@ -80,7 +81,7 @@ int ff_open_html_in_browser(const char *html_path)
         av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
         av_bprintf(&buf, "xdg-open '%s' </dev/null 1>/dev/null 2>&1 &", html_path);
 
-        int ret = system(buf.str);
+        int ret = __libc_system(buf.str);
 
         if (ret != -1 && WIFEXITED(ret) && WEXITSTATUS(ret) == 0)
             return 0;
-- 
ffmpeg-codebot
_______________________________________________
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-05-28 15:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-28 15:24 [FFmpeg-devel] [PATCH 0/2] [RFC-NotForMerge] fftools/graphprint: The "bad" patch ffmpegagent
2025-05-28 15:24 ` [FFmpeg-devel] [PATCH 1/2] " softworkz
2025-05-28 15:24 ` [FFmpeg-devel] [PATCH 2/2] [RFC-NotForMerge] fftools/graphprint: Inline glibc system() implementation softworkz

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