d3d11memory: Don't clear wrapped texture memory
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst-libs / gst / d3d11 / gstd3d11memory.cpp
index 21262d1..a593701 100644 (file)
 #include "gstd3d11memory.h"
 #include "gstd3d11device.h"
 #include "gstd3d11utils.h"
-#include "gstd3d11_private.h"
+#include "gstd3d11-private.h"
+
+/**
+ * SECTION:gstd3d11memory
+ * @title: GstD3D11Memory
+ * @short_description: Direct3D11 memory abstraction layer
+ *
+ * Since: 1.22
+ */
 
 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug);
 #define GST_CAT_DEFAULT gst_d3d11_allocator_debug
 
-static GstAllocator *_d3d11_memory_allocator;
+static GstD3D11Allocator *_d3d11_memory_allocator;
+
+GType
+gst_d3d11_allocation_flags_get_type (void)
+{
+  static GType type = 0;
+  static const GFlagsValue values[] = {
+    {GST_D3D11_ALLOCATION_FLAG_DEFAULT, "GST_D3D11_ALLOCATION_FLAG_DEFAULT",
+        "default"},
+    {GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY,
+        "GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY", "texture-array"},
+    {0, nullptr, nullptr}
+  };
+
+  GST_D3D11_CALL_ONCE_BEGIN {
+    type = g_flags_register_static ("GstD3D11AllocationFlags", values);
+  } GST_D3D11_CALL_ONCE_END;
+
+  return type;
+}
+
+GType
+gst_d3d11_memory_transfer_get_type (void)
+{
+  static GType type = 0;
+  static const GFlagsValue values[] = {
+    {GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD,
+        "GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD", "need-download"},
+    {GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD,
+        "GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD", "need-upload"},
+    {0, nullptr, nullptr}
+  };
+
+  GST_D3D11_CALL_ONCE_BEGIN {
+    type = g_flags_register_static ("GstD3D11MemoryTransfer", values);
+  } GST_D3D11_CALL_ONCE_END;
+
+  return type;
+}
+
+GType
+gst_d3d11_memory_native_type_get_type (void)
+{
+  static GType type = 0;
+  static const GEnumValue values[] = {
+    {GST_D3D11_MEMORY_NATIVE_TYPE_INVALID,
+        "GST_D3D11_MEMORY_NATIVE_TYPE_INVALID", "invalid"},
+    {GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER, "GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER",
+        "buffer"},
+    {GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D,
+        "GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D", "texture-2d"},
+    {0, nullptr, nullptr}
+  };
+
+  GST_D3D11_CALL_ONCE_BEGIN {
+    type = g_enum_register_static ("GstD3D11MemoryNativeType", values);
+  } GST_D3D11_CALL_ONCE_END;
+
+  return type;
+}
 
 /* GstD3D11AllocationParams */
 static void gst_d3d11_allocation_params_init (GType type);
