• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer Intel MSDK plugin
2  * Copyright (c) 2018, Intel Corporation
3  * Copyright (c) 2018, Igalia S.L.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of the copyright holder nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGDECE
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "gstmsdkcontext.h"
34 #ifndef _WIN32
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <xf86drm.h>
38 #include <va/va_drm.h>
39 #include <gudev/gudev.h>
40 #endif
41 
42 GST_DEBUG_CATEGORY_STATIC (gst_debug_msdkcontext);
43 #define GST_CAT_DEFAULT gst_debug_msdkcontext
44 
45 struct _GstMsdkContextPrivate
46 {
47   MsdkSession session;
48   GList *cached_alloc_responses;
49   gboolean hardware;
50   gboolean has_frame_allocator;
51   GstMsdkContextJobType job_type;
52   gint shared_async_depth;
53   GMutex mutex;
54   GList *child_session_list;
55   GstMsdkContext *parent_context;
56 #ifndef _WIN32
57   gint fd;
58   VADisplay dpy;
59 #endif
60 };
61 
62 #define gst_msdk_context_parent_class parent_class
63 G_DEFINE_TYPE_WITH_CODE (GstMsdkContext, gst_msdk_context, GST_TYPE_OBJECT,
64     G_ADD_PRIVATE (GstMsdkContext)
65     GST_DEBUG_CATEGORY_INIT (gst_debug_msdkcontext, "msdkcontext", 0,
66         "MSDK Context"));
67 
68 #ifndef _WIN32
69 
70 static gint
get_device_id(void)71 get_device_id (void)
72 {
73   GUdevClient *client = NULL;
74   GUdevEnumerator *e = NULL;
75   GList *devices, *l;
76   GUdevDevice *dev, *parent;
77   const gchar *devnode_path;
78   const gchar *devnode_files[2] = { "renderD[0-9]*", "card[0-9]*" };
79   int fd = -1, i;
80   const gchar *user_choice = g_getenv ("GST_MSDK_DRM_DEVICE");
81 
82   if (user_choice) {
83     if (g_str_has_prefix (user_choice, "/dev/dri/"))
84       fd = open (user_choice, O_RDWR | O_CLOEXEC);
85 
86     if (fd >= 0) {
87       drmVersionPtr drm_version = drmGetVersion (fd);
88 
89       if (!drm_version || strncmp (drm_version->name, "i915", 4)) {
90         GST_ERROR ("The specified device isn't an Intel device");
91         drmFreeVersion (drm_version);
92         close (fd);
93         fd = -1;
94       } else {
95         GST_DEBUG ("Opened the specified drm device %s", user_choice);
96         drmFreeVersion (drm_version);
97       }
98     } else {
99       GST_ERROR ("The specified device isn't a valid drm device");
100     }
101 
102     return fd;
103   }
104 
105   client = g_udev_client_new (NULL);
106   if (!client)
107     goto done;
108 
109   e = g_udev_enumerator_new (client);
110   if (!e)
111     goto done;
112 
113   g_udev_enumerator_add_match_subsystem (e, "drm");
114   for (i = 0; i < 2; i++) {
115     g_udev_enumerator_add_match_name (e, devnode_files[i]);
116     devices = g_udev_enumerator_execute (e);
117 
118     for (l = devices; l != NULL; l = l->next) {
119       dev = (GUdevDevice *) l->data;
120 
121       parent = g_udev_device_get_parent (dev);
122       if (strcmp (g_udev_device_get_subsystem (parent), "pci") != 0 ||
123           strcmp (g_udev_device_get_driver (parent), "i915") != 0) {
124         g_object_unref (parent);
125         continue;
126       }
127       g_object_unref (parent);
128 
129       devnode_path = g_udev_device_get_device_file (dev);
130       fd = open (devnode_path, O_RDWR | O_CLOEXEC);
131       if (fd < 0)
132         continue;
133       GST_DEBUG ("Opened the drm device node %s", devnode_path);
134       break;
135     }
136 
137     g_list_foreach (devices, (GFunc) gst_object_unref, NULL);
138     g_list_free (devices);
139     if (fd >= 0)
140       goto done;
141   }
142 
143 done:
144   if (e)
145     g_object_unref (e);
146   if (client)
147     g_object_unref (client);
148 
149   return fd;
150 }
151 
152 
153 static gboolean
gst_msdk_context_use_vaapi(GstMsdkContext * context)154 gst_msdk_context_use_vaapi (GstMsdkContext * context)
155 {
156   gint fd;
157   gint maj_ver, min_ver;
158   VADisplay va_dpy = NULL;
159   VAStatus va_status;
160   mfxStatus status;
161   GstMsdkContextPrivate *priv = context->priv;
162 
163   fd = get_device_id ();
164   if (fd < 0) {
165     GST_WARNING ("Couldn't find a valid drm device node");
166     return FALSE;
167   }
168 
169   va_dpy = vaGetDisplayDRM (fd);
170   if (!va_dpy) {
171     GST_ERROR ("Couldn't get a VA DRM display");
172     goto failed;
173   }
174 
175   va_status = vaInitialize (va_dpy, &maj_ver, &min_ver);
176   if (va_status != VA_STATUS_SUCCESS) {
177     GST_ERROR ("Couldn't initialize VA DRM display");
178     goto failed;
179   }
180 
181   status = MFXVideoCORE_SetHandle (priv->session.session, MFX_HANDLE_VA_DISPLAY,
182       (mfxHDL) va_dpy);
183   if (status != MFX_ERR_NONE) {
184     GST_ERROR ("Setting VAAPI handle failed (%s)",
185         msdk_status_to_string (status));
186     goto failed;
187   }
188 
189   priv->fd = fd;
190   priv->dpy = va_dpy;
191 
192   return TRUE;
193 
194 failed:
195   if (va_dpy)
196     vaTerminate (va_dpy);
197   close (fd);
198   return FALSE;
199 }
200 #endif
201 
202 static gboolean
gst_msdk_context_open(GstMsdkContext * context,gboolean hardware,GstMsdkContextJobType job_type)203 gst_msdk_context_open (GstMsdkContext * context, gboolean hardware,
204     GstMsdkContextJobType job_type)
205 {
206   mfxU16 codename;
207   GstMsdkContextPrivate *priv = context->priv;
208   MsdkSession msdk_session;
209 
210   priv->job_type = job_type;
211   priv->hardware = hardware;
212 
213   msdk_session =
214       msdk_open_session (hardware ? MFX_IMPL_HARDWARE_ANY : MFX_IMPL_SOFTWARE);
215   priv->session = msdk_session;
216   if (!priv->session.session)
217     goto failed;
218 
219 #ifndef _WIN32
220   priv->fd = -1;
221 
222   if (hardware) {
223     if (!gst_msdk_context_use_vaapi (context))
224       goto failed;
225   }
226 #endif
227 
228   codename = msdk_get_platform_codename (priv->session.session);
229 
230   if (codename != MFX_PLATFORM_UNKNOWN)
231     GST_INFO ("Detected MFX platform with device code %d", codename);
232   else
233     GST_WARNING ("Unknown MFX platform");
234 
235   return TRUE;
236 
237 failed:
238   return FALSE;
239 }
240 
241 static void
gst_msdk_context_init(GstMsdkContext * context)242 gst_msdk_context_init (GstMsdkContext * context)
243 {
244   GstMsdkContextPrivate *priv = gst_msdk_context_get_instance_private (context);
245 
246   context->priv = priv;
247 
248   g_mutex_init (&priv->mutex);
249 }
250 
251 static void
release_child_session(gpointer session)252 release_child_session (gpointer session)
253 {
254   mfxStatus status;
255 
256   mfxSession _session = session;
257   status = MFXDisjoinSession (_session);
258   if (status != MFX_ERR_NONE)
259     GST_WARNING ("failed to disjoin (%s)", msdk_status_to_string (status));
260   msdk_close_mfx_session (_session);
261 }
262 
263 static void
gst_msdk_context_finalize(GObject * obj)264 gst_msdk_context_finalize (GObject * obj)
265 {
266   GstMsdkContext *context = GST_MSDK_CONTEXT_CAST (obj);
267   GstMsdkContextPrivate *priv = context->priv;
268 
269   /* child sessions will be closed when the parent session is closed */
270   if (priv->parent_context) {
271     gst_object_unref (priv->parent_context);
272     goto done;
273   } else
274     g_list_free_full (priv->child_session_list, release_child_session);
275 
276   msdk_close_session (&priv->session);
277   g_mutex_clear (&priv->mutex);
278 
279 #ifndef _WIN32
280   if (priv->dpy)
281     vaTerminate (priv->dpy);
282   if (priv->fd >= 0)
283     close (priv->fd);
284 #endif
285 
286 done:
287   G_OBJECT_CLASS (parent_class)->finalize (obj);
288 }
289 
290 static void
gst_msdk_context_class_init(GstMsdkContextClass * klass)291 gst_msdk_context_class_init (GstMsdkContextClass * klass)
292 {
293   GObjectClass *const g_object_class = G_OBJECT_CLASS (klass);
294 
295   g_object_class->finalize = gst_msdk_context_finalize;
296 }
297 
298 GstMsdkContext *
gst_msdk_context_new(gboolean hardware,GstMsdkContextJobType job_type)299 gst_msdk_context_new (gboolean hardware, GstMsdkContextJobType job_type)
300 {
301   GstMsdkContext *obj = g_object_new (GST_TYPE_MSDK_CONTEXT, NULL);
302 
303   if (obj && !gst_msdk_context_open (obj, hardware, job_type)) {
304     if (obj)
305       gst_object_unref (obj);
306     return NULL;
307   }
308 
309   return obj;
310 }
311 
312 GstMsdkContext *
gst_msdk_context_new_with_parent(GstMsdkContext * parent)313 gst_msdk_context_new_with_parent (GstMsdkContext * parent)
314 {
315   mfxStatus status;
316   GstMsdkContext *obj = g_object_new (GST_TYPE_MSDK_CONTEXT, NULL);
317   GstMsdkContextPrivate *priv = obj->priv;
318   GstMsdkContextPrivate *parent_priv = parent->priv;
319   mfxVersion version;
320   mfxIMPL impl;
321   MsdkSession child_msdk_session;
322   mfxHandleType handle_type = 0;
323   mfxHDL handle = NULL;
324 
325   status = MFXQueryIMPL (parent_priv->session.session, &impl);
326 
327   if (status == MFX_ERR_NONE)
328     status = MFXQueryVersion (parent_priv->session.session, &version);
329 
330   if (status != MFX_ERR_NONE) {
331     GST_ERROR ("Failed to query the session attributes (%s)",
332         msdk_status_to_string (status));
333     g_object_unref (obj);
334     return NULL;
335   }
336 
337   if (MFX_IMPL_VIA_VAAPI == (0x0f00 & (impl)))
338     handle_type = MFX_HANDLE_VA_DISPLAY;
339 
340   if (handle_type) {
341     status =
342         MFXVideoCORE_GetHandle (parent_priv->session.session, handle_type,
343         &handle);
344 
345     if (status != MFX_ERR_NONE || !handle) {
346       GST_ERROR ("Failed to get session handle (%s)",
347           msdk_status_to_string (status));
348       g_object_unref (obj);
349       return NULL;
350     }
351   }
352 
353   child_msdk_session.loader = parent_priv->session.loader;
354   child_msdk_session.session = NULL;
355   status = msdk_init_msdk_session (impl, &version, &child_msdk_session);
356 
357   if (status != MFX_ERR_NONE) {
358     GST_ERROR ("Failed to create a child mfx session (%s)",
359         msdk_status_to_string (status));
360     g_object_unref (obj);
361     return NULL;
362   }
363 
364   if (handle) {
365     status =
366         MFXVideoCORE_SetHandle (child_msdk_session.session, handle_type,
367         handle);
368 
369     if (status != MFX_ERR_NONE) {
370       GST_ERROR ("Failed to set a HW handle (%s)",
371           msdk_status_to_string (status));
372       MFXClose (child_msdk_session.session);
373       g_object_unref (obj);
374       return NULL;
375     }
376   }
377 #if (MFX_VERSION >= 1025)
378   status =
379       MFXJoinSession (parent_priv->session.session, child_msdk_session.session);
380 
381   if (status != MFX_ERR_NONE) {
382     GST_ERROR ("Failed to join two sessions (%s)",
383         msdk_status_to_string (status));
384     MFXClose (child_msdk_session.session);
385     g_object_unref (obj);
386     return NULL;
387   }
388 #endif
389 
390   /* Set loader to NULL for child session */
391   priv->session.loader = NULL;
392   priv->session.session = child_msdk_session.session;
393   priv->hardware = parent_priv->hardware;
394   priv->job_type = parent_priv->job_type;
395   parent_priv->child_session_list =
396       g_list_prepend (parent_priv->child_session_list, priv->session.session);
397 #ifndef _WIN32
398   priv->dpy = parent_priv->dpy;
399   priv->fd = parent_priv->fd;
400 #endif
401   priv->parent_context = gst_object_ref (parent);
402 
403   return obj;
404 }
405 
406 mfxSession
gst_msdk_context_get_session(GstMsdkContext * context)407 gst_msdk_context_get_session (GstMsdkContext * context)
408 {
409   return context->priv->session.session;
410 }
411 
412 gpointer
gst_msdk_context_get_handle(GstMsdkContext * context)413 gst_msdk_context_get_handle (GstMsdkContext * context)
414 {
415 #ifndef _WIN32
416   return context->priv->dpy;
417 #else
418   return NULL;
419 #endif
420 }
421 
422 gint
gst_msdk_context_get_fd(GstMsdkContext * context)423 gst_msdk_context_get_fd (GstMsdkContext * context)
424 {
425 #ifndef _WIN32
426   return context->priv->fd;
427 #else
428   return -1;
429 #endif
430 }
431 
432 static gint
_find_response(gconstpointer resp,gconstpointer comp_resp)433 _find_response (gconstpointer resp, gconstpointer comp_resp)
434 {
435   GstMsdkAllocResponse *cached_resp = (GstMsdkAllocResponse *) resp;
436   mfxFrameAllocResponse *_resp = (mfxFrameAllocResponse *) comp_resp;
437 
438   return cached_resp ? cached_resp->response.mids != _resp->mids : -1;
439 }
440 
441 static inline gboolean
_requested_frame_size_is_equal_or_lower(mfxFrameAllocRequest * _req,GstMsdkAllocResponse * cached_resp)442 _requested_frame_size_is_equal_or_lower (mfxFrameAllocRequest * _req,
443     GstMsdkAllocResponse * cached_resp)
444 {
445   if (((_req->Type & MFX_MEMTYPE_EXPORT_FRAME) &&
446           _req->Info.Width == cached_resp->request.Info.Width &&
447           _req->Info.Height == cached_resp->request.Info.Height) ||
448       (!(_req->Type & MFX_MEMTYPE_EXPORT_FRAME) &&
449           _req->Info.Width <= cached_resp->request.Info.Width &&
450           _req->Info.Height <= cached_resp->request.Info.Height))
451     return TRUE;
452 
453   return FALSE;
454 }
455 
456 static gint
_find_request(gconstpointer resp,gconstpointer req)457 _find_request (gconstpointer resp, gconstpointer req)
458 {
459   GstMsdkAllocResponse *cached_resp = (GstMsdkAllocResponse *) resp;
460   mfxFrameAllocRequest *_req = (mfxFrameAllocRequest *) req;
461 
462   /* Confirm if it's under the size of the cached response */
463   if (_req->NumFrameSuggested <= cached_resp->request.NumFrameSuggested &&
464       _requested_frame_size_is_equal_or_lower (_req, cached_resp))
465     return _req->Type & cached_resp->
466         request.Type & MFX_MEMTYPE_FROM_DECODE ? 0 : -1;
467 
468   return -1;
469 }
470 
471 GstMsdkAllocResponse *
gst_msdk_context_get_cached_alloc_responses(GstMsdkContext * context,mfxFrameAllocResponse * resp)472 gst_msdk_context_get_cached_alloc_responses (GstMsdkContext * context,
473     mfxFrameAllocResponse * resp)
474 {
475   GstMsdkContextPrivate *priv = context->priv;
476   GList *l =
477       g_list_find_custom (priv->cached_alloc_responses, resp, _find_response);
478 
479   if (l)
480     return l->data;
481   else
482     return NULL;
483 }
484 
485 GstMsdkAllocResponse *
gst_msdk_context_get_cached_alloc_responses_by_request(GstMsdkContext * context,mfxFrameAllocRequest * req)486 gst_msdk_context_get_cached_alloc_responses_by_request (GstMsdkContext *
487     context, mfxFrameAllocRequest * req)
488 {
489   GstMsdkContextPrivate *priv = context->priv;
490   GList *l =
491       g_list_find_custom (priv->cached_alloc_responses, req, _find_request);
492 
493   if (l)
494     return l->data;
495   else
496     return NULL;
497 }
498 
499 static void
create_surfaces(GstMsdkContext * context,GstMsdkAllocResponse * resp)500 create_surfaces (GstMsdkContext * context, GstMsdkAllocResponse * resp)
501 {
502   gint i;
503   mfxMemId *mem_id;
504   mfxFrameSurface1 *surface;
505 
506   for (i = 0; i < resp->response.NumFrameActual; i++) {
507     mem_id = resp->response.mids[i];
508     surface = (mfxFrameSurface1 *) g_slice_new0 (mfxFrameSurface1);
509     if (!surface) {
510       GST_ERROR ("failed to allocate surface");
511       break;
512     }
513     surface->Data.MemId = mem_id;
514     resp->surfaces_avail = g_list_prepend (resp->surfaces_avail, surface);
515   }
516 }
517 
518 static void
free_surface(gpointer surface)519 free_surface (gpointer surface)
520 {
521   g_slice_free1 (sizeof (mfxFrameSurface1), surface);
522 }
523 
524 static void
remove_surfaces(GstMsdkContext * context,GstMsdkAllocResponse * resp)525 remove_surfaces (GstMsdkContext * context, GstMsdkAllocResponse * resp)
526 {
527   g_list_free_full (resp->surfaces_used, free_surface);
528   g_list_free_full (resp->surfaces_avail, free_surface);
529   g_list_free_full (resp->surfaces_locked, free_surface);
530 }
531 
532 void
gst_msdk_context_add_alloc_response(GstMsdkContext * context,GstMsdkAllocResponse * resp)533 gst_msdk_context_add_alloc_response (GstMsdkContext * context,
534     GstMsdkAllocResponse * resp)
535 {
536   context->priv->cached_alloc_responses =
537       g_list_prepend (context->priv->cached_alloc_responses, resp);
538 
539   create_surfaces (context, resp);
540 }
541 
542 gboolean
gst_msdk_context_remove_alloc_response(GstMsdkContext * context,mfxFrameAllocResponse * resp)543 gst_msdk_context_remove_alloc_response (GstMsdkContext * context,
544     mfxFrameAllocResponse * resp)
545 {
546   GstMsdkAllocResponse *msdk_resp;
547   GstMsdkContextPrivate *priv = context->priv;
548   GList *l =
549       g_list_find_custom (priv->cached_alloc_responses, resp, _find_response);
550 
551   if (!l)
552     return FALSE;
553 
554   msdk_resp = l->data;
555 
556   remove_surfaces (context, msdk_resp);
557 
558   g_slice_free1 (sizeof (GstMsdkAllocResponse), msdk_resp);
559   priv->cached_alloc_responses =
560       g_list_delete_link (priv->cached_alloc_responses, l);
561 
562   return TRUE;
563 }
564 
565 static gboolean
check_surfaces_available(GstMsdkContext * context,GstMsdkAllocResponse * resp)566 check_surfaces_available (GstMsdkContext * context, GstMsdkAllocResponse * resp)
567 {
568   GList *l;
569   mfxFrameSurface1 *surface = NULL;
570   GstMsdkContextPrivate *priv = context->priv;
571   gboolean ret = FALSE;
572 
573   g_mutex_lock (&priv->mutex);
574   for (l = resp->surfaces_locked; l;) {
575     surface = l->data;
576     l = l->next;
577     if (!surface->Data.Locked) {
578       resp->surfaces_locked = g_list_remove (resp->surfaces_locked, surface);
579       resp->surfaces_avail = g_list_prepend (resp->surfaces_avail, surface);
580       ret = TRUE;
581     }
582   }
583   g_mutex_unlock (&priv->mutex);
584 
585   return ret;
586 }
587 
588 /*
589  * There are 3 lists here in GstMsdkContext as the following:
590  * 1. surfaces_avail : surfaces which are free and unused anywhere
591  * 2. surfaces_used : surfaces coupled with a gst buffer and being used now.
592  * 3. surfaces_locked : surfaces still locked even after the gst buffer is released.
593  *
594  * Note that they need to be protected by mutex to be thread-safe.
595  */
596 
597 mfxFrameSurface1 *
gst_msdk_context_get_surface_available(GstMsdkContext * context,mfxFrameAllocResponse * resp)598 gst_msdk_context_get_surface_available (GstMsdkContext * context,
599     mfxFrameAllocResponse * resp)
600 {
601   GList *l;
602   mfxFrameSurface1 *surface = NULL;
603   GstMsdkAllocResponse *msdk_resp =
604       gst_msdk_context_get_cached_alloc_responses (context, resp);
605   gint retry = 0;
606   GstMsdkContextPrivate *priv = context->priv;
607 
608 retry:
609   g_mutex_lock (&priv->mutex);
610   for (l = msdk_resp->surfaces_avail; l;) {
611     surface = l->data;
612     l = l->next;
613     if (!surface->Data.Locked) {
614       msdk_resp->surfaces_avail =
615           g_list_remove (msdk_resp->surfaces_avail, surface);
616       msdk_resp->surfaces_used =
617           g_list_prepend (msdk_resp->surfaces_used, surface);
618       break;
619     }
620   }
621   g_mutex_unlock (&priv->mutex);
622 
623   /*
624    * If a msdk context is shared by multiple msdk elements,
625    * upstream msdk element sometimes needs to wait for a gst buffer
626    * to be released in downstream.
627    *
628    * Poll the pool for a maximum of 20 millisecond.
629    *
630    * FIXME: Is there any better way to handle this case?
631    */
632   if (!surface && retry < 20) {
633     /* If there's no surface available, find unlocked surfaces in the locked list,
634      * take it back to the available list and then search again.
635      */
636     check_surfaces_available (context, msdk_resp);
637     retry++;
638     g_usleep (1000);
639     goto retry;
640   }
641 
642   return surface;
643 }
644 
645 void
gst_msdk_context_put_surface_locked(GstMsdkContext * context,mfxFrameAllocResponse * resp,mfxFrameSurface1 * surface)646 gst_msdk_context_put_surface_locked (GstMsdkContext * context,
647     mfxFrameAllocResponse * resp, mfxFrameSurface1 * surface)
648 {
649   GstMsdkContextPrivate *priv = context->priv;
650   GstMsdkAllocResponse *msdk_resp =
651       gst_msdk_context_get_cached_alloc_responses (context, resp);
652 
653   g_mutex_lock (&priv->mutex);
654   if (!g_list_find (msdk_resp->surfaces_locked, surface)) {
655     msdk_resp->surfaces_used =
656         g_list_remove (msdk_resp->surfaces_used, surface);
657     msdk_resp->surfaces_locked =
658         g_list_prepend (msdk_resp->surfaces_locked, surface);
659   }
660   g_mutex_unlock (&priv->mutex);
661 }
662 
663 void
gst_msdk_context_put_surface_available(GstMsdkContext * context,mfxFrameAllocResponse * resp,mfxFrameSurface1 * surface)664 gst_msdk_context_put_surface_available (GstMsdkContext * context,
665     mfxFrameAllocResponse * resp, mfxFrameSurface1 * surface)
666 {
667   GstMsdkContextPrivate *priv = context->priv;
668   GstMsdkAllocResponse *msdk_resp =
669       gst_msdk_context_get_cached_alloc_responses (context, resp);
670 
671   g_mutex_lock (&priv->mutex);
672   if (!g_list_find (msdk_resp->surfaces_avail, surface)) {
673     msdk_resp->surfaces_used =
674         g_list_remove (msdk_resp->surfaces_used, surface);
675     msdk_resp->surfaces_avail =
676         g_list_prepend (msdk_resp->surfaces_avail, surface);
677   }
678   g_mutex_unlock (&priv->mutex);
679 }
680 
681 GstMsdkContextJobType
gst_msdk_context_get_job_type(GstMsdkContext * context)682 gst_msdk_context_get_job_type (GstMsdkContext * context)
683 {
684   return context->priv->job_type;
685 }
686 
687 void
gst_msdk_context_add_job_type(GstMsdkContext * context,GstMsdkContextJobType job_type)688 gst_msdk_context_add_job_type (GstMsdkContext * context,
689     GstMsdkContextJobType job_type)
690 {
691   context->priv->job_type |= job_type;
692 }
693 
694 gint
gst_msdk_context_get_shared_async_depth(GstMsdkContext * context)695 gst_msdk_context_get_shared_async_depth (GstMsdkContext * context)
696 {
697   return context->priv->shared_async_depth;
698 }
699 
700 void
gst_msdk_context_add_shared_async_depth(GstMsdkContext * context,gint async_depth)701 gst_msdk_context_add_shared_async_depth (GstMsdkContext * context,
702     gint async_depth)
703 {
704   context->priv->shared_async_depth += async_depth;
705 }
706 
707 void
gst_msdk_context_set_frame_allocator(GstMsdkContext * context,mfxFrameAllocator * allocator)708 gst_msdk_context_set_frame_allocator (GstMsdkContext * context,
709     mfxFrameAllocator * allocator)
710 {
711   GstMsdkContextPrivate *priv = context->priv;
712 
713   g_mutex_lock (&priv->mutex);
714 
715   if (!priv->has_frame_allocator) {
716     mfxStatus status;
717 
718     status = MFXVideoCORE_SetFrameAllocator (priv->session.session, allocator);
719 
720     if (status != MFX_ERR_NONE)
721       GST_ERROR ("Failed to set frame allocator");
722     else
723       priv->has_frame_allocator = 1;
724   }
725 
726   g_mutex_unlock (&priv->mutex);
727 }
728