diff options
Diffstat (limited to 'sys/msdk/gstmsdkcontext.c')
-rw-r--r-- | sys/msdk/gstmsdkcontext.c | 158 |
1 files changed, 157 insertions, 1 deletions
diff --git a/sys/msdk/gstmsdkcontext.c b/sys/msdk/gstmsdkcontext.c index 696998ea6..352148f87 100644 --- a/sys/msdk/gstmsdkcontext.c +++ b/sys/msdk/gstmsdkcontext.c @@ -58,6 +58,7 @@ struct _GstMsdkContextPrivate gboolean is_joined; GstMsdkContextJobType job_type; gint shared_async_depth; + GMutex mutex; #ifndef _WIN32 gint fd; VADisplay dpy; @@ -208,6 +209,8 @@ gst_msdk_context_init (GstMsdkContext * context) GstMsdkContextPrivate *priv = GST_MSDK_CONTEXT_GET_PRIVATE (context); context->priv = priv; + + g_mutex_init (&priv->mutex); } static void @@ -222,6 +225,7 @@ gst_msdk_context_finalize (GObject * obj) } msdk_close_session (priv->session); + g_mutex_clear (&priv->mutex); #ifndef _WIN32 if (priv->dpy) @@ -365,12 +369,47 @@ gst_msdk_context_get_cached_alloc_responses_by_request (GstMsdkContext * return NULL; } +static void +create_surfaces (GstMsdkContext * context, GstMsdkAllocResponse * resp) +{ + gint i; + mfxMemId *mem_id; + mfxFrameSurface1 *surface; + + for (i = 0; i < resp->response->NumFrameActual; i++) { + mem_id = resp->mem_ids[i]; + surface = (mfxFrameSurface1 *) g_slice_new0 (mfxFrameSurface1); + if (!surface) { + GST_ERROR ("failed to allocate surface"); + break; + } + surface->Data.MemId = mem_id; + resp->surfaces_avail = g_list_prepend (resp->surfaces_avail, surface); + } +} + +static void +free_surface (gpointer surface) +{ + g_slice_free1 (sizeof (mfxFrameSurface1), surface); +} + +static void +remove_surfaces (GstMsdkContext * context, GstMsdkAllocResponse * resp) +{ + g_list_free_full (resp->surfaces_used, free_surface); + g_list_free_full (resp->surfaces_avail, free_surface); + g_list_free_full (resp->surfaces_locked, free_surface); +} + void gst_msdk_context_add_alloc_response (GstMsdkContext * context, GstMsdkAllocResponse * resp) { context->priv->cached_alloc_responses = - g_list_append (context->priv->cached_alloc_responses, resp); + g_list_prepend (context->priv->cached_alloc_responses, resp); + + create_surfaces (context, resp); } gboolean @@ -387,6 +426,8 @@ gst_msdk_context_remove_alloc_response (GstMsdkContext * context, msdk_resp = l->data; + remove_surfaces (context, msdk_resp); + g_slice_free1 (sizeof (GstMsdkAllocResponse), msdk_resp); priv->cached_alloc_responses = g_list_delete_link (priv->cached_alloc_responses, l); @@ -394,6 +435,121 @@ gst_msdk_context_remove_alloc_response (GstMsdkContext * context, return TRUE; } +static gboolean +check_surfaces_available (GstMsdkContext * context, GstMsdkAllocResponse * resp) +{ + GList *l; + mfxFrameSurface1 *surface = NULL; + GstMsdkContextPrivate *priv = context->priv; + gboolean ret = FALSE; + + g_mutex_lock (&priv->mutex); + for (l = resp->surfaces_locked; l; l = l->next) { + surface = l->data; + if (!surface->Data.Locked) { + resp->surfaces_locked = g_list_remove (resp->surfaces_locked, surface); + resp->surfaces_avail = g_list_prepend (resp->surfaces_avail, surface); + ret = TRUE; + } + } + g_mutex_unlock (&priv->mutex); + + return ret; +} + +/* + * There are 3 lists here in GstMsdkContext as the following: + * 1. surfaces_avail : surfaces which are free and unused anywhere + * 2. surfaces_used : surfaces coupled with a gst buffer and being used now. + * 3. surfaces_locked : surfaces still locked even after the gst buffer is released. + * + * Note that they need to be protected by mutex to be thread-safe. + */ + +mfxFrameSurface1 * +gst_msdk_context_get_surface_available (GstMsdkContext * context, + mfxFrameAllocResponse * resp) +{ + GList *l; + mfxFrameSurface1 *surface = NULL; + GstMsdkAllocResponse *msdk_resp = + gst_msdk_context_get_cached_alloc_responses (context, resp); + gint retry = 0; + GstMsdkContextPrivate *priv = context->priv; + +retry: + g_mutex_lock (&priv->mutex); + for (l = msdk_resp->surfaces_avail; l; l = l->next) { + surface = l->data; + + if (!surface->Data.Locked) { + msdk_resp->surfaces_avail = + g_list_remove (msdk_resp->surfaces_avail, surface); + msdk_resp->surfaces_used = + g_list_prepend (msdk_resp->surfaces_used, surface); + break; + } + } + g_mutex_unlock (&priv->mutex); + + /* + * If a msdk context is shared by multiple msdk elements, + * upstream msdk element sometimes needs to wait for a gst buffer + * to be released in downstream. + * + * Poll the pool for a maximum of 20 milisecnds. + * + * FIXME: Is there any better way to handle this case? + */ + if (!surface && retry < 20) { + /* If there's no surface available, find unlocked surfaces in the locked list, + * take it back to the available list and then search again. + */ + check_surfaces_available (context, msdk_resp); + retry++; + g_usleep (1000); + goto retry; + } + + return surface; +} + +void +gst_msdk_context_put_surface_locked (GstMsdkContext * context, + mfxFrameAllocResponse * resp, mfxFrameSurface1 * surface) +{ + GstMsdkContextPrivate *priv = context->priv; + GstMsdkAllocResponse *msdk_resp = + gst_msdk_context_get_cached_alloc_responses (context, resp); + + g_mutex_lock (&priv->mutex); + if (!g_list_find (msdk_resp->surfaces_locked, surface)) { + msdk_resp->surfaces_used = + g_list_remove (msdk_resp->surfaces_used, surface); + msdk_resp->surfaces_locked = + g_list_prepend (msdk_resp->surfaces_locked, surface); + } + g_mutex_unlock (&priv->mutex); +} + +void +gst_msdk_context_put_surface_available (GstMsdkContext * context, + mfxFrameAllocResponse * resp, mfxFrameSurface1 * surface) +{ + GstMsdkContextPrivate *priv = context->priv; + GstMsdkAllocResponse *msdk_resp = + gst_msdk_context_get_cached_alloc_responses (context, resp); + + g_mutex_lock (&priv->mutex); + if (!g_list_find (msdk_resp->surfaces_avail, surface)) { + msdk_resp->surfaces_used = + g_list_remove (msdk_resp->surfaces_used, surface); + msdk_resp->surfaces_avail = + g_list_prepend (msdk_resp->surfaces_avail, surface); + } + g_mutex_unlock (&priv->mutex); +} + GstMsdkContextJobType gst_msdk_context_get_job_type (GstMsdkContext * context) { |