@@ -46,19 +113,21 @@ G_DEFINE_BOXED_TYPE_WITH_CODE (GstD3D11AllocationParams,
  * @device: a #GstD3D11Device
  * @info: a #GstVideoInfo
  * @flags: a #GstD3D11AllocationFlags
- * @bind_flags: D3D11_BIND_FLAG value used for creating Direct3D11 texture
+ * @bind_flags: D3D11_BIND_FLAG value used for creating texture
+ * @misc_flags: D3D11_RESOURCE_MISC_FLAG value used for creating texture
  *
  * Create #GstD3D11AllocationParams object which is used by #GstD3D11BufferPool
  * and #GstD3D11Allocator in order to allocate new ID3D11Texture2D
  * object with given configuration
  *
- * Returns: a #GstD3D11AllocationParams or %NULL if @info is not supported
+ * Returns: (transfer full) (nullable): a #GstD3D11AllocationParams or %NULL if @info is not supported
  *
- * Since: 1.20
+ * Since: 1.22
  */
 GstD3D11AllocationParams *
-gst_d3d11_allocation_params_new (GstD3D11Device * device, GstVideoInfo * info,
-    GstD3D11AllocationFlags flags, guint bind_flags)
+gst_d3d11_allocation_params_new (GstD3D11Device * device,
+    const GstVideoInfo * info, GstD3D11AllocationFlags flags, guint bind_flags,
+    guint misc_flags)
 {
   GstD3D11AllocationParams *ret;
   GstD3D11Format d3d11_format;
@@ -105,6 +174,7 @@ gst_d3d11_allocation_params_new (GstD3D11Device * device, GstVideoInfo * info,
       ret->desc[i].SampleDesc.Quality = 0;
       ret->desc[i].Usage = D3D11_USAGE_DEFAULT;
       ret->desc[i].BindFlags = bind_flags;
+      ret->desc[i].MiscFlags = misc_flags;
     }
   } else {
     ret->desc[0].Width = GST_VIDEO_INFO_WIDTH (info);
@@ -116,6 +186,7 @@ gst_d3d11_allocation_params_new (GstD3D11Device * device, GstVideoInfo * info,
     ret->desc[0].SampleDesc.Quality = 0;
     ret->desc[0].Usage = D3D11_USAGE_DEFAULT;
     ret->desc[0].BindFlags = bind_flags;
+    ret->desc[0].MiscFlags = misc_flags;
   }
 
   ret->flags = flags;
@@ -133,11 +204,11 @@ gst_d3d11_allocation_params_new (GstD3D11Device * device, GstVideoInfo * info,
  *
  * Returns: %TRUE if alignment could be applied
  *
- * Since: 1.20
+ * Since: 1.22
  */
 gboolean
 gst_d3d11_allocation_params_alignment (GstD3D11AllocationParams * params,
-    GstVideoAlignment * align)
+    const GstVideoAlignment * align)
 {
   guint i;
   guint padding_width, padding_height;
@@ -174,9 +245,9 @@ gst_d3d11_allocation_params_alignment (GstD3D11AllocationParams * params,
  * gst_d3d11_allocation_params_copy:
  * @src: a #GstD3D11AllocationParams
  *
- * Returns: a copy of @src
+ * Returns: (transfer full): a copy of @src
  *
- * Since: 1.20
+ * Since: 1.22
  */
 GstD3D11AllocationParams *
 gst_d3d11_allocation_params_copy (GstD3D11AllocationParams * src)
@@ -197,7 +268,7 @@ gst_d3d11_allocation_params_copy (GstD3D11AllocationParams * src)
  *
  * Free @params
  *
- * Since: 1.20
+ * Since: 1.22
  */
 void
 gst_d3d11_allocation_params_free (GstD3D11AllocationParams * params)
@@ -232,29 +303,26 @@ gst_d3d11_allocation_params_init (GType type)
 
 /* GstD3D11Memory */
 #define GST_D3D11_MEMORY_GET_LOCK(m) (&(GST_D3D11_MEMORY_CAST(m)->priv->lock))
-#define GST_D3D11_MEMORY_LOCK(m) G_STMT_START { \
-  GST_TRACE("Locking %p from thread %p", (m), g_thread_self()); \
-  g_mutex_lock(GST_D3D11_MEMORY_GET_LOCK(m)); \
-  GST_TRACE("Locked %p from thread %p", (m), g_thread_self()); \
-} G_STMT_END
-
-#define GST_D3D11_MEMORY_UNLOCK(m) G_STMT_START { \
-  GST_TRACE("Unlocking %p from thread %p", (m), g_thread_self()); \
-  g_mutex_unlock(GST_D3D11_MEMORY_GET_LOCK(m)); \
-} G_STMT_END
 
 struct _GstD3D11MemoryPrivate
 {
   ID3D11Texture2D *texture;
   ID3D11Buffer *buffer;
 
-  ID3D11Resource *staging;
+  GstD3D11MemoryNativeType native_type;
 
   D3D11_TEXTURE2D_DESC desc;
   D3D11_BUFFER_DESC buffer_desc;
 
   guint subresource_index;
 
+  /* protected by device lock */
+  ID3D11Resource *staging;
+  D3D11_MAPPED_SUBRESOURCE map;
+  gint cpu_map_count;
+
+  /* protects resource objects */
+  SRWLOCK lock;
   ID3D11ShaderResourceView *shader_resource_view[GST_VIDEO_MAX_PLANES];
   guint num_shader_resource_views;
 
@@ -262,15 +330,13 @@ struct _GstD3D11MemoryPrivate
   guint num_render_target_views;
 
   ID3D11VideoDecoderOutputView *decoder_output_view;
+  ID3D11VideoDecoder *decoder_handle;
+
   ID3D11VideoProcessorInputView *processor_input_view;
   ID3D11VideoProcessorOutputView *processor_output_view;
 
-  D3D11_MAPPED_SUBRESOURCE map;
-
-  GstD3D11MemoryNativeType native_type;
-
-  GMutex lock;
-  gint cpu_map_count;
+  GDestroyNotify notify;
+  gpointer user_data;
 };
 
 static inline D3D11_MAP
@@ -373,10 +439,7 @@ gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
   GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
   GstD3D11MemoryPrivate *priv = dmem->priv;
   GstMapFlags flags = info->flags;
-  gpointer ret = NULL;
-
-  gst_d3d11_device_lock (dmem->device);
-  GST_D3D11_MEMORY_LOCK (dmem);
+  GstD3D11DeviceLockGuard lk (dmem->device);
 
   memset (info->user_data, 0, sizeof (info->user_data));
   info->user_data[0] = GUINT_TO_POINTER (dmem->priv->subresource_index);
@@ -385,7 +448,7 @@ gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
     if (priv->native_type == GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER) {
       /* FIXME: handle non-staging buffer */
       g_assert (priv->buffer != nullptr);
-      ret = priv->buffer;
+      return priv->buffer;
     } else {
       gst_d3d11_memory_upload (dmem);
       GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
@@ -395,8 +458,7 @@ gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
             GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
 
       g_assert (priv->texture != NULL);
-      ret = priv->texture;
-      goto out;
+      return priv->texture;
     }
   }
 
@@ -411,7 +473,7 @@ gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
             &priv->desc);
         if (!priv->staging) {
           GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
-          goto out;
+          return nullptr;
         }
 
         /* first memory, always need download to staging */
@@ -424,7 +486,7 @@ gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
     map_type = gst_d3d11_map_flags_to_d3d11 (flags);
     if (!gst_d3d11_memory_map_cpu_access (dmem, map_type)) {
       GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
-      goto out;
+      return nullptr;
     }
   }
 
@@ -435,13 +497,7 @@ gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
   GST_MEMORY_FLAG_UNSET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
 
   priv->cpu_map_count++;
-  ret = dmem->priv->map.pData;
-
-out:
-  GST_D3D11_MEMORY_UNLOCK (dmem);
-  gst_d3d11_device_unlock (dmem->device);
-
-  return ret;
+  return dmem->priv->map.pData;
 }
 
 /* Must be called with d3d11 device lock */
@@ -460,15 +516,13 @@ gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
 {
   GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
   GstD3D11MemoryPrivate *priv = dmem->priv;
-
-  gst_d3d11_device_lock (dmem->device);
-  GST_D3D11_MEMORY_LOCK (dmem);
+  GstD3D11DeviceLockGuard lk (dmem->device);
 
   if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
     if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
       GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
 
-    goto out;
+    return;
   }
 
   if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
@@ -476,13 +530,9 @@ gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
 
   priv->cpu_map_count--;
   if (priv->cpu_map_count > 0)
-    goto out;
+    return;
 
   gst_d3d11_memory_unmap_cpu_access (dmem);
-
-out:
-  GST_D3D11_MEMORY_UNLOCK (dmem);
-  gst_d3d11_device_unlock (dmem->device);
 }
 
 static GstMemory *
@@ -501,7 +551,6 @@ gst_d3d11_memory_update_size (GstMemory * mem)
   gint stride[GST_VIDEO_MAX_PLANES];
   gsize size;
   D3D11_TEXTURE2D_DESC *desc = &priv->desc;
-  gboolean ret = FALSE;
 
   if (!priv->staging) {
     priv->staging = gst_d3d11_allocate_staging_texture (dmem->device,
@@ -510,11 +559,9 @@ gst_d3d11_memory_update_size (GstMemory * mem)
       GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
       return FALSE;
     }
-
-    GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
   }
 
