From 1c0049ec2bccdc1673addfb88615f8d325ba563f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Dzi=C4=99giel?= Date: Thu, 19 Jun 2025 08:32:54 +0200 Subject: [PATCH] clapper: Make timeline insert/remove work from any thread Detect and auto switch thread to main if done from a different one. With this, apps can still continue to implement thread switch and doing multiple insertions/deletions within single main thread invoke or simply call this function from a different thread for convenience. --- src/lib/clapper/clapper-timeline-private.h | 6 + src/lib/clapper/clapper-timeline.c | 63 +++++----- src/lib/clapper/clapper-timeline.h | 2 +- src/lib/clapper/clapper-utils-private.h | 8 ++ src/lib/clapper/clapper-utils.c | 129 +++++++++++++-------- 5 files changed, 135 insertions(+), 73 deletions(-) diff --git a/src/lib/clapper/clapper-timeline-private.h b/src/lib/clapper/clapper-timeline-private.h index 5e8ab7c4..f10b9f97 100644 --- a/src/lib/clapper/clapper-timeline-private.h +++ b/src/lib/clapper/clapper-timeline-private.h @@ -34,4 +34,10 @@ gboolean clapper_timeline_set_toc (ClapperTimeline *timeline, GstToc *toc, gbool G_GNUC_INTERNAL void clapper_timeline_refresh (ClapperTimeline *timeline); +G_GNUC_INTERNAL +void clapper_timeline_insert_marker_internal (ClapperTimeline *timeline, ClapperMarker *marker); + +G_GNUC_INTERNAL +void clapper_timeline_remove_marker_internal (ClapperTimeline *timeline, ClapperMarker *marker); + G_END_DECLS diff --git a/src/lib/clapper/clapper-timeline.c b/src/lib/clapper/clapper-timeline.c index b03e326d..9fa7425e 100644 --- a/src/lib/clapper/clapper-timeline.c +++ b/src/lib/clapper/clapper-timeline.c @@ -30,6 +30,7 @@ #include "clapper-player-private.h" #include "clapper-reactables-manager-private.h" #include "clapper-features-manager-private.h" +#include "clapper-utils-private.h" #define GST_CAT_DEFAULT clapper_timeline_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); @@ -187,25 +188,12 @@ _take_marker_unlocked (ClapperTimeline *self, ClapperMarker *marker) return g_sequence_iter_get_position (iter); } -/** - * clapper_timeline_insert_marker: - * @timeline: a #ClapperTimeline - * @marker: a #ClapperMarker - * - * Insert the #ClapperMarker into @timeline. - * - * Returns: %TRUE if inserted, %FALSE if marker was - * already inserted into timeline. - */ -gboolean -clapper_timeline_insert_marker (ClapperTimeline *self, ClapperMarker *marker) +void +clapper_timeline_insert_marker_internal (ClapperTimeline *self, ClapperMarker *marker) { gboolean success; gint position = 0; - g_return_val_if_fail (CLAPPER_IS_TIMELINE (self), FALSE); - g_return_val_if_fail (CLAPPER_IS_MARKER (marker), FALSE); - GST_OBJECT_LOCK (self); if ((success = !g_sequence_lookup (self->markers_seq, marker, @@ -220,30 +208,34 @@ clapper_timeline_insert_marker (ClapperTimeline *self, ClapperMarker *marker) clapper_timeline_post_item_updated (self); } - - return success; } /** - * clapper_timeline_remove_marker: + * clapper_timeline_insert_marker: * @timeline: a #ClapperTimeline * @marker: a #ClapperMarker * - * Removes #ClapperMarker from the timeline. - * - * If marker was not in the @timeline, this function will do nothing, - * so it is safe to call if unsure. + * Insert the #ClapperMarker into @timeline. */ void -clapper_timeline_remove_marker (ClapperTimeline *self, ClapperMarker *marker) +clapper_timeline_insert_marker (ClapperTimeline *self, ClapperMarker *marker) +{ + g_return_if_fail (CLAPPER_IS_TIMELINE (self)); + g_return_if_fail (CLAPPER_IS_MARKER (marker)); + + if (g_main_context_is_owner (g_main_context_default ())) + clapper_timeline_insert_marker_internal (self, marker); + else + clapper_utils_timeline_insert_on_main_sync (self, marker); +} + +void +clapper_timeline_remove_marker_internal (ClapperTimeline *self, ClapperMarker *marker) { GSequenceIter *iter; gint position = 0; gboolean success = FALSE; - g_return_if_fail (CLAPPER_IS_TIMELINE (self)); - g_return_if_fail (CLAPPER_IS_MARKER (marker)); - GST_OBJECT_LOCK (self); if ((iter = g_sequence_lookup (self->markers_seq, marker, @@ -264,6 +256,25 @@ clapper_timeline_remove_marker (ClapperTimeline *self, ClapperMarker *marker) } } +/** + * clapper_timeline_remove_marker: + * @timeline: a #ClapperTimeline + * @marker: a #ClapperMarker + * + * Removes #ClapperMarker from the timeline if present. + */ +void +clapper_timeline_remove_marker (ClapperTimeline *self, ClapperMarker *marker) +{ + g_return_if_fail (CLAPPER_IS_TIMELINE (self)); + g_return_if_fail (CLAPPER_IS_MARKER (marker)); + + if (g_main_context_is_owner (g_main_context_default ())) + clapper_timeline_remove_marker_internal (self, marker); + else + clapper_utils_timeline_remove_on_main_sync (self, marker); +} + /** * clapper_timeline_get_marker: * @timeline: a #ClapperTimeline diff --git a/src/lib/clapper/clapper-timeline.h b/src/lib/clapper/clapper-timeline.h index fa621192..022560f4 100644 --- a/src/lib/clapper/clapper-timeline.h +++ b/src/lib/clapper/clapper-timeline.h @@ -38,7 +38,7 @@ CLAPPER_API G_DECLARE_FINAL_TYPE (ClapperTimeline, clapper_timeline, CLAPPER, TIMELINE, GstObject) CLAPPER_API -gboolean clapper_timeline_insert_marker (ClapperTimeline *timeline, ClapperMarker *marker); +void clapper_timeline_insert_marker (ClapperTimeline *timeline, ClapperMarker *marker); CLAPPER_API void clapper_timeline_remove_marker (ClapperTimeline *timeline, ClapperMarker *marker); diff --git a/src/lib/clapper/clapper-utils-private.h b/src/lib/clapper/clapper-utils-private.h index 6c391dbf..49e695db 100644 --- a/src/lib/clapper/clapper-utils-private.h +++ b/src/lib/clapper/clapper-utils-private.h @@ -26,6 +26,8 @@ #include "clapper-utils.h" #include "clapper-queue.h" #include "clapper-media-item.h" +#include "clapper-timeline.h" +#include "clapper-marker.h" G_BEGIN_DECLS @@ -44,6 +46,12 @@ void clapper_utils_queue_remove_on_main_sync (ClapperQueue *queue, ClapperMediaI G_GNUC_INTERNAL void clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue); +G_GNUC_INTERNAL +void clapper_utils_timeline_insert_on_main_sync (ClapperTimeline *timeline, ClapperMarker *marker); + +G_GNUC_INTERNAL +void clapper_utils_timeline_remove_on_main_sync (ClapperTimeline *timeline, ClapperMarker *marker); + G_GNUC_INTERNAL void clapper_utils_prop_notify_on_main_sync (GObject *object, GParamSpec *pspec); diff --git a/src/lib/clapper/clapper-utils.c b/src/lib/clapper/clapper-utils.c index ad090117..9477fe74 100644 --- a/src/lib/clapper/clapper-utils.c +++ b/src/lib/clapper/clapper-utils.c @@ -17,6 +17,7 @@ */ #include "clapper-utils-private.h" +#include "clapper-timeline-private.h" #include "../shared/clapper-shared-utils-private.h" #define GST_CAT_DEFAULT clapper_utils_debug @@ -24,19 +25,21 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); typedef enum { - CLAPPER_UTILS_QUEUE_ALTER_APPEND = 1, - CLAPPER_UTILS_QUEUE_ALTER_INSERT, - CLAPPER_UTILS_QUEUE_ALTER_REMOVE, - CLAPPER_UTILS_QUEUE_ALTER_CLEAR -} ClapperUtilsQueueAlterMethod; + CLAPPER_UTILS_LIST_ALTER_QUEUE_APPEND = 1, + CLAPPER_UTILS_LIST_ALTER_QUEUE_INSERT, + CLAPPER_UTILS_LIST_ALTER_QUEUE_REMOVE, + CLAPPER_UTILS_LIST_ALTER_QUEUE_CLEAR, + CLAPPER_UTILS_LIST_ALTER_TIMELINE_INSERT, + CLAPPER_UTILS_LIST_ALTER_TIMELINE_REMOVE +} ClapperUtilsListAlterMethod; typedef struct { - ClapperQueue *queue; - ClapperMediaItem *item; - ClapperMediaItem *after_item; - ClapperUtilsQueueAlterMethod method; -} ClapperUtilsQueueAlterData; + GListModel *list; + GObject *item; + GObject *after_item; + ClapperUtilsListAlterMethod method; +} ClapperUtilsListAlterData; typedef struct { @@ -51,27 +54,26 @@ clapper_utils_initialize (void) "Clapper Utilities"); } -static ClapperUtilsQueueAlterData * -clapper_utils_queue_alter_data_new (ClapperQueue *queue, - ClapperMediaItem *item, ClapperMediaItem *after_item, - ClapperUtilsQueueAlterMethod method) +static ClapperUtilsListAlterData * +clapper_utils_list_alter_data_new (GListModel *list, GObject *item, + GObject *after_item, ClapperUtilsListAlterMethod method) { - ClapperUtilsQueueAlterData *data = g_new (ClapperUtilsQueueAlterData, 1); + ClapperUtilsListAlterData *data = g_new (ClapperUtilsListAlterData, 1); - data->queue = queue; + data->list = list; data->item = item; data->after_item = after_item; data->method = method; - GST_TRACE ("Created queue alter data: %p", data); + GST_TRACE ("Created list alter data: %p", data); return data; } static void -clapper_utils_queue_alter_data_free (ClapperUtilsQueueAlterData *data) +clapper_utils_list_alter_data_free (ClapperUtilsListAlterData *data) { - GST_TRACE ("Freeing queue alter data: %p", data); + GST_TRACE ("Freeing list alter data: %p", data); g_free (data); } @@ -98,35 +100,48 @@ clapper_utils_prop_notify_data_free (ClapperUtilsPropNotifyData *data) } static gpointer -clapper_utils_queue_alter_on_main (ClapperUtilsQueueAlterData *data) +clapper_utils_list_alter_on_main (ClapperUtilsListAlterData *data) { GST_DEBUG ("Queue alter invoked"); switch (data->method) { - case CLAPPER_UTILS_QUEUE_ALTER_APPEND: - clapper_queue_add_item (data->queue, data->item); + case CLAPPER_UTILS_LIST_ALTER_QUEUE_APPEND: + clapper_queue_add_item (CLAPPER_QUEUE_CAST (data->list), + CLAPPER_MEDIA_ITEM_CAST (data->item)); break; - case CLAPPER_UTILS_QUEUE_ALTER_INSERT:{ + case CLAPPER_UTILS_LIST_ALTER_QUEUE_INSERT:{ guint index; /* If we have "after_item" then we need to insert after it, otherwise prepend */ if (data->after_item) { - if (clapper_queue_find_item (data->queue, data->after_item, &index)) + if (clapper_queue_find_item (CLAPPER_QUEUE_CAST (data->list), + CLAPPER_MEDIA_ITEM_CAST (data->after_item), &index)) { index++; - else // If not found, just append at the end - index = -1; + } else { + index = -1; // if not found, just append at the end + } } else { index = 0; } - clapper_queue_insert_item (data->queue, data->item, index); + clapper_queue_insert_item (CLAPPER_QUEUE_CAST (data->list), + CLAPPER_MEDIA_ITEM_CAST (data->item), index); break; } - case CLAPPER_UTILS_QUEUE_ALTER_REMOVE: - clapper_queue_remove_item (data->queue, data->item); + case CLAPPER_UTILS_LIST_ALTER_QUEUE_REMOVE: + clapper_queue_remove_item (CLAPPER_QUEUE_CAST (data->list), + CLAPPER_MEDIA_ITEM_CAST (data->item)); break; - case CLAPPER_UTILS_QUEUE_ALTER_CLEAR: - clapper_queue_clear (data->queue); + case CLAPPER_UTILS_LIST_ALTER_QUEUE_CLEAR: + clapper_queue_clear (CLAPPER_QUEUE_CAST (data->list)); + break; + case CLAPPER_UTILS_LIST_ALTER_TIMELINE_INSERT: + clapper_timeline_insert_marker_internal (CLAPPER_TIMELINE_CAST (data->list), + CLAPPER_MARKER_CAST (data->item)); + break; + case CLAPPER_UTILS_LIST_ALTER_TIMELINE_REMOVE: + clapper_timeline_remove_marker_internal (CLAPPER_TIMELINE_CAST (data->list), + CLAPPER_MARKER_CAST (data->item)); break; default: g_assert_not_reached (); @@ -146,13 +161,13 @@ clapper_utils_prop_notify_on_main (ClapperUtilsPropNotifyData *data) } static inline void -clapper_utils_queue_alter_invoke_on_main_sync_take (ClapperUtilsQueueAlterData *data) +clapper_utils_list_alter_invoke_on_main_sync_take (ClapperUtilsListAlterData *data) { GST_DEBUG ("Invoking queue alter on main..."); clapper_shared_utils_context_invoke_sync_full (g_main_context_default (), - (GThreadFunc) clapper_utils_queue_alter_on_main, data, - (GDestroyNotify) clapper_utils_queue_alter_data_free); + (GThreadFunc) clapper_utils_list_alter_on_main, data, + (GDestroyNotify) clapper_utils_list_alter_data_free); GST_DEBUG ("Queue alter invoke finished"); } @@ -160,34 +175,56 @@ clapper_utils_queue_alter_invoke_on_main_sync_take (ClapperUtilsQueueAlterData * void clapper_utils_queue_append_on_main_sync (ClapperQueue *queue, ClapperMediaItem *item) { - ClapperUtilsQueueAlterData *data = clapper_utils_queue_alter_data_new (queue, - item, NULL, CLAPPER_UTILS_QUEUE_ALTER_APPEND); - clapper_utils_queue_alter_invoke_on_main_sync_take (data); + ClapperUtilsListAlterData *data = clapper_utils_list_alter_data_new ( + (GListModel *) queue, (GObject *) item, NULL, + CLAPPER_UTILS_LIST_ALTER_QUEUE_APPEND); + clapper_utils_list_alter_invoke_on_main_sync_take (data); } void clapper_utils_queue_insert_on_main_sync (ClapperQueue *queue, ClapperMediaItem *item, ClapperMediaItem *after_item) { - ClapperUtilsQueueAlterData *data = clapper_utils_queue_alter_data_new (queue, - item, after_item, CLAPPER_UTILS_QUEUE_ALTER_INSERT); - clapper_utils_queue_alter_invoke_on_main_sync_take (data); + ClapperUtilsListAlterData *data = clapper_utils_list_alter_data_new ( + (GListModel *) queue, (GObject *) item, (GObject *) after_item, + CLAPPER_UTILS_LIST_ALTER_QUEUE_INSERT); + clapper_utils_list_alter_invoke_on_main_sync_take (data); } void clapper_utils_queue_remove_on_main_sync (ClapperQueue *queue, ClapperMediaItem *item) { - ClapperUtilsQueueAlterData *data = clapper_utils_queue_alter_data_new (queue, - item, NULL, CLAPPER_UTILS_QUEUE_ALTER_REMOVE); - clapper_utils_queue_alter_invoke_on_main_sync_take (data); + ClapperUtilsListAlterData *data = clapper_utils_list_alter_data_new ( + (GListModel *) queue, (GObject *) item, NULL, + CLAPPER_UTILS_LIST_ALTER_QUEUE_REMOVE); + clapper_utils_list_alter_invoke_on_main_sync_take (data); } void clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue) { - ClapperUtilsQueueAlterData *data = clapper_utils_queue_alter_data_new (queue, - NULL, NULL, CLAPPER_UTILS_QUEUE_ALTER_CLEAR); - clapper_utils_queue_alter_invoke_on_main_sync_take (data); + ClapperUtilsListAlterData *data = clapper_utils_list_alter_data_new ( + (GListModel *) queue, NULL, NULL, + CLAPPER_UTILS_LIST_ALTER_QUEUE_CLEAR); + clapper_utils_list_alter_invoke_on_main_sync_take (data); +} + +void +clapper_utils_timeline_insert_on_main_sync (ClapperTimeline *timeline, ClapperMarker *marker) +{ + ClapperUtilsListAlterData *data = clapper_utils_list_alter_data_new ( + (GListModel *) timeline, (GObject *) marker, NULL, + CLAPPER_UTILS_LIST_ALTER_TIMELINE_INSERT); + clapper_utils_list_alter_invoke_on_main_sync_take (data); +} + +void +clapper_utils_timeline_remove_on_main_sync (ClapperTimeline *timeline, ClapperMarker *marker) +{ + ClapperUtilsListAlterData *data = clapper_utils_list_alter_data_new ( + (GListModel *) timeline, (GObject *) marker, NULL, + CLAPPER_UTILS_LIST_ALTER_TIMELINE_REMOVE); + clapper_utils_list_alter_invoke_on_main_sync_take (data); } void