clapper-app: Create pipeline preview file async

This commit is contained in:
Rafał Dzięgiel
2025-02-18 21:32:35 +01:00
parent b8a4a90b6c
commit 224326857b
4 changed files with 120 additions and 43 deletions

View File

@@ -41,6 +41,7 @@ struct _ClapperAppApplication
GtkApplication parent; GtkApplication parent;
GSettings *settings; GSettings *settings;
GCancellable *cancellable;
gboolean need_init_state; gboolean need_init_state;
}; };
@@ -61,6 +62,12 @@ struct ClapperPluginData
struct ClapperPluginFeatureData features[10]; struct ClapperPluginFeatureData features[10];
}; };
typedef struct
{
ClapperAppApplication *app;
guint id;
} ClapperAppWindowData;
typedef struct typedef struct
{ {
const gchar *action; const gchar *action;
@@ -396,7 +403,7 @@ show_info (GSimpleAction *action, GVariant *param, gpointer user_data)
} }
static void static void
_show_pipeline_cb (GtkFileLauncher *launcher, _launch_pipeline_cb (GtkFileLauncher *launcher,
GAsyncResult *res, gpointer user_data G_GNUC_UNUSED) GAsyncResult *res, gpointer user_data G_GNUC_UNUSED)
{ {
GError *error = NULL; GError *error = NULL;
@@ -411,14 +418,52 @@ _show_pipeline_cb (GtkFileLauncher *launcher,
} }
static void static void
show_pipeline (GSimpleAction *action, GVariant *param, gpointer user_data) _show_pipeline_cb (GObject *source G_GNUC_UNUSED,
GAsyncResult *res, ClapperAppWindowData *win_data)
{ {
GtkApplication *gtk_app = GTK_APPLICATION (user_data); GTask *task = G_TASK (res);
GtkWindow *window; GtkWindow *window;
GtkFileLauncher *launcher;
GFile *svg_file; GFile *svg_file;
GError *error = NULL; GError *error = NULL;
svg_file = (GFile *) g_task_propagate_pointer (task, &error);
if (error) {
if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED) {
GST_ERROR ("Could not create pipeline graph file, reason: %s",
GST_STR_NULL (error->message));
}
g_error_free (error);
g_free (win_data);
return;
}
if ((window = gtk_application_get_window_by_id (
GTK_APPLICATION (win_data->app), win_data->id))) {
GtkFileLauncher *launcher = gtk_file_launcher_new (svg_file);
#if GTK_CHECK_VERSION(4,12,0)
gtk_file_launcher_set_always_ask (launcher, TRUE);
#endif
gtk_file_launcher_launch (launcher, window, NULL,
(GAsyncReadyCallback) _launch_pipeline_cb, NULL);
g_object_unref (launcher);
}
g_object_unref (svg_file);
g_free (win_data);
}
static void
show_pipeline (GSimpleAction *action, GVariant *param, gpointer user_data)
{
ClapperAppApplication *self = CLAPPER_APP_APPLICATION_CAST (user_data);
GtkApplication *gtk_app = GTK_APPLICATION (self);
GtkWindow *window;
ClapperAppWindowData *win_data;
window = gtk_application_get_active_window (gtk_app); window = gtk_application_get_active_window (gtk_app);
while (window && !CLAPPER_APP_IS_WINDOW (window)) while (window && !CLAPPER_APP_IS_WINDOW (window))
@@ -427,25 +472,19 @@ show_pipeline (GSimpleAction *action, GVariant *param, gpointer user_data)
if (G_UNLIKELY (window == NULL)) if (G_UNLIKELY (window == NULL))
return; return;
if (!(svg_file = clapper_app_utils_create_pipeline_svg_file ( if (self->cancellable) {
clapper_app_window_get_player (CLAPPER_APP_WINDOW (window)), &error))) { g_cancellable_cancel (self->cancellable);
GST_ERROR ("Could not create pipeline graph file, reason: %s", g_object_unref (self->cancellable);
GST_STR_NULL (error->message));
g_error_free (error);
return;
} }
self->cancellable = g_cancellable_new ();
launcher = gtk_file_launcher_new (svg_file); win_data = g_new (ClapperAppWindowData, 1);
g_object_unref (svg_file); win_data->app = self;
win_data->id = gtk_application_window_get_id (GTK_APPLICATION_WINDOW (window));
#if GTK_CHECK_VERSION(4,12,0) clapper_app_utils_create_pipeline_svg_file_async (
gtk_file_launcher_set_always_ask (launcher, TRUE); clapper_app_window_get_player (CLAPPER_APP_WINDOW (window)),
#endif self->cancellable, (GAsyncReadyCallback) _show_pipeline_cb, win_data);
gtk_file_launcher_launch (launcher, window, NULL,
(GAsyncReadyCallback) _show_pipeline_cb, NULL);
g_object_unref (launcher);
} }
static void static void
@@ -809,6 +848,19 @@ clapper_app_application_constructed (GObject *object)
G_OBJECT_CLASS (parent_class)->constructed (object); G_OBJECT_CLASS (parent_class)->constructed (object);
} }
static void
clapper_app_application_dispose (GObject *object)
{
ClapperAppApplication *self = CLAPPER_APP_APPLICATION_CAST (object);
if (self->cancellable) {
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void static void
clapper_app_application_finalize (GObject *object) clapper_app_application_finalize (GObject *object)
{ {
@@ -832,6 +884,7 @@ clapper_app_application_class_init (ClapperAppApplicationClass *klass)
"Clapper App Application"); "Clapper App Application");
gobject_class->constructed = clapper_app_application_constructed; gobject_class->constructed = clapper_app_application_constructed;
gobject_class->dispose = clapper_app_application_dispose;
gobject_class->finalize = clapper_app_application_finalize; gobject_class->finalize = clapper_app_application_finalize;
gtk_application_class->window_removed = clapper_app_application_window_removed; gtk_application_class->window_removed = clapper_app_application_window_removed;

View File

@@ -19,6 +19,7 @@
#include <glib.h> #include <glib.h>
#include <glib-object.h> #include <glib-object.h>
#include <gio/gio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
G_BEGIN_DECLS G_BEGIN_DECLS

View File

@@ -548,42 +548,42 @@ _get_tmp_dir (const gchar *subdir)
#ifdef HAVE_GRAPHVIZ #ifdef HAVE_GRAPHVIZ
static GFile * static GFile *
_create_tmp_subdir (const gchar *subdir) _create_tmp_subdir (const gchar *subdir, GCancellable *cancellable, GError **error)
{ {
GFile *tmp_dir; GFile *tmp_dir;
GError *error = NULL; GError *my_error = NULL;
tmp_dir = _get_tmp_dir (subdir); tmp_dir = _get_tmp_dir (subdir);
if (!g_file_make_directory_with_parents (tmp_dir, NULL, &error)) { if (!g_file_make_directory_with_parents (tmp_dir, cancellable, &my_error)) {
if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_EXISTS) { if (my_error->domain != G_IO_ERROR || my_error->code != G_IO_ERROR_EXISTS) {
GST_ERROR ("Could not create temp dir, reason: %s", *error = g_error_copy (my_error);
GST_STR_NULL (error->message));
g_clear_object (&tmp_dir); // return NULL g_clear_object (&tmp_dir); // return NULL
} }
g_error_free (error); g_error_free (my_error);
} }
return tmp_dir; return tmp_dir;
} }
#endif #endif
GFile * static void
clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **error) _create_pipeline_svg_file_in_thread (GTask *task, GObject *source G_GNUC_UNUSED,
ClapperPlayer *player, GCancellable *cancellable)
{ {
GFile *tmp_file = NULL; GFile *tmp_file = NULL;
GError *error = NULL;
#ifdef HAVE_GRAPHVIZ #ifdef HAVE_GRAPHVIZ
GFile *tmp_subdir; GFile *tmp_subdir;
Agraph_t *graph; Agraph_t *graph;
GVC_t *gvc; GVC_t *gvc;
gchar *path, *template, *dot_data, *img_data = NULL; gchar *path, *template = NULL, *dot_data = NULL, *img_data = NULL;
gint fd; gint fd;
guint size = 0; guint size = 0;
tmp_subdir = _create_tmp_subdir ("pipelines"); if (!(tmp_subdir = _create_tmp_subdir ("pipelines", cancellable, &error)))
if (G_UNLIKELY (tmp_subdir == NULL)) goto finish;
return NULL;
path = g_file_get_path (tmp_subdir); path = g_file_get_path (tmp_subdir);
g_object_unref (tmp_subdir); g_object_unref (tmp_subdir);
@@ -594,14 +594,16 @@ clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **erro
fd = g_mkstemp (template); // Modifies template to actual filename fd = g_mkstemp (template); // Modifies template to actual filename
if (G_UNLIKELY (fd == -1)) { if (G_UNLIKELY (fd == -1)) {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not open temp file for writing"); "Could not open temp file for writing");
g_free (template); goto finish;
return NULL;
} }
dot_data = clapper_player_make_pipeline_graph (player, GST_DEBUG_GRAPH_SHOW_ALL); dot_data = clapper_player_make_pipeline_graph (player, GST_DEBUG_GRAPH_SHOW_ALL);
if (g_cancellable_is_cancelled (cancellable))
goto close_and_finish;
graph = agmemread (dot_data); graph = agmemread (dot_data);
gvc = gvContext (); gvc = gvContext ();
@@ -610,27 +612,48 @@ clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **erro
agclose (graph); agclose (graph);
gvFreeContext (gvc); gvFreeContext (gvc);
g_free (dot_data);
if (g_cancellable_is_cancelled (cancellable))
goto close_and_finish;
if (write (fd, img_data, size) != -1) { if (write (fd, img_data, size) != -1) {
tmp_file = g_file_new_for_path (template); tmp_file = g_file_new_for_path (template);
} else { } else {
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not write data to temp file"); "Could not write data to temp file");
} }
close_and_finish:
/* Always close the file IO */ /* Always close the file IO */
if (G_UNLIKELY (close (fd) == -1)) if (G_UNLIKELY (close (fd) == -1))
GST_ERROR ("Could not close temp file!"); GST_ERROR ("Could not close temp file!");
g_free (img_data); finish:
g_free (template); g_free (template);
g_free (dot_data);
g_free (img_data);
#else #else
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Cannot create graph file when compiled without Graphviz"); "Cannot create graph file when compiled without Graphviz");
#endif #endif
return tmp_file; if (tmp_file)
g_task_return_pointer (task, tmp_file, (GDestroyNotify) g_object_unref);
else
g_task_return_error (task, error);
}
void
clapper_app_utils_create_pipeline_svg_file_async (ClapperPlayer *player,
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
{
GTask *task;
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_task_data (task, gst_object_ref (player), (GDestroyNotify) gst_object_unref);
g_task_run_in_thread (task, (GTaskThreadFunc) _create_pipeline_svg_file_in_thread);
g_object_unref (task);
} }
static gboolean static gboolean

View File

@@ -85,7 +85,7 @@ G_GNUC_INTERNAL
GstElement * clapper_app_utils_make_element (const gchar *string); GstElement * clapper_app_utils_make_element (const gchar *string);
G_GNUC_INTERNAL G_GNUC_INTERNAL
GFile * clapper_app_utils_create_pipeline_svg_file (ClapperPlayer *player, GError **error); void clapper_app_utils_create_pipeline_svg_file_async (ClapperPlayer *player, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
G_GNUC_INTERNAL G_GNUC_INTERNAL
void clapper_app_utils_delete_tmp_dir (void); void clapper_app_utils_delete_tmp_dir (void);