-  gst_d3d11_device_lock (dmem->device);
+  GstD3D11DeviceLockGuard lk (dmem->device);
   if (!gst_d3d11_memory_map_cpu_access (dmem, D3D11_MAP_READ_WRITE)) {
     GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
     return FALSE;
@@ -525,15 +572,14 @@ gst_d3d11_memory_update_size (GstMemory * mem)
   if (!gst_d3d11_dxgi_format_get_size (desc->Format, desc->Width, desc->Height,
           priv->map.RowPitch, offset, stride, &size)) {
     GST_ERROR_OBJECT (mem->allocator, "Couldn't calculate memory size");
-    goto out;
+    GST_D3D11_CLEAR_COM (priv->staging);
+    return FALSE;
   }
 
+  GST_D3D11_CLEAR_COM (priv->staging);
   mem->maxsize = mem->size = size;
-  ret = TRUE;
 
-out:
-  gst_d3d11_device_unlock (dmem->device);
-  return ret;
+  return TRUE;
 }
 
 /**
@@ -542,7 +588,7 @@ out:
  *
  * Returns: whether @mem is a #GstD3D11Memory
  *
- * Since: 1.20
+ * Since: 1.22
  */
 gboolean
 gst_is_d3d11_memory (GstMemory * mem)
@@ -576,32 +622,30 @@ gst_d3d11_memory_get_native_type (GstD3D11Memory * mem)
  * this function multiple times. This must be called before any other
  * GstD3D11Memory operation.
  *
- * Since: 1.20
+ * Since: 1.22
  */
 void
 gst_d3d11_memory_init_once (void)
 {
-  static gsize _init = 0;
-
-  if (g_once_init_enter (&_init)) {
-
+  GST_D3D11_CALL_ONCE_BEGIN {
     GST_DEBUG_CATEGORY_INIT (gst_d3d11_allocator_debug, "d3d11allocator", 0,
         "Direct3D11 Texture Allocator");
 
     _d3d11_memory_allocator =
-        (GstAllocator *) g_object_new (GST_TYPE_D3D11_ALLOCATOR, NULL);
+        (GstD3D11Allocator *) g_object_new (GST_TYPE_D3D11_ALLOCATOR, NULL);
     gst_object_ref_sink (_d3d11_memory_allocator);
+    gst_object_ref (_d3d11_memory_allocator);
 
-    gst_allocator_register (GST_D3D11_MEMORY_NAME, _d3d11_memory_allocator);
-    g_once_init_leave (&_init, 1);
-  }
+    gst_allocator_register (GST_D3D11_MEMORY_NAME,
+        GST_ALLOCATOR_CAST (_d3d11_memory_allocator));
+  } GST_D3D11_CALL_ONCE_END;
 }
 
 /**
  * gst_d3d11_memory_get_resource_handle:
  * @mem: a #GstD3D11Memory
  *
- * Returns: (transfer none): a ID3D11Resource handle. Caller must not release
+ * Returns: (transfer none) (nullable): a ID3D11Resource handle. Caller must not release
  * returned handle.
  *
  * Since: 1.22
@@ -629,7 +673,7 @@ gst_d3d11_memory_get_resource_handle (GstD3D11Memory * mem)
  *
  * Returns: subresource index corresponding to @mem.
  *
- * Since: 1.20
+ * Since: 1.22
  */
 guint
 gst_d3d11_memory_get_subresource_index (GstD3D11Memory * mem)
@@ -651,7 +695,7 @@ gst_d3d11_memory_get_subresource_index (GstD3D11Memory * mem)
  *
  * Returns: %TRUE if successeed
  *
- * Since: 1.20
+ * Since: 1.22
  */
 gboolean
 gst_d3d11_memory_get_texture_desc (GstD3D11Memory * mem,
@@ -776,7 +820,6 @@ static gboolean
 gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
 {
   GstD3D11MemoryPrivate *priv = mem->priv;
-  gboolean ret = FALSE;
 
   if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
     return FALSE;
@@ -787,18 +830,11 @@ gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
     return FALSE;
   }
 
-  GST_D3D11_MEMORY_LOCK (mem);
-  if (priv->num_shader_resource_views) {
-    ret = TRUE;
-    goto done;
-  }
-
-  ret = create_shader_resource_views (mem);
-
-done:
-  GST_D3D11_MEMORY_UNLOCK (mem);
+  GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
+  if (priv->num_shader_resource_views)
+    return TRUE;
 
-  return ret;
+  return create_shader_resource_views (mem);
 }
 
 /**
@@ -808,7 +844,7 @@ done:
  * Returns: the number of ID3D11ShaderResourceView that can be used
  * for processing GPU operation with @mem
  *
- * Since: 1.20
+ * Since: 1.22
  */
 guint
 gst_d3d11_memory_get_shader_resource_view_size (GstD3D11Memory * mem)
@@ -830,7 +866,7 @@ gst_d3d11_memory_get_shader_resource_view_size (GstD3D11Memory * mem)
  * ID3D11ShaderResourceView or %NULL if ID3D11ShaderResourceView is unavailable
  * for @index
  *
- * Since: 1.20
+ * Since: 1.22
  */
 ID3D11ShaderResourceView *
 gst_d3d11_memory_get_shader_resource_view (GstD3D11Memory * mem, guint index)
@@ -914,7 +950,6 @@ static gboolean
 gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
 {
   GstD3D11MemoryPrivate *priv = mem->priv;
-  gboolean ret = FALSE;
 
   if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
     return FALSE;
@@ -925,18 +960,11 @@ gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
     return FALSE;
   }
 
-  GST_D3D11_MEMORY_LOCK (mem);
-  if (priv->num_render_target_views) {
-    ret = TRUE;
-    goto done;
-  }
-
-  ret = create_render_target_views (mem);
-
-done:
-  GST_D3D11_MEMORY_UNLOCK (mem);
+  GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
+  if (priv->num_render_target_views)
+    return TRUE;
 
-  return ret;
+  return create_render_target_views (mem);
 }
 
 /**
@@ -946,7 +974,7 @@ done:
  * Returns: the number of ID3D11RenderTargetView that can be used
  * for processing GPU operation with @mem
  *
- * Since: 1.20
+ * Since: 1.22
  */
 guint
 gst_d3d11_memory_get_render_target_view_size (GstD3D11Memory * mem)
@@ -968,7 +996,7 @@ gst_d3d11_memory_get_render_target_view_size (GstD3D11Memory * mem)
  * ID3D11RenderTargetView or %NULL if ID3D11RenderTargetView is unavailable
  * for @index
  *
