dshowdecwrapper: Fix COM initialization
authorJulien MOUTTE <julien@moutte.net>
Mon, 30 May 2011 06:43:59 +0000 (08:43 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 30 May 2011 06:45:01 +0000 (08:45 +0200)
Fixes bug #625190.

sys/dshowdecwrapper/gstdshowaudiodec.cpp
sys/dshowdecwrapper/gstdshowaudiodec.h
sys/dshowdecwrapper/gstdshowvideodec.cpp
sys/dshowdecwrapper/gstdshowvideodec.h

index b4ead24..f10ac8c 100644 (file)
@@ -366,11 +366,47 @@ gst_dshowaudiodec_class_init (GstDshowAudioDecClass * klass)
 }
 
 static void
+gst_dshowaudiodec_com_thread (GstDshowAudioDec * adec)
+{
+  HRESULT res;
+
+  g_mutex_lock (adec->com_init_lock);
+
+  /* Initialize COM with a MTA for this process. This thread will
+   * be the first one to enter the apartement and the last one to leave
+   * it, unitializing COM properly */
+
+  res = CoInitializeEx (0, COINIT_MULTITHREADED);
+  if (res == S_FALSE)
+    GST_WARNING_OBJECT (adec, "COM has been already initialized in the same process");
+  else if (res == RPC_E_CHANGED_MODE)
+    GST_WARNING_OBJECT (adec, "The concurrency model of COM has changed.");
+  else
+    GST_INFO_OBJECT (adec, "COM intialized succesfully");
+
+  adec->comInitialized = TRUE;
+
+  /* Signal other threads waiting on this condition that COM was initialized */
+  g_cond_signal (adec->com_initialized);
+
+  g_mutex_unlock (adec->com_init_lock);
+
+  /* Wait until the unitialize condition is met to leave the COM apartement */
+  g_mutex_lock (adec->com_deinit_lock);
+  g_cond_wait (adec->com_uninitialize, adec->com_deinit_lock);
+
+  CoUninitialize ();
+  GST_INFO_OBJECT (adec, "COM unintialized succesfully");
+  adec->comInitialized = FALSE;
+  g_cond_signal (adec->com_uninitialized);
+  g_mutex_unlock (adec->com_deinit_lock);
+}
+
+static void
 gst_dshowaudiodec_init (GstDshowAudioDec * adec,
     GstDshowAudioDecClass * adec_class)
 {
   GstElementClass *element_class = GST_ELEMENT_GET_CLASS (adec);
-  HRESULT hr;
 
   /* setup pads */
   adec->sinkpad =
@@ -407,10 +443,21 @@ gst_dshowaudiodec_init (GstDshowAudioDec * adec,
 
   adec->last_ret = GST_FLOW_OK;
 
-  hr = CoInitialize (0);
-  if (SUCCEEDED(hr)) {
-    adec->comInitialized = TRUE;
-  }
+  adec->com_init_lock = g_mutex_new();
+  adec->com_deinit_lock = g_mutex_new();
+  adec->com_initialized = g_cond_new();
+  adec->com_uninitialize = g_cond_new();
+  adec->com_uninitialized = g_cond_new();
+
+  g_mutex_lock (adec->com_init_lock);
+
+  /* create the COM initialization thread */
+  g_thread_create ((GThreadFunc)gst_dshowaudiodec_com_thread,
+      adec, FALSE, NULL);
+
+  /* wait until the COM thread signals that COM has been initialized */
+  g_cond_wait (adec->com_initialized, adec->com_init_lock);
+  g_mutex_unlock (adec->com_init_lock);
 }
 
 static void
@@ -428,11 +475,20 @@ gst_dshowaudiodec_dispose (GObject * object)
     adec->codec_data = NULL;
   }
 
+  /* signal the COM thread that it sould uninitialize COM */
   if (adec->comInitialized) {
-    CoUninitialize ();
-    adec->comInitialized = FALSE;
+    g_mutex_lock (adec->com_deinit_lock);
+    g_cond_signal (adec->com_uninitialize);
+    g_cond_wait (adec->com_uninitialized, adec->com_deinit_lock);
+    g_mutex_unlock (adec->com_deinit_lock);
   }
 
+  g_mutex_free (adec->com_init_lock);
+  g_mutex_free (adec->com_deinit_lock);
+  g_cond_free (adec->com_initialized);
+  g_cond_free (adec->com_uninitialize);
+  g_cond_free (adec->com_uninitialized);
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
index 77d7891..5f52cb8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GStreamer DirectShow codecs wrapper
- * Copyright <2006, 2007, 2008> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007, 2008, 2009, 2010> Fluendo <support@fluendo.com>
  * Copyright <2006, 2007, 2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
  * Copyright <2007,2008> Sebastien Moutte <sebastien@moutte.net>
  *
@@ -113,6 +113,11 @@ struct _GstDshowAudioDec
   GstClockTime timestamp;
 
   gboolean comInitialized;
