ges: Enhance ges_{init/deinit} documentation

Add some init/deinit related comment and make assertion when
ges_deinit() is called from unexpected thread.
This commit is contained in:
Seungha Yang 2019-01-28 20:45:11 +09:00 committed by Thibault Saunier
parent facea28b28
commit 41597dfdfd
2 changed files with 29 additions and 9 deletions

View file

@ -1082,6 +1082,14 @@ done:
* method. This asset can not be used as is. * method. This asset can not be used as is.
* @user_data: The user data to pass when @callback is called * @user_data: The user data to pass when @callback is called
* *
* The @callback will be called from a running #GMainLoop which is iterating a #GMainContext.
* Note that, users should ensure the #GMainContext, since this method will notify
* @callback from the thread which was associated with a thread default
* #GMainContext at calling ges_init().
* For example, if a user wants non-default #GMainContext to be associated
* with @callback, ges_init() must be called after g_main_context_push_thread_default ()
* with custom #GMainContext.
*
* Request a new #GESAsset asyncronously, @callback will be called when the materail is * Request a new #GESAsset asyncronously, @callback will be called when the materail is
* ready to be used or if an error occured. * ready to be used or if an error occured.
* *

View file

@ -47,13 +47,16 @@ GST_DEBUG_CATEGORY (_ges_debug);
G_LOCK_DEFINE_STATIC (init_lock); G_LOCK_DEFINE_STATIC (init_lock);
static gboolean ges_initialized = FALSE; /* (without holding ref) thread object for thread_self() validation
* between init/deinit
*/
static GThread *initialized_thread = NULL;
static gboolean static gboolean
ges_init_pre (GOptionContext * context, GOptionGroup * group, gpointer data, ges_init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
GError ** error) GError ** error)
{ {
if (ges_initialized) { if (initialized_thread) {
GST_DEBUG ("already initialized"); GST_DEBUG ("already initialized");
return TRUE; return TRUE;
} }
@ -72,7 +75,7 @@ ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
GESUriClipAssetClass *uriasset_klass = NULL; GESUriClipAssetClass *uriasset_klass = NULL;
GstElementFactory *nlecomposition_factory = NULL; GstElementFactory *nlecomposition_factory = NULL;
if (ges_initialized) { if (initialized_thread) {
GST_DEBUG ("already initialized ges"); GST_DEBUG ("already initialized ges");
return TRUE; return TRUE;
} }
@ -124,7 +127,7 @@ ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
gst_element_register (NULL, "gespipeline", 0, GES_TYPE_PIPELINE); gst_element_register (NULL, "gespipeline", 0, GES_TYPE_PIPELINE);
/* TODO: user-defined types? */ /* TODO: user-defined types? */
ges_initialized = TRUE; initialized_thread = g_thread_self ();
g_type_class_unref (uriasset_klass); g_type_class_unref (uriasset_klass);
GST_DEBUG ("GStreamer Editing Services initialized"); GST_DEBUG ("GStreamer Editing Services initialized");
@ -146,6 +149,11 @@ failed:
* Initialize the GStreamer Editing Service. Call this before any usage of * Initialize the GStreamer Editing Service. Call this before any usage of
* GES. You should take care of initilizing GStreamer before calling this * GES. You should take care of initilizing GStreamer before calling this
* function. * function.
*
* MT safety.
* GStreamer Editing Services do not guarantee MT safety.
* An application is required to use GES APIs (including ges_deinit())
* in the thread where ges_init() was called.
*/ */
gboolean gboolean
@ -170,8 +178,9 @@ ges_init (void)
* It is normally not needed to call this function in a normal application as the * It is normally not needed to call this function in a normal application as the
* resources will automatically be freed when the program terminates. * resources will automatically be freed when the program terminates.
* This function is therefore mostly used by testsuites and other memory profiling tools. * This function is therefore mostly used by testsuites and other memory profiling tools.
* This function should be called from the thread where ges_init() was called.
* *
* After this call GES (including this method) should not be used anymore. * After this call GES should not be used until another ges_init() call.
*/ */
void void
ges_deinit (void) ges_deinit (void)
@ -180,12 +189,15 @@ ges_deinit (void)
GST_INFO ("deinitializing GES"); GST_INFO ("deinitializing GES");
if (!ges_initialized) { if (!initialized_thread) {
GST_DEBUG ("nothing to deinitialize"); GST_DEBUG ("nothing to deinitialize");
G_UNLOCK (init_lock); G_UNLOCK (init_lock);
return; return;
} }
/* Allow deinit only from a thread where ges_init() was called */
g_assert (initialized_thread == g_thread_self ());
_ges_uri_asset_cleanup (); _ges_uri_asset_cleanup ();
g_type_class_unref (g_type_class_peek (GES_TYPE_TEST_CLIP)); g_type_class_unref (g_type_class_peek (GES_TYPE_TEST_CLIP));
@ -210,7 +222,7 @@ ges_deinit (void)
ges_asset_cache_deinit (); ges_asset_cache_deinit ();
ges_initialized = FALSE; initialized_thread = NULL;
G_UNLOCK (init_lock); G_UNLOCK (init_lock);
GST_INFO ("deinitialized GES"); GST_INFO ("deinitialized GES");
@ -335,7 +347,7 @@ ges_init_check (int *argc, char **argv[], GError ** err)
G_LOCK (init_lock); G_LOCK (init_lock);
if (ges_initialized) { if (initialized_thread) {
GST_DEBUG ("already initialized ges"); GST_DEBUG ("already initialized ges");
G_UNLOCK (init_lock); G_UNLOCK (init_lock);
return TRUE; return TRUE;
@ -374,5 +386,5 @@ ges_init_check (int *argc, char **argv[], GError ** err)
gboolean gboolean
ges_is_initialized (void) ges_is_initialized (void)
{ {
return ges_initialized; return initialized_thread ? TRUE : FALSE;
} }