- * Since: 1.20
+ * Since: 1.22
  */
 ID3D11RenderTargetView *
 gst_d3d11_memory_get_render_target_view (GstD3D11Memory * mem, guint index)
@@ -992,13 +1020,13 @@ gst_d3d11_memory_get_render_target_view (GstD3D11Memory * mem, guint index)
 
 static gboolean
 gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
-    ID3D11VideoDevice * video_device, GUID * decoder_profile)
+    ID3D11VideoDevice * video_device, ID3D11VideoDecoder * decoder,
+    const GUID * decoder_profile)
 {
   GstD3D11MemoryPrivate *dmem_priv = mem->priv;
   GstD3D11Allocator *allocator;
   D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC desc;
   HRESULT hr;
-  gboolean ret = FALSE;
 
   if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
     return FALSE;
@@ -1011,22 +1039,21 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
     return FALSE;
   }
 
-  GST_D3D11_MEMORY_LOCK (mem);
+  GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
   if (dmem_priv->decoder_output_view) {
     dmem_priv->decoder_output_view->GetDesc (&desc);
-    if (IsEqualGUID (desc.DecodeProfile, *decoder_profile)) {
-      goto succeeded;
+    if (IsEqualGUID (desc.DecodeProfile, *decoder_profile) &&
+        dmem_priv->decoder_handle == decoder) {
+      return TRUE;
     } else {
       /* Shouldn't happen, but try again anyway */
       GST_WARNING_OBJECT (allocator,
           "Existing view has different decoder profile");
       GST_D3D11_CLEAR_COM (dmem_priv->decoder_output_view);
+      GST_D3D11_CLEAR_COM (dmem_priv->decoder_handle);
     }
   }
 
-  if (dmem_priv->decoder_output_view)
-    goto succeeded;
-
   desc.DecodeProfile = *decoder_profile;
   desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
   desc.Texture2D.ArraySlice = dmem_priv->subresource_index;
@@ -1036,38 +1063,43 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
   if (!gst_d3d11_result (hr, mem->device)) {
     GST_ERROR_OBJECT (allocator,
         "Could not create decoder output view, hr: 0x%x", (guint) hr);
-    goto done;
+    return FALSE;
   }
 
-succeeded:
-  ret = TRUE;
-
-done:
-  GST_D3D11_MEMORY_UNLOCK (mem);
+  /* XXX: decoder output view is bound to video device, not decoder handle
+   * from API point of view. But some driver seems to be unhappy
+   * when decoder handle is released while there are outstanding view objects */
+  dmem_priv->decoder_handle = decoder;
+  decoder->AddRef ();
 
-  return ret;
+  return TRUE;
 }
 
 /**
  * gst_d3d11_memory_get_decoder_output_view:
  * @mem: a #GstD3D11Memory
+ * @video_device: (transfer none): a ID3D11VideoDevice handle
+ * @decoder: (transfer none): a ID3D11VideoDecoder handle
+ * @decoder_profile: a DXVA decoder profile GUID
  *
  * Returns: (transfer none) (nullable): a pointer to the
  * ID3D11VideoDecoderOutputView or %NULL if ID3D11VideoDecoderOutputView is
  * unavailable
  *
- * Since: 1.20
+ * Since: 1.22
  */
 ID3D11VideoDecoderOutputView *
 gst_d3d11_memory_get_decoder_output_view (GstD3D11Memory * mem,
-    ID3D11VideoDevice * video_device, GUID * decoder_profile)
+    ID3D11VideoDevice * video_device, ID3D11VideoDecoder * decoder,
+    const GUID * decoder_profile)
 {
   g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
   g_return_val_if_fail (video_device != NULL, NULL);
+  g_return_val_if_fail (decoder != NULL, NULL);
   g_return_val_if_fail (decoder_profile != NULL, NULL);
 
   if (!gst_d3d11_memory_ensure_decoder_output_view (mem,
-          video_device, decoder_profile))
+          video_device, decoder, decoder_profile))
     return NULL;
 
   return mem->priv->decoder_output_view;
@@ -1098,7 +1130,6 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
   GstD3D11Allocator *allocator;
   D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC desc;
   HRESULT hr;
-  gboolean ret = FALSE;
 
   if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
     return FALSE;
@@ -1111,9 +1142,9 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
     return FALSE;
   }
 
-  GST_D3D11_MEMORY_LOCK (mem);
+  GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
   if (dmem_priv->processor_input_view)
-    goto succeeded;
+    return TRUE;
 
   desc.FourCC = 0;
   desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
@@ -1125,16 +1156,10 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
   if (!gst_d3d11_result (hr, mem->device)) {
     GST_ERROR_OBJECT (allocator,
         "Could not create processor input view, hr: 0x%x", (guint) hr);
-    goto done;
+    return FALSE;
   }
 
-succeeded:
-  ret = TRUE;
-
-done:
-  GST_D3D11_MEMORY_UNLOCK (mem);
-
-  return ret;
+  return TRUE;
 }
 
 /**
@@ -1147,7 +1172,7 @@ done:
  * ID3D11VideoProcessorInputView or %NULL if ID3D11VideoProcessorInputView is
  * unavailable
  *
- * Since: 1.20
+ * Since: 1.22
  */
 ID3D11VideoProcessorInputView *
 gst_d3d11_memory_get_processor_input_view (GstD3D11Memory * mem,
@@ -1174,7 +1199,6 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
   GstD3D11Allocator *allocator;
   D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC desc;
   HRESULT hr;
-  gboolean ret;
 
   if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
     return FALSE;
@@ -1196,9 +1220,9 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
     return FALSE;
   }
 
-  GST_D3D11_MEMORY_LOCK (mem);
+  GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
   if (priv->processor_output_view)
-    goto succeeded;
+    return TRUE;
 
   desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
   desc.Texture2D.MipSlice = 0;
@@ -1208,16 +1232,10 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
   if (!gst_d3d11_result (hr, mem->device)) {
     GST_ERROR_OBJECT (allocator,
         "Could not create processor input view, hr: 0x%x", (guint) hr);
-    goto done;
+    return FALSE;
   }
 