+  GMutex   *com_init_lock;
+  GMutex   *com_deinit_lock;
+  GCond    *com_initialized;
+  GCond    *com_uninitialize;
+  GCond    *com_uninitialized;
 };
 
 struct _GstDshowAudioDecClass
index 0dcc3fa..663e980 100644 (file)
@@ -418,11 +418,47 @@ gst_dshowvideodec_class_init (GstDshowVideoDecClass * klass)
 }
 
 static void
+gst_dshowvideodec_com_thread (GstDshowVideoDec * vdec)
+{
+  HRESULT res;
+
+  g_mutex_lock (vdec->com_init_lock);
+
+  /* Initialize COM with a MTA for this process. This thread will
+   * be the first one to enter the apartement and the last one to leave
+   * it, unitializing COM properly */
+
+  res = CoInitializeEx (0, COINIT_MULTITHREADED);
+  if (res == S_FALSE)
+    GST_WARNING_OBJECT (vdec, "COM has been already initialized in the same process");
+  else if (res == RPC_E_CHANGED_MODE)
+    GST_WARNING_OBJECT (vdec, "The concurrency model of COM has changed.");
+  else
+    GST_INFO_OBJECT (vdec, "COM intialized succesfully");
+
+  vdec->comInitialized = TRUE;
+
+  /* Signal other threads waiting on this condition that COM was initialized */
+  g_cond_signal (vdec->com_initialized);
+
+  g_mutex_unlock (vdec->com_init_lock);
+
+  /* Wait until the unitialize condition is met to leave the COM apartement */
+  g_mutex_lock (vdec->com_deinit_lock);
+  g_cond_wait (vdec->com_uninitialize, vdec->com_deinit_lock);
+
+  CoUninitialize ();
+  GST_INFO_OBJECT (vdec, "COM unintialized succesfully");
+  vdec->comInitialized = FALSE;
+  g_cond_signal (vdec->com_uninitialized);
+  g_mutex_unlock (vdec->com_deinit_lock);
+}
+
+static void
 gst_dshowvideodec_init (GstDshowVideoDec * vdec,
     GstDshowVideoDecClass * vdec_class)
 {
   GstElementClass *element_class = GST_ELEMENT_GET_CLASS (vdec);
-  HRESULT hr;
 
   /* setup pads */
   vdec->sinkpad =
@@ -455,10 +491,21 @@ gst_dshowvideodec_init (GstDshowVideoDec * vdec,
 
   vdec->setup = FALSE;
 
-  hr = CoInitialize (0);
-  if (SUCCEEDED(hr)) {
-    vdec->comInitialized = TRUE;
-  }
+  vdec->com_init_lock = g_mutex_new();
+  vdec->com_deinit_lock = g_mutex_new();
+  vdec->com_initialized = g_cond_new();
+  vdec->com_uninitialize = g_cond_new();
+  vdec->com_uninitialized = g_cond_new();
+
+  g_mutex_lock (vdec->com_init_lock);
+
+  /* create the COM initialization thread */
+  g_thread_create ((GThreadFunc)gst_dshowvideodec_com_thread,
+      vdec, FALSE, NULL);
+
+  /* wait until the COM thread signals that COM has been initialized */
+  g_cond_wait (vdec->com_initialized, vdec->com_init_lock);
+  g_mutex_unlock (vdec->com_init_lock);
 }
 
 static void
@@ -471,11 +518,20 @@ gst_dshowvideodec_dispose (GObject * object)
     vdec->segment = NULL;
   }
 
+  /* signal the COM thread that it sould uninitialize COM */
   if (vdec->comInitialized) {
-    CoUninitialize ();
-    vdec->comInitialized = FALSE;
+    g_mutex_lock (vdec->com_deinit_lock);
+    g_cond_signal (vdec->com_uninitialize);
+    g_cond_wait (vdec->com_uninitialized, vdec->com_deinit_lock);
+    g_mutex_unlock (vdec->com_deinit_lock);
   }
 
+  g_mutex_free (vdec->com_init_lock);
+  g_mutex_free (vdec->com_deinit_lock);
+  g_cond_free (vdec->com_initialized);
+  g_cond_free (vdec->com_uninitialize);
+  g_cond_free (vdec->com_uninitialized);
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
index 4e2d7dc..b5253a6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GStreamer DirectShow codecs wrapper
- * Copyright <2006, 2007, 2008> Fluendo <gstreamer@fluendo.com>
+ * Copyright <2006, 2007, 2008, 2009, 2010> Fluendo <support@fluendo.com>
  * Copyright <2006, 2007, 2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
  * Copyright <2007,2008> Sebastien Moutte <sebastien@moutte.net>
  *
@@ -113,6 +113,11 @@ struct _GstDshowVideoDec
   gboolean setup;
 
   gboolean comInitialized;
+  GMutex   *com_init_lock;
+  GMutex   *com_deinit_lock;
+  GCond    *com_initialized;
+  GCond    *com_uninitialize;
+  GCond    *com_uninitialized;
 };
 
 struct _GstDshowVideoDecClass