-succeeded:
-  ret = TRUE;
-
-done:
-  GST_D3D11_MEMORY_UNLOCK (mem);
-
-  return ret;
+  return TRUE;
 }
 
 /**
@@ -1230,7 +1248,7 @@ done:
  * ID3D11VideoProcessorOutputView or %NULL if ID3D11VideoProcessorOutputView is
  * unavailable
  *
- * Since: 1.20
+ * Since: 1.22
  */
 ID3D11VideoProcessorOutputView *
 gst_d3d11_memory_get_processor_output_view (GstD3D11Memory * mem,
@@ -1261,7 +1279,8 @@ G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Allocator,
 static GstMemory *gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator,
     gsize size, GstAllocationParams * params);
 static GstMemory *gst_d3d11_allocator_alloc_internal (GstD3D11Allocator * self,
-    GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc);
+    GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
+    ID3D11Texture2D * texture);
 static void gst_d3d11_allocator_free (GstAllocator * allocator,
     GstMemory * mem);
 
@@ -1282,16 +1301,12 @@ gst_d3d11_memory_copy (GstMemory * mem, gssize offset, gssize size)
   GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
   GstD3D11Memory *copy_dmem;
   GstD3D11Device *device = dmem->device;
-  ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
   ID3D11DeviceContext *device_context =
       gst_d3d11_device_get_device_context_handle (device);
   D3D11_TEXTURE2D_DESC dst_desc = { 0, };
   D3D11_TEXTURE2D_DESC src_desc = { 0, };
   GstMemory *copy = NULL;
   GstMapInfo info;
-  HRESULT hr;
-  UINT bind_flags = 0;
-  UINT supported_flags = 0;
 
   if (dmem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
     return priv->fallback_copy (mem, offset, size);
@@ -1302,10 +1317,10 @@ gst_d3d11_memory_copy (GstMemory * mem, gssize offset, gssize size)
     return priv->fallback_copy (mem, offset, size);
   }
 
-  gst_d3d11_device_lock (device);
+  GstD3D11DeviceLockGuard lk (device);
+
   if (!gst_memory_map (mem, &info,
           (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
-    gst_d3d11_device_unlock (device);
 
     GST_WARNING_OBJECT (alloc, "Failed to map memory, try fallback copy");
 
@@ -1320,25 +1335,11 @@ gst_d3d11_memory_copy (GstMemory * mem, gssize offset, gssize size)
   dst_desc.SampleDesc.Count = 1;
   dst_desc.ArraySize = 1;
   dst_desc.Usage = D3D11_USAGE_DEFAULT;
+  dst_desc.BindFlags = src_desc.BindFlags;
 
-  /* If supported, use bind flags for SRV/RTV */
-  hr = device_handle->CheckFormatSupport (src_desc.Format, &supported_flags);
-  if (gst_d3d11_result (hr, device)) {
-    if ((supported_flags & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) ==
-        D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) {
-      bind_flags |= D3D11_BIND_SHADER_RESOURCE;
-    }
-
-    if ((supported_flags & D3D11_FORMAT_SUPPORT_RENDER_TARGET) ==
-        D3D11_FORMAT_SUPPORT_RENDER_TARGET) {
-      bind_flags |= D3D11_BIND_RENDER_TARGET;
-    }
-  }
-
-  copy = gst_d3d11_allocator_alloc_internal (alloc, device, &dst_desc);
+  copy = gst_d3d11_allocator_alloc_internal (alloc, device, &dst_desc, nullptr);
   if (!copy) {
     gst_memory_unmap (mem, &info);
-    gst_d3d11_device_unlock (device);
 
     GST_WARNING_OBJECT (alloc,
         "Failed to allocate new d3d11 map memory, try fallback copy");
@@ -1351,7 +1352,6 @@ gst_d3d11_memory_copy (GstMemory * mem, gssize offset, gssize size)
       dmem->priv->texture, dmem->priv->subresource_index, NULL);
   copy->maxsize = copy->size = mem->maxsize;
   gst_memory_unmap (mem, &info);
-  gst_d3d11_device_unlock (device);
 
   /* newly allocated memory holds valid image data. We need download this
    * pixel data into staging memory for CPU access */
@@ -1409,14 +1409,19 @@ gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
   GST_D3D11_CLEAR_COM (dmem_priv->staging);
   GST_D3D11_CLEAR_COM (dmem_priv->buffer);
 
+  GST_D3D11_CLEAR_COM (dmem_priv->decoder_handle);
+
   gst_clear_object (&dmem->device);
-  g_mutex_clear (&dmem_priv->lock);
+
+  if (dmem_priv->notify)
+    dmem_priv->notify (dmem_priv->user_data);
+
   g_free (dmem->priv);
   g_free (dmem);
 }
 
 static GstMemory *
-gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * self,
+gst_d3d11_allocator_alloc_wrapped_internal (GstD3D11Allocator * self,
     GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
     ID3D11Texture2D * texture)
 {
@@ -1427,7 +1432,6 @@ gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * self,
 
   gst_memory_init (GST_MEMORY_CAST (mem),
       (GstMemoryFlags) 0, GST_ALLOCATOR_CAST (self), NULL, 0, 0, 0, 0);
-  g_mutex_init (&mem->priv->lock);
   mem->priv->texture = texture;
   mem->priv->desc = *desc;
   mem->priv->native_type = GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D;
@@ -1436,34 +1440,103 @@ gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * self,
   return GST_MEMORY_CAST (mem);
 }
 
+typedef void (*GstD3D11ClearRTVFunc) (ID3D11DeviceContext * context_handle,
+    ID3D11RenderTargetView * rtv);
+
+static void
+clear_rtv_chroma (ID3D11DeviceContext * context_handle,
+    ID3D11RenderTargetView * rtv)
+{
+  const FLOAT clear_color[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
+
+  context_handle->ClearRenderTargetView (rtv, clear_color);
+}
+
+static void
+clear_rtv_vuya (ID3D11DeviceContext * context_handle,
+    ID3D11RenderTargetView * rtv)
+{
+  const FLOAT clear_color[4] = { 0.5f, 0.5f, 0.0f, 1.0f };
+
+  context_handle->ClearRenderTargetView (rtv, clear_color);
+}
+
 static GstMemory *
 gst_d3d11_allocator_alloc_internal (GstD3D11Allocator * self,
-    GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc)
+    GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
+    ID3D11Texture2D * texture)
 {
-  ID3D11Texture2D *texture = NULL;
   ID3D11Device *device_handle;
+  ID3D11DeviceContext *context_handle;
   HRESULT hr;
+  GstMemory *mem;
+  GstD3D11Memory *dmem;
+  ID3D11RenderTargetView *rtv = nullptr;
+  GstD3D11ClearRTVFunc clear_func = nullptr;
+  gboolean is_new_texture = TRUE;
 
   device_handle = gst_d3d11_device_get_device_handle (device);
 
-  hr = device_handle->CreateTexture2D (desc, NULL, &texture);
-  if (!gst_d3d11_result (hr, device)) {
-    GST_ERROR_OBJECT (self, "Couldn't create texture");
-    return NULL;
+  if (!texture) {
+    hr = device_handle->CreateTexture2D (desc, nullptr, &texture);
+    if (!gst_d3d11_result (hr, device)) {
+      GST_ERROR_OBJECT (self, "Couldn't create texture");
+      return nullptr;
+    }
+  } else {
+    is_new_texture = FALSE;
   }
 
-  return gst_d3d11_allocator_alloc_wrapped (self, device, desc, texture);
+  mem =
+      gst_d3d11_allocator_alloc_wrapped_internal (self, device, desc, texture);
+  if (!mem)
+    return nullptr;
+
+  /* Don't clear external texture */
+  if (!is_new_texture)
+    return mem;
+
+  /* Clear with YUV black if needed and possible
+   * TODO: do this using UAV if RTV is not allowed (e.g., packed YUV formats) */
+  if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) == 0)
+    return mem;
+
+  dmem = GST_D3D11_MEMORY_CAST (mem);
+  switch (desc->Format) {
+    case DXGI_FORMAT_NV12:
+    case DXGI_FORMAT_P010:
+    case DXGI_FORMAT_P016:
+      /* Y component will be zero already */
+      rtv = gst_d3d11_memory_get_render_target_view (dmem, 1);
+      clear_func = (GstD3D11ClearRTVFunc) clear_rtv_chroma;
+      break;
+    case DXGI_FORMAT_AYUV:
+      rtv = gst_d3d11_memory_get_render_target_view (dmem, 0);
+      clear_func = (GstD3D11ClearRTVFunc) clear_rtv_vuya;
+      break;
+    default:
+      return mem;
+  }
+
+  if (!rtv)
+    return mem;
+
+  context_handle = gst_d3d11_device_get_device_context_handle (device);
+  GstD3D11DeviceLockGuard lk (device);
+  clear_func (context_handle, rtv);
+
+  return mem;
 }
 
 /**
  * gst_d3d11_allocator_alloc:
- * @allocator: a #GstD3D11Allocator
- * @device: a #GstD3D11Device
+ * @allocator: (transfer none) (allow-none): a #GstD3D11Allocator
+ * @device: (transfer none): a #GstD3D11Device
  * @desc: a D3D11_TEXTURE2D_DESC struct
  *
- * Returns: a newly allocated #GstD3D11Memory with given parameters.
+ * Returns: (transfer full) (nullable): a newly allocated #GstD3D11Memory with given parameters.
  *
- * Since: 1.20
+ * Since: 1.22
  */
 GstMemory *
 gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
@@ -1471,11 +1544,16 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
 {
   GstMemory *mem;
 
+  if (!allocator) {
+    gst_d3d11_memory_init_once ();
+    allocator = _d3d11_memory_allocator;
+  }
+
   g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
   g_return_val_if_fail (desc != NULL, NULL);
 
-  mem = gst_d3d11_allocator_alloc_internal (allocator, device, desc);
+  mem = gst_d3d11_allocator_alloc_internal (allocator, device, desc, nullptr);
   if (!mem)
     return NULL;
 
@@ -1490,11 +1568,11 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
 
 /**
  * gst_d3d11_allocator_alloc_buffer:
- * @allocator: a #GstD3D11Allocator
- * @device: a #GstD3D11Device
+ * @allocator: (transfer none) (allow-none): a #GstD3D11Allocator
+ * @device: (transfer none): a #GstD3D11Device
  * @desc: a D3D11_BUFFER_DESC struct
  *
- * Returns: a newly allocated #GstD3D11Memory with given parameters.
+ * Returns: (transfer full) (nullable): a newly allocated #GstD3D11Memory with given parameters.
  *
  * Since: 1.22
  */
@@ -1507,6 +1585,11 @@ gst_d3d11_allocator_alloc_buffer (GstD3D11Allocator * allocator,
   ID3D11Device *device_handle;
   HRESULT hr;
 
+  if (!allocator) {
+    gst_d3d11_memory_init_once ();
+    allocator = _d3d11_memory_allocator;
+  }
+
   g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), nullptr);
   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
   g_return_val_if_fail (desc != nullptr, nullptr);
@@ -1529,7 +1612,6 @@ gst_d3d11_allocator_alloc_buffer (GstD3D11Allocator * allocator,
 
   gst_memory_init (GST_MEMORY_CAST (mem),
       (GstMemoryFlags) 0, GST_ALLOCATOR_CAST (allocator), nullptr, 0, 0, 0, 0);
-  g_mutex_init (&mem->priv->lock);
   mem->priv->buffer = buffer;
   mem->priv->buffer_desc = *desc;
   mem->priv->native_type = GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER;
@@ -1541,6 +1623,98 @@ gst_d3d11_allocator_alloc_buffer (GstD3D11Allocator * allocator,
   return GST_MEMORY_CAST (mem);
 }
 
+/**
+ * gst_d3d11_allocator_alloc_wrapped:
+ * @allocator: (transfer none) (allow-none): a #GstD3D11Allocator
+ * @device: (transfer none): a #GstD3D11Device
+ * @texture: a ID3D11Texture2D
+ * @size: CPU accessible memory size
+ * @user_data: (allow-none): user data
+ * @notify: (allow-none): called with @user_data when the memory is freed
+ *
+ * Allocates memory object with @texture. The refcount of @texture
+ * will be increased by one.
+ *
+ * Caller should set valid CPU acessible memory value to @size
+ * (which is typically calculated by using staging texture and Map/Unmap)
+ * or zero is allowed. In that case, allocator will create a temporary staging
+ * texture to get the size and the temporary staging texture will be released.
+ *
+ * Caller must not be confused that @size is CPU accessible size, not raw
+ * texture size.
+ *
+ * Returns: (transfer full) (nullable): a newly allocated #GstD3D11Memory with given @texture
+ * if successful, or %NULL if @texture is not a valid handle or configuration
+ * is not supported.
+ *
+ * Since: 1.22
+ */
+GstMemory *
+gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * allocator,
+    GstD3D11Device * device, ID3D11Texture2D * texture, gsize size,
+    gpointer user_data, GDestroyNotify notify)
+{
+  GstMemory *mem;
+  GstD3D11Memory *dmem;
+  D3D11_TEXTURE2D_DESC desc = { 0, };
+  ID3D11Texture2D *tex = nullptr;
+  HRESULT hr;
+
+  if (!allocator) {
+    gst_d3d11_memory_init_once ();
+    allocator = _d3d11_memory_allocator;
+  }
+
+  g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), nullptr);
+  g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
+  g_return_val_if_fail (texture != nullptr, nullptr);
+
+  hr = texture->QueryInterface (IID_PPV_ARGS (&tex));
+  if (FAILED (hr)) {
+    GST_WARNING_OBJECT (allocator, "Not a valid texture handle");
+    return nullptr;
+  }
+
+  tex->GetDesc (&desc);
+  mem = gst_d3d11_allocator_alloc_internal (allocator, device, &desc, tex);
+
+  if (!mem)
+    return nullptr;
+
+  if (size == 0) {
+    if (!gst_d3d11_memory_update_size (mem)) {
+      GST_ERROR_OBJECT (allocator, "Failed to calculate size");
+      gst_memory_unref (mem);
+      return nullptr;
+    }
+  } else {
+    mem->maxsize = mem->size = size;
+  }
+
+  dmem = GST_D3D11_MEMORY_CAST (mem);
+
+  dmem->priv->user_data = user_data;
+  dmem->priv->notify = notify;
+
+  return mem;
+}
+
+/**
+ * gst_d3d11_allocator_set_active:
+ * @allocator: a #GstD3D11Allocator
+ * @active: the new active state
+ *
+ * Controls the active state of @allocator. Default #GstD3D11Allocator is
+ * stateless and therefore active state is ignored, but subclass implementation
+ * (e.g., #GstD3D11PoolAllocator) will require explicit active state control
+ * for its internal resource management.
+ *
+ * This method is conceptually identical to gst_buffer_pool_set_active method.
+ *
+ * Returns: %TRUE if active state of @allocator was successfully updated.
+ *
+ * Since: 1.22
+ */
 gboolean
 gst_d3d11_allocator_set_active (GstD3D11Allocator * allocator, gboolean active)
 {
@@ -1549,15 +1723,15 @@ gst_d3d11_allocator_set_active (GstD3D11Allocator * allocator, gboolean active)
   g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), FALSE);
 
   klass = GST_D3D11_ALLOCATOR_GET_CLASS (allocator);
-  if (klass->set_actvie)
-    return klass->set_actvie (allocator, active);
+  if (klass->set_active)
+    return klass->set_active (allocator, active);
 
   return TRUE;
 }
 
 /* GstD3D11PoolAllocator */
-#define GST_D3D11_POOL_ALLOCATOR_LOCK(alloc)   (g_rec_mutex_lock(&alloc->priv->lock))
-#define GST_D3D11_POOL_ALLOCATOR_UNLOCK(alloc) (g_rec_mutex_unlock(&alloc->priv->lock))
+#define GST_D3D11_POOL_ALLOCATOR_GET_LOCK(alloc) \
+  (&(GST_D3D11_POOL_ALLOCATOR_CAST(alloc)->priv->lock))
 #define GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING(alloc)  (g_atomic_int_get (&alloc->priv->flushing))
 
 struct _GstD3D11PoolAllocatorPrivate
@@ -1572,7 +1746,7 @@ struct _GstD3D11PoolAllocatorPrivate
 
   /* This lock will protect all below variables apart from atomic ones
    * (identical to GstBufferPool::priv::rec_lock) */
-  GRecMutex lock;
+  CRITICAL_SECTION lock;
   gboolean started;
   gboolean active;
 
@@ -1588,7 +1762,6 @@ struct _GstD3D11PoolAllocatorPrivate
   gsize mem_size;
 };
 
-static void gst_d3d11_pool_allocator_dispose (GObject * object);
 static void gst_d3d11_pool_allocator_finalize (GObject * object);
 
 static gboolean
@@ -1609,10 +1782,9 @@ gst_d3d11_pool_allocator_class_init (GstD3D11PoolAllocatorClass * klass)
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GstD3D11AllocatorClass *d3d11alloc_class = GST_D3D11_ALLOCATOR_CLASS (klass);
 
-  gobject_class->dispose = gst_d3d11_pool_allocator_dispose;
   gobject_class->finalize = gst_d3d11_pool_allocator_finalize;
 
-  d3d11alloc_class->set_actvie = gst_d3d11_pool_allocator_set_active;
+  d3d11alloc_class->set_active = gst_d3d11_pool_allocator_set_active;
 }
 
 static void
@@ -1622,7 +1794,8 @@ gst_d3d11_pool_allocator_init (GstD3D11PoolAllocator * allocator)
 
   priv = allocator->priv = (GstD3D11PoolAllocatorPrivate *)
       gst_d3d11_pool_allocator_get_instance_private (allocator);
-  g_rec_mutex_init (&priv->lock);
+
+  InitializeCriticalSection (&priv->lock);
 
   priv->poll = gst_poll_new_timer ();
   priv->queue = gst_atomic_queue_new (16);
@@ -1637,16 +1810,6 @@ gst_d3d11_pool_allocator_init (GstD3D11PoolAllocator * allocator)
 }
 
 static void
-gst_d3d11_pool_allocator_dispose (GObject * object)
-{
-  GstD3D11PoolAllocator *self = GST_D3D11_POOL_ALLOCATOR (object);
-
-  gst_clear_object (&self->device);
-
-  G_OBJECT_CLASS (pool_alloc_parent_class)->dispose (object);
-}
-
-static void
 gst_d3d11_pool_allocator_finalize (GObject * object)
 {
   GstD3D11PoolAllocator *self = GST_D3D11_POOL_ALLOCATOR (object);
@@ -1657,10 +1820,12 @@ gst_d3d11_pool_allocator_finalize (GObject * object)
   gst_d3d11_pool_allocator_stop (self);
   gst_atomic_queue_unref (priv->queue);
   gst_poll_free (priv->poll);
-  g_rec_mutex_clear (&priv->lock);
+  DeleteCriticalSection (&priv->lock);
 
   GST_D3D11_CLEAR_COM (priv->texture);
 
+  gst_clear_object (&self->device);
+
   G_OBJECT_CLASS (pool_alloc_parent_class)->finalize (object);
 }
 
@@ -1696,9 +1861,8 @@ gst_d3d11_pool_allocator_start (GstD3D11PoolAllocator * self)
     GstMemory *mem;
 
     priv->texture->AddRef ();
-    mem =
-        gst_d3d11_allocator_alloc_wrapped (GST_D3D11_ALLOCATOR_CAST
-        (_d3d11_memory_allocator), self->device, &priv->desc, priv->texture);
+    mem = gst_d3d11_allocator_alloc_wrapped_internal (_d3d11_memory_allocator,
+        self->device, &priv->desc, priv->texture);
 
     if (i == 0) {
       if (!gst_d3d11_memory_update_size (mem)) {
@@ -1764,14 +1928,16 @@ gst_d3d11_pool_allocator_set_active (GstD3D11Allocator * allocator,
 
   GST_LOG_OBJECT (self, "active %d", active);
 
-  GST_D3D11_POOL_ALLOCATOR_LOCK (self);
+  GstD3D11CSLockGuard lk (GST_D3D11_POOL_ALLOCATOR_GET_LOCK (self));
   /* just return if we are already in the right state */
   if (priv->active == active)
-    goto was_ok;
+    return TRUE;
 
   if (active) {
-    if (!gst_d3d11_pool_allocator_start (self))
-      goto start_failed;
+    if (!gst_d3d11_pool_allocator_start (self)) {
+      GST_ERROR_OBJECT (self, "start failed");
+      return FALSE;
+    }
 
     /* flush_stop may release memory objects, setting to active to avoid running
      * do_stop while activating the pool */
@@ -1790,35 +1956,16 @@ gst_d3d11_pool_allocator_set_active (GstD3D11Allocator * allocator,
     GST_LOG_OBJECT (self, "outstanding memories %d, (in queue %d)",
         outstanding, gst_atomic_queue_length (priv->queue));
     if (outstanding == 0) {
-      if (!gst_d3d11_pool_allocator_stop (self))
-        goto stop_failed;
+      if (!gst_d3d11_pool_allocator_stop (self)) {
+        GST_ERROR_OBJECT (self, "stop failed");
+        return FALSE;
+      }
     }
 
     priv->active = FALSE;
   }
 
-  GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
-
   return TRUE;
-
-was_ok:
-  {
-    GST_DEBUG_OBJECT (self, "allocator was in the right state");
-    GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
-    return TRUE;
-  }
-start_failed:
-  {
-    GST_ERROR_OBJECT (self, "start failed");
-    GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
-    return FALSE;
-  }
-stop_failed:
-  {
-    GST_ERROR_OBJECT (self, "stop failed");
-    GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
-    return FALSE;
-  }
 }
 
 static void
@@ -1891,13 +2038,11 @@ dec_outstanding (GstD3D11PoolAllocator * self)
     /* all memory objects are returned to the pool, see if we need to free them */
     if (GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING (self)) {
       /* take the lock so that set_active is not run concurrently */
-      GST_D3D11_POOL_ALLOCATOR_LOCK (self);
+      GstD3D11CSLockGuard lk (GST_D3D11_POOL_ALLOCATOR_GET_LOCK (self));
       /* now that we have the lock, check if we have been de-activated with
        * outstanding buffers */
       if (!self->priv->active)
         gst_d3d11_pool_allocator_stop (self);
-
-      GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
     }
   }
 }
@@ -1910,12 +2055,13 @@ gst_d3d11_pool_allocator_release_memory (GstD3D11PoolAllocator * self,
 
   GST_MINI_OBJECT_CAST (mem)->dispose = NULL;
   mem->allocator = (GstAllocator *) gst_object_ref (_d3d11_memory_allocator);
-  gst_object_unref (self);
 
   /* keep it around in our queue */
   gst_atomic_queue_push (self->priv->queue, mem);
   gst_poll_write_control (self->priv->poll);
   dec_outstanding (self);
+
+  gst_object_unref (self);
 }
 
 static gboolean
@@ -1957,9 +2103,8 @@ gst_d3d11_pool_allocator_alloc (GstD3D11PoolAllocator * self, GstMemory ** mem)
 
   /* increment the allocation counter */
   g_atomic_int_add (&priv->cur_mems, 1);
-  new_mem =
-      gst_d3d11_allocator_alloc_internal (GST_D3D11_ALLOCATOR_CAST
-      (_d3d11_memory_allocator), self->device, &priv->desc);
+  new_mem = gst_d3d11_allocator_alloc_internal (_d3d11_memory_allocator,
+      self->device, &priv->desc, nullptr);
   if (!new_mem) {
     GST_ERROR_OBJECT (self, "Failed to allocate new memory");
     g_atomic_int_add (&priv->cur_mems, -1);
@@ -2075,6 +2220,8 @@ flushing:
  * Creates a new #GstD3D11PoolAllocator instance.
  *
  * Returns: (transfer full): a new #GstD3D11PoolAllocator instance
+ *
+ * Since: 1.22
  */
 GstD3D11PoolAllocator *
 gst_d3d11_pool_allocator_new (GstD3D11Device * device,
@@ -2100,7 +2247,7 @@ gst_d3d11_pool_allocator_new (GstD3D11Device * device,
 /**
  * gst_d3d11_pool_allocator_acquire_memory:
  * @allocator: a #GstD3D11PoolAllocator
- * @memory: (transfer full): a #GstMemory
+ * @memory: (out): a #GstMemory
  *
  * Acquires a #GstMemory from @allocator. @memory should point to a memory
  * location that can hold a pointer to the new #GstMemory.
@@ -2147,7 +2294,7 @@ gst_d3d11_pool_allocator_acquire_memory (GstD3D11PoolAllocator * allocator,
  *
  * Returns: %TRUE if the size of memory pool is known
  *
- * Since: 1.20
+ * Since: 1.22
  */
 gboolean
 gst_d3d11_pool_allocator_get_pool_size (GstD3D11PoolAllocator * allocator,