• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer Intel MSDK plugin
2  * Copyright (c) 2016, Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #  include <config.h>
34 #endif
35 
36 #include <stdlib.h>
37 
38 #include "gstmsdkdec.h"
39 #include "gstmsdkbufferpool.h"
40 #include "gstmsdkvideomemory.h"
41 #include "gstmsdksystemmemory.h"
42 #include "gstmsdkcontextutil.h"
43 
44 GST_DEBUG_CATEGORY_EXTERN (gst_msdkdec_debug);
45 #define GST_CAT_DEFAULT gst_msdkdec_debug
46 
47 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
48     GST_PAD_SRC,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS (GST_MSDK_CAPS_STR ("NV12", "NV12"))
51     );
52 
53 #define PROP_HARDWARE_DEFAULT            TRUE
54 #define PROP_ASYNC_DEPTH_DEFAULT         1
55 
56 #define IS_ALIGNED(i, n) (((i) & ((n)-1)) == 0)
57 
58 #define GST_TO_MFX_TIME(time) ((time) == GST_CLOCK_TIME_NONE ? \
59     MFX_TIMESTAMP_UNKNOWN : gst_util_uint64_scale_round ((time), 9, 100000))
60 
61 #define MFX_TIME_IS_VALID(time) ((time) != MFX_TIMESTAMP_UNKNOWN)
62 
63 #define gst_msdkdec_parent_class parent_class
64 G_DEFINE_TYPE (GstMsdkDec, gst_msdkdec, GST_TYPE_VIDEO_DECODER);
65 
66 typedef struct _MsdkSurface
67 {
68   mfxFrameSurface1 *surface;
69   GstBuffer *buf;
70   GstVideoFrame data;
71   GstVideoFrame copy;
72 } MsdkSurface;
73 
74 struct _MsdkDecTask
75 {
76   MsdkSurface *surface;
77   mfxSyncPoint sync_point;
78 
79   gboolean decode_only;
80 };
81 
82 static gboolean gst_msdkdec_drain (GstVideoDecoder * decoder);
83 static gboolean gst_msdkdec_flush (GstVideoDecoder * decoder);
84 static gboolean gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset);
85 
86 void
gst_msdkdec_add_bs_extra_param(GstMsdkDec * thiz,mfxExtBuffer * param)87 gst_msdkdec_add_bs_extra_param (GstMsdkDec * thiz, mfxExtBuffer * param)
88 {
89   if (thiz->num_bs_extra_params < MAX_BS_EXTRA_PARAMS) {
90     thiz->bs_extra_params[thiz->num_bs_extra_params] = param;
91     thiz->num_bs_extra_params++;
92   }
93 }
94 
95 static GstVideoCodecFrame *
gst_msdkdec_get_oldest_frame(GstVideoDecoder * decoder)96 gst_msdkdec_get_oldest_frame (GstVideoDecoder * decoder)
97 {
98   GstVideoCodecFrame *frame = NULL, *old_frame = NULL;
99   GList *frames, *l;
100   gint count = 0;
101 
102   frames = gst_video_decoder_get_frames (decoder);
103 
104   for (l = frames; l != NULL; l = l->next) {
105     GstVideoCodecFrame *f = l->data;
106 
107     if (!GST_CLOCK_TIME_IS_VALID (f->pts)) {
108       GST_INFO
109           ("Frame doesn't have a valid pts yet, Use gst_video_decoder_get_oldest_frame()"
110           "with out considering the PTS for selecting the frame to be finished");
111       old_frame = gst_video_decoder_get_oldest_frame (decoder);
112       break;
113     }
114 
115     if (!frame || frame->pts > f->pts)
116       frame = f;
117 
118     count++;
119   }
120 
121   if (old_frame)
122     frame = old_frame;
123 
124   if (frame) {
125     GST_LOG_OBJECT (decoder,
126         "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
127         frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
128     gst_video_codec_frame_ref (frame);
129   }
130 
131   if (old_frame)
132     gst_video_codec_frame_unref (old_frame);
133 
134   g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
135 
136   return frame;
137 }
138 
139 static inline void
free_surface(MsdkSurface * s)140 free_surface (MsdkSurface * s)
141 {
142   gst_buffer_unref (s->buf);
143   g_slice_free (MsdkSurface, s);
144 }
145 
146 static void
unmap_frame(GstMsdkDec * thiz,MsdkSurface * s)147 unmap_frame (GstMsdkDec * thiz, MsdkSurface * s)
148 {
149   if (s->copy.buffer) {
150     /* we allocate this buffer from down stream, we need ref-1 for it */
151     gst_buffer_unref (s->copy.buffer);
152     gst_video_frame_unmap (&s->copy);
153     s->copy.buffer = NULL;
154   }
155 
156   if (s->data.buffer) {
157     gst_video_frame_unmap (&s->data);
158     s->data.buffer = NULL;
159   }
160 }
161 
162 static void
gst_msdkdec_free_unlocked_msdk_surfaces(GstMsdkDec * thiz)163 gst_msdkdec_free_unlocked_msdk_surfaces (GstMsdkDec * thiz)
164 {
165   GList *l;
166   MsdkSurface *surface;
167 
168   for (l = thiz->locked_msdk_surfaces; l;) {
169     GList *next = l->next;
170     surface = l->data;
171     if (surface->surface->Data.Locked == 0) {
172       unmap_frame (thiz, surface);
173       free_surface (surface);
174       thiz->locked_msdk_surfaces =
175           g_list_delete_link (thiz->locked_msdk_surfaces, l);
176     }
177     l = next;
178   }
179 }
180 
181 static GstFlowReturn
allocate_output_buffer(GstMsdkDec * thiz,GstBuffer ** buffer)182 allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
183 {
184   GstFlowReturn flow;
185   GstVideoCodecFrame *frame;
186   GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
187 
188   frame = gst_msdkdec_get_oldest_frame (decoder);
189   if (!frame) {
190     if (GST_PAD_IS_FLUSHING (decoder->srcpad))
191       return GST_FLOW_FLUSHING;
192     else
193       return GST_FLOW_CUSTOM_SUCCESS;
194   }
195 
196   if (!frame->output_buffer) {
197     /* Free un-unsed msdk surfaces firstly, hence the associated mfx
198      * surfaces will be moved from used list to available list */
199     gst_msdkdec_free_unlocked_msdk_surfaces (thiz);
200 
201     flow = gst_video_decoder_allocate_output_frame (decoder, frame);
202     if (flow != GST_FLOW_OK) {
203       gst_video_codec_frame_unref (frame);
204       return flow;
205     }
206   }
207 
208   *buffer = gst_buffer_ref (frame->output_buffer);
209   gst_buffer_replace (&frame->output_buffer, NULL);
210   gst_video_codec_frame_unref (frame);
211 
212   return GST_FLOW_OK;
213 }
214 
215 static MsdkSurface *
get_surface(GstMsdkDec * thiz,GstBuffer * buffer)216 get_surface (GstMsdkDec * thiz, GstBuffer * buffer)
217 {
218   MsdkSurface *i;
219   GstVideoCodecState *output_state = NULL;
220   gboolean success;
221 
222   i = g_slice_new0 (MsdkSurface);
223 
224   if (gst_msdk_is_msdk_buffer (buffer)) {
225     i->surface = gst_msdk_get_surface_from_buffer (buffer);
226     i->buf = buffer;
227   } else {
228     /* Confirm to activate the side pool */
229     if (!gst_buffer_pool_is_active (thiz->pool) &&
230         !gst_buffer_pool_set_active (thiz->pool, TRUE)) {
231       g_slice_free (MsdkSurface, i);
232       return NULL;
233     }
234 
235     if (!gst_video_frame_map (&i->copy, &thiz->non_msdk_pool_info, buffer,
236             GST_MAP_WRITE))
237       goto failed_unref_buffer;
238 
239     if (gst_buffer_pool_acquire_buffer (thiz->pool, &buffer,
240             NULL) != GST_FLOW_OK)
241       goto failed_unmap_copy;
242 
243     i->surface = gst_msdk_get_surface_from_buffer (buffer);
244     i->buf = buffer;
245 
246     output_state =
247         gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
248     success =
249         gst_video_frame_map (&i->data, &output_state->info, buffer,
250         GST_MAP_READWRITE);
251     gst_video_codec_state_unref (output_state);
252     if (!success)
253       goto failed_unref_buffer2;
254   }
255 
256   gst_msdk_update_mfx_frame_info_from_mfx_video_param (&i->surface->Info,
257       &thiz->param);
258 
259   thiz->locked_msdk_surfaces = g_list_append (thiz->locked_msdk_surfaces, i);
260   return i;
261 
262 failed_unref_buffer2:
263   gst_buffer_unref (buffer);
264   buffer = i->data.buffer;
265 failed_unmap_copy:
266   gst_video_frame_unmap (&i->copy);
267 failed_unref_buffer:
268   gst_buffer_unref (buffer);
269   g_slice_free (MsdkSurface, i);
270 
271   GST_ERROR_OBJECT (thiz, "failed to handle buffer");
272   return NULL;
273 }
274 
275 static void
gst_msdkdec_close_decoder(GstMsdkDec * thiz,gboolean reset_param)276 gst_msdkdec_close_decoder (GstMsdkDec * thiz, gboolean reset_param)
277 {
278   mfxStatus status;
279 
280   if (!thiz->context || !thiz->initialized)
281     return;
282 
283   GST_DEBUG_OBJECT (thiz, "Closing decoder with context %" GST_PTR_FORMAT,
284       thiz->context);
285 
286   if (thiz->use_video_memory)
287     gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
288 
289   status = MFXVideoDECODE_Close (gst_msdk_context_get_session (thiz->context));
290   if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
291     GST_WARNING_OBJECT (thiz, "Decoder close failed (%s)",
292         msdk_status_to_string (status));
293   }
294 
295   g_array_set_size (thiz->tasks, 0);
296 
297   if (reset_param)
298     memset (&thiz->param, 0, sizeof (thiz->param));
299 
300   thiz->num_bs_extra_params = 0;
301   thiz->initialized = FALSE;
302   gst_adapter_clear (thiz->adapter);
303 }
304 
305 static void
gst_msdkdec_set_context(GstElement * element,GstContext * context)306 gst_msdkdec_set_context (GstElement * element, GstContext * context)
307 {
308   GstMsdkContext *msdk_context = NULL;
309   GstMsdkDec *thiz = GST_MSDKDEC (element);
310 
311   if (gst_msdk_context_get_context (context, &msdk_context)) {
312     gst_object_replace ((GstObject **) & thiz->context,
313         (GstObject *) msdk_context);
314     gst_object_unref (msdk_context);
315   }
316 
317   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
318 }
319 
320 static gboolean
gst_msdkdec_init_decoder(GstMsdkDec * thiz)321 gst_msdkdec_init_decoder (GstMsdkDec * thiz)
322 {
323   GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
324   GstVideoInfo *info;
325   mfxSession session;
326   mfxStatus status;
327   mfxFrameAllocRequest request;
328 
329   if (thiz->initialized)
330     return TRUE;
331 
332   if (!thiz->context) {
333     GST_WARNING_OBJECT (thiz, "No MSDK Context");
334     return FALSE;
335   }
336 
337   if (!thiz->input_state) {
338     GST_DEBUG_OBJECT (thiz, "Have no input state yet");
339     return FALSE;
340   }
341   info = &thiz->input_state->info;
342 
343   GST_OBJECT_LOCK (thiz);
344 
345   if (thiz->use_video_memory) {
346     gst_msdk_set_frame_allocator (thiz->context);
347     thiz->param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
348   } else {
349     thiz->param.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
350   }
351 
352   GST_INFO_OBJECT (thiz, "This MSDK decoder uses %s memory",
353       thiz->use_video_memory ? "video" : "system");
354 
355   thiz->param.AsyncDepth = thiz->async_depth;
356 
357   /* We expect msdk to fill the width and height values */
358   g_return_val_if_fail (thiz->param.mfx.FrameInfo.Width
359       && thiz->param.mfx.FrameInfo.Height, FALSE);
360 
361   klass->preinit_decoder (thiz);
362 
363   /* Set frame rate only if provided.
364    * If not, frame rate will be assumed inside the driver.
365    * Also we respect the upstream provided fps values */
366   if (info->fps_n > 0 && info->fps_d > 0
367       && info->fps_n != thiz->param.mfx.FrameInfo.FrameRateExtN
368       && info->fps_d != thiz->param.mfx.FrameInfo.FrameRateExtD) {
369     thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
370     thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
371   }
372 
373   if (info->par_n && info->par_d && !thiz->param.mfx.FrameInfo.AspectRatioW
374       && !thiz->param.mfx.FrameInfo.AspectRatioH) {
375     thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
376     thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
377   }
378 
379   thiz->param.mfx.FrameInfo.FourCC =
380       thiz->param.mfx.FrameInfo.FourCC ? thiz->param.mfx.
381       FrameInfo.FourCC : MFX_FOURCC_NV12;
382   thiz->param.mfx.FrameInfo.ChromaFormat =
383       thiz->param.mfx.FrameInfo.ChromaFormat ? thiz->param.mfx.
384       FrameInfo.ChromaFormat : MFX_CHROMAFORMAT_YUV420;
385 
386   session = gst_msdk_context_get_session (thiz->context);
387   /* validate parameters and allow MFX to make adjustments */
388   status = MFXVideoDECODE_Query (session, &thiz->param, &thiz->param);
389   if (status < MFX_ERR_NONE) {
390     GST_ERROR_OBJECT (thiz, "Video Decode Query failed (%s)",
391         msdk_status_to_string (status));
392     goto failed;
393   } else if (status > MFX_ERR_NONE) {
394     GST_WARNING_OBJECT (thiz, "Video Decode Query returned: %s",
395         msdk_status_to_string (status));
396   }
397 
398   klass->postinit_decoder (thiz);
399 
400   status = MFXVideoDECODE_QueryIOSurf (session, &thiz->param, &request);
401   if (status < MFX_ERR_NONE) {
402     GST_ERROR_OBJECT (thiz, "Query IO surfaces failed (%s)",
403         msdk_status_to_string (status));
404     goto failed;
405   } else if (status > MFX_ERR_NONE) {
406     GST_WARNING_OBJECT (thiz, "Query IO surfaces returned: %s",
407         msdk_status_to_string (status));
408   }
409 
410   if (request.NumFrameSuggested < thiz->param.AsyncDepth) {
411     GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
412         request.NumFrameMin, request.NumFrameSuggested, thiz->param.AsyncDepth);
413     goto failed;
414   }
415 
416   /* account for downstream requirement */
417   if (G_LIKELY (thiz->min_prealloc_buffers))
418     request.NumFrameSuggested += thiz->min_prealloc_buffers;
419   else
420     GST_WARNING_OBJECT (thiz,
421         "Allocating resources without considering the downstream requirement"
422         "or extra scratch surface count");
423 
424   if (thiz->use_video_memory) {
425     gint shared_async_depth;
426 
427     shared_async_depth =
428         gst_msdk_context_get_shared_async_depth (thiz->context);
429     request.NumFrameSuggested += shared_async_depth;
430 
431     request.Type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
432     if (thiz->use_dmabuf)
433       request.Type |= MFX_MEMTYPE_EXPORT_FRAME;
434     gst_msdk_frame_alloc (thiz->context, &request, &thiz->alloc_resp);
435   }
436 
437   /* update the prealloc_buffer count, which will be used later
438    * as GstBufferPool min_buffers */
439   thiz->min_prealloc_buffers = request.NumFrameSuggested;
440 
441   GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested)",
442       request.NumFrameMin, request.NumFrameSuggested);
443 
444   status = MFXVideoDECODE_Init (session, &thiz->param);
445   if (status < MFX_ERR_NONE) {
446     GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
447     goto failed;
448   } else if (status > MFX_ERR_NONE) {
449     GST_WARNING_OBJECT (thiz, "Init returned: %s",
450         msdk_status_to_string (status));
451   }
452 
453   status = MFXVideoDECODE_GetVideoParam (session, &thiz->param);
454   if (status < MFX_ERR_NONE) {
455     GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
456         msdk_status_to_string (status));
457     goto failed;
458   } else if (status > MFX_ERR_NONE) {
459     GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
460         msdk_status_to_string (status));
461   }
462 
463   g_array_set_size (thiz->tasks, 0);    /* resets array content */
464   g_array_set_size (thiz->tasks, thiz->param.AsyncDepth);
465   thiz->next_task = 0;
466 
467   GST_OBJECT_UNLOCK (thiz);
468 
469   thiz->initialized = TRUE;
470   return TRUE;
471 
472 failed:
473   GST_OBJECT_UNLOCK (thiz);
474   return FALSE;
475 }
476 
477 
478 static gboolean
_gst_caps_has_feature(const GstCaps * caps,const gchar * feature)479 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
480 {
481   guint i;
482 
483   for (i = 0; i < gst_caps_get_size (caps); i++) {
484     GstCapsFeatures *const features = gst_caps_get_features (caps, i);
485     /* Skip ANY features, we need an exact match for correct evaluation */
486     if (gst_caps_features_is_any (features))
487       continue;
488     if (gst_caps_features_contains (features, feature))
489       return TRUE;
490   }
491 
492   return FALSE;
493 }
494 
495 static gboolean
srcpad_can_dmabuf(GstMsdkDec * thiz)496 srcpad_can_dmabuf (GstMsdkDec * thiz)
497 {
498   gboolean ret = FALSE;
499   GstCaps *caps, *out_caps;
500   GstPad *srcpad;
501 
502   srcpad = GST_VIDEO_DECODER_SRC_PAD (thiz);
503   caps = gst_pad_get_pad_template_caps (srcpad);
504 
505   out_caps = gst_pad_peer_query_caps (srcpad, caps);
506   if (!out_caps)
507     goto done;
508 
509   if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps)
510       || out_caps == caps)
511     goto done;
512 
513   if (_gst_caps_has_feature (out_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
514     ret = TRUE;
515 
516 done:
517   if (caps)
518     gst_caps_unref (caps);
519   if (out_caps)
520     gst_caps_unref (out_caps);
521   return ret;
522 }
523 
524 static gboolean
gst_msdkdec_set_src_caps(GstMsdkDec * thiz,gboolean need_allocation)525 gst_msdkdec_set_src_caps (GstMsdkDec * thiz, gboolean need_allocation)
526 {
527   GstVideoCodecState *output_state;
528   GstVideoInfo *vinfo;
529   GstVideoAlignment align;
530   GstCaps *allocation_caps = NULL;
531   GstVideoFormat format;
532   guint width, height;
533   guint alloc_w, alloc_h;
534   const gchar *format_str;
535 
536   /* use display width and display height in output state, which
537    * will be used for caps negotiation */
538   width =
539       thiz->param.mfx.FrameInfo.CropW ? thiz->param.mfx.
540       FrameInfo.CropW : GST_VIDEO_INFO_WIDTH (&thiz->input_state->info);
541   height =
542       thiz->param.mfx.FrameInfo.CropH ? thiz->param.mfx.
543       FrameInfo.CropH : GST_VIDEO_INFO_HEIGHT (&thiz->input_state->info);
544 
545   format =
546       gst_msdk_get_video_format_from_mfx_fourcc (thiz->param.mfx.
547       FrameInfo.FourCC);
548 
549   if (format == GST_VIDEO_FORMAT_UNKNOWN) {
550     GST_WARNING_OBJECT (thiz, "Failed to find a valid video format");
551     return FALSE;
552   }
553 
554   output_state =
555       gst_video_decoder_set_output_state (GST_VIDEO_DECODER (thiz),
556       format, width, height, thiz->input_state);
557   if (!output_state)
558     return FALSE;
559 
560   /* Find allocation width and height */
561   alloc_w =
562       GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
563       FrameInfo.Width : width);
564   alloc_h =
565       GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
566       FrameInfo.Height : height);
567 
568   /* Ensure output_state->caps and info have same width and height
569    * Also, mandate 32 bit alignment */
570   vinfo = &output_state->info;
571   gst_msdk_set_video_alignment (vinfo, alloc_w, alloc_h, &align);
572   gst_video_info_align (vinfo, &align);
573   output_state->caps = gst_video_info_to_caps (vinfo);
574   if (srcpad_can_dmabuf (thiz))
575     gst_caps_set_features (output_state->caps, 0,
576         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
577 
578   if (need_allocation) {
579     /* Find allocation width and height */
580     width =
581         GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
582         FrameInfo.Width : GST_VIDEO_INFO_WIDTH (&output_state->info));
583     height =
584         GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
585         FrameInfo.Height : GST_VIDEO_INFO_HEIGHT (&output_state->info));
586 
587     /* set allocation width and height in allocation_caps,
588      * which may or may not be similar to the output_state caps */
589     allocation_caps = gst_caps_copy (output_state->caps);
590     format_str =
591         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
592         (&output_state->info));
593     gst_caps_set_simple (allocation_caps, "width", G_TYPE_INT, width, "height",
594         G_TYPE_INT, height, "format", G_TYPE_STRING, format_str, NULL);
595     GST_INFO_OBJECT (thiz, "new alloc caps = %" GST_PTR_FORMAT,
596         allocation_caps);
597     gst_caps_replace (&output_state->allocation_caps, allocation_caps);
598     gst_caps_unref (allocation_caps);
599   } else {
600     /* We keep the allocation parameters as it is to avoid pool re-negotiation.
601      * For codecs like VP9, dynamic resolution change doesn't require allocation
602      * reset if the new video frame resolution is lower than the
603      * already configured one */
604   }
605   gst_video_codec_state_unref (output_state);
606 
607   return TRUE;
608 }
609 
610 static void
gst_msdkdec_set_latency(GstMsdkDec * thiz)611 gst_msdkdec_set_latency (GstMsdkDec * thiz)
612 {
613   GstVideoInfo *info = &thiz->input_state->info;
614   gint min_delayed_frames;
615   GstClockTime latency;
616 
617   min_delayed_frames = thiz->async_depth;
618 
619   if (info->fps_n) {
620     latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
621         min_delayed_frames, info->fps_n);
622   } else {
623     /* FIXME: Assume 25fps. This is better than reporting no latency at
624      * all and then later failing in live pipelines
625      */
626     latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
627         min_delayed_frames, 25);
628   }
629 
630   GST_INFO_OBJECT (thiz,
631       "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
632       GST_TIME_ARGS (latency), min_delayed_frames);
633 
634   gst_video_decoder_set_latency (GST_VIDEO_DECODER (thiz), latency, latency);
635 }
636 
637 static gint
_find_msdk_surface(gconstpointer msdk_surface,gconstpointer comp_surface)638 _find_msdk_surface (gconstpointer msdk_surface, gconstpointer comp_surface)
639 {
640   MsdkSurface *cached_surface = (MsdkSurface *) msdk_surface;
641   mfxFrameSurface1 *_surface = (mfxFrameSurface1 *) comp_surface;
642 
643   return cached_surface ? cached_surface->surface != _surface : -1;
644 }
645 
646 static void
finish_task(GstMsdkDec * thiz,MsdkDecTask * task)647 finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
648 {
649   MsdkSurface *surface = task->surface;
650   if (surface) {
651     if (G_UNLIKELY (surface->copy.buffer)) {
652       unmap_frame (thiz, surface);
653     }
654     thiz->locked_msdk_surfaces =
655         g_list_append (thiz->locked_msdk_surfaces, surface);
656   }
657   task->sync_point = NULL;
658   task->surface = NULL;
659   task->decode_only = FALSE;
660 }
661 
662 static void
gst_msdkdec_frame_corruption_report(GstMsdkDec * thiz,mfxU16 corruption)663 gst_msdkdec_frame_corruption_report (GstMsdkDec * thiz, mfxU16 corruption)
664 {
665   if (!thiz->report_error || !corruption)
666     return;
667 
668   if (corruption & MFX_CORRUPTION_MINOR)
669     GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
670         ("[Corruption] Minor corruption detected!"), (NULL));
671 
672   if (corruption & MFX_CORRUPTION_MAJOR)
673     GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
674         ("[Corruption] Major corruption detected!"), (NULL));
675 
676   if (corruption & MFX_CORRUPTION_ABSENT_TOP_FIELD)
677     GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
678         ("[Corruption] Absent top field!"), (NULL));
679 
680   if (corruption & MFX_CORRUPTION_ABSENT_BOTTOM_FIELD)
681     GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
682         ("[Corruption] Absent bottom field!"), (NULL));
683 
684   if (corruption & MFX_CORRUPTION_REFERENCE_FRAME)
685     GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
686         ("[Corruption] Corrupted reference frame!"), (NULL));
687 
688   if (corruption & MFX_CORRUPTION_REFERENCE_LIST)
689     GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
690         ("[Corruption] Corrupted reference list!"), (NULL));
691 }
692 
693 static GstFlowReturn
gst_msdkdec_finish_task(GstMsdkDec * thiz,MsdkDecTask * task)694 gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
695 {
696   GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
697   GstFlowReturn flow;
698   GstVideoCodecFrame *frame;
699   MsdkSurface *surface;
700   mfxStatus status;
701   guint64 pts = MFX_TIMESTAMP_UNKNOWN;
702 
703   if (G_LIKELY (task->sync_point)) {
704     status =
705         MFXVideoCORE_SyncOperation (gst_msdk_context_get_session
706         (thiz->context), task->sync_point, 300000);
707     if (status != MFX_ERR_NONE) {
708       GST_ERROR_OBJECT (thiz, "failed to do sync operation");
709       return GST_FLOW_ERROR;
710     }
711   }
712 
713   surface = task->surface;
714   if (surface) {
715     gst_msdkdec_frame_corruption_report (thiz,
716         surface->surface->Data.Corrupted);
717     GST_DEBUG_OBJECT (thiz, "Decoded MFX TimeStamp: %" G_GUINT64_FORMAT,
718         (guint64) surface->surface->Data.TimeStamp);
719     pts = surface->surface->Data.TimeStamp;
720   }
721 
722   if (G_LIKELY (task->sync_point || (surface && task->decode_only))) {
723     gboolean decode_only = task->decode_only;
724 
725     frame = gst_msdkdec_get_oldest_frame (decoder);
726     /* align decoder frame list with current decoded position */
727     while (frame && MFX_TIME_IS_VALID (pts)
728         && GST_CLOCK_TIME_IS_VALID (frame->pts)
729         && GST_TO_MFX_TIME (frame->pts) < pts) {
730       GST_INFO_OBJECT (thiz, "Discarding frame: %p PTS: %" GST_TIME_FORMAT
731           " MFX TimeStamp: %" G_GUINT64_FORMAT,
732           frame, GST_TIME_ARGS (frame->pts), GST_TO_MFX_TIME (frame->pts));
733       gst_video_decoder_release_frame (decoder, frame);
734       frame = gst_msdkdec_get_oldest_frame (decoder);
735     }
736 
737     if (G_LIKELY (frame)) {
738       if (G_LIKELY (surface->copy.buffer == NULL)) {
739         /* gst_video_decoder_finish_frame will call gst_buffer_make_writable
740          * we need this to avoid copy buffer                               */
741         GST_MINI_OBJECT_FLAG_SET (surface->buf, GST_MINI_OBJECT_FLAG_LOCKABLE);
742         frame->output_buffer = gst_buffer_ref (surface->buf);
743       } else {
744         gst_video_frame_copy (&surface->copy, &surface->data);
745         frame->output_buffer = gst_buffer_ref (surface->copy.buffer);
746         unmap_frame (thiz, surface);
747       }
748       GST_DEBUG_OBJECT (thiz, "surface %p TimeStamp: %" G_GUINT64_FORMAT
749           " frame %p TimeStamp: %" G_GUINT64_FORMAT,
750           surface->surface, (guint64) surface->surface->Data.TimeStamp,
751           frame, GST_TO_MFX_TIME (frame->pts));
752     }
753 
754     finish_task (thiz, task);
755 
756     if (!frame)
757       return GST_FLOW_FLUSHING;
758 
759     if (decode_only)
760       GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
761     flow = gst_video_decoder_finish_frame (decoder, frame);
762     if (flow == GST_FLOW_ERROR)
763       GST_ERROR_OBJECT (thiz, "Failed to finish frame");
764     return flow;
765   }
766   finish_task (thiz, task);
767   return GST_FLOW_OK;
768 }
769 
770 static gboolean
gst_msdkdec_context_prepare(GstMsdkDec * thiz)771 gst_msdkdec_context_prepare (GstMsdkDec * thiz)
772 {
773   /* Try to find an existing context from the pipeline. This may (indirectly)
774    * invoke gst_msdkdec_set_context, which will set thiz->context. */
775   if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
776     return FALSE;
777 
778   if (thiz->context == thiz->old_context) {
779     GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
780         ", reusing as-is", thiz->context);
781     return TRUE;
782   }
783 
784   /* TODO: Currently d3d allocator is not implemented.
785    * So decoder uses system memory by default on Windows.
786    */
787 #ifndef _WIN32
788   thiz->use_video_memory = TRUE;
789 #else
790   thiz->use_video_memory = FALSE;
791 #endif
792 
793   GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
794       thiz->context);
795 
796   if (!(gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_DECODER)) {
797     gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_DECODER);
798     return TRUE;
799   }
800 
801   /* Found an existing context that's already being used as a decoder, clone
802    * the MFX session inside it to create a new one */
803   {
804     GstMsdkContext *parent_context, *msdk_context;
805 
806     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
807         "joined session", thiz->context);
808     parent_context = thiz->context;
809     msdk_context = gst_msdk_context_new_with_parent (parent_context);
810 
811     if (!msdk_context) {
812       GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
813           "as %" GST_PTR_FORMAT, parent_context);
814       return FALSE;
815     }
816 
817     thiz->context = msdk_context;
818     gst_msdk_context_add_shared_async_depth (thiz->context,
819         gst_msdk_context_get_shared_async_depth (parent_context));
820     gst_object_unref (parent_context);
821   }
822 
823   return TRUE;
824 }
825 
826 static gboolean
gst_msdkdec_start(GstVideoDecoder * decoder)827 gst_msdkdec_start (GstVideoDecoder * decoder)
828 {
829   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
830 
831   if (!gst_msdkdec_context_prepare (thiz)) {
832     if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
833             thiz->hardware, GST_MSDK_JOB_DECODER))
834       return FALSE;
835     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
836         thiz->context);
837   }
838 
839   /* Save the current context in a separate field so that we know whether it
840    * has changed between calls to _start() */
841   gst_object_replace ((GstObject **) & thiz->old_context,
842       (GstObject *) thiz->context);
843 
844   gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
845 
846   return TRUE;
847 }
848 
849 static gboolean
gst_msdkdec_close(GstVideoDecoder * decoder)850 gst_msdkdec_close (GstVideoDecoder * decoder)
851 {
852   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
853 
854   gst_clear_object (&thiz->context);
855 
856   return TRUE;
857 }
858 
859 static gboolean
gst_msdkdec_stop(GstVideoDecoder * decoder)860 gst_msdkdec_stop (GstVideoDecoder * decoder)
861 {
862   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
863 
864   gst_msdkdec_flush (decoder);
865 
866   if (thiz->input_state) {
867     gst_video_codec_state_unref (thiz->input_state);
868     thiz->input_state = NULL;
869   }
870   if (thiz->pool) {
871     gst_object_unref (thiz->pool);
872     thiz->pool = NULL;
873   }
874   gst_video_info_init (&thiz->non_msdk_pool_info);
875 
876   gst_msdkdec_close_decoder (thiz, TRUE);
877   return TRUE;
878 }
879 
880 static gboolean
gst_msdkdec_set_format(GstVideoDecoder * decoder,GstVideoCodecState * state)881 gst_msdkdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
882 {
883   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
884 
885   if (thiz->input_state) {
886     /* mark for re-negotiation if display resolution or any other video info
887      * changes like framerate. */
888     if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
889       GST_INFO_OBJECT (thiz, "Schedule renegotiation as video info changed");
890       thiz->do_renego = TRUE;
891     }
892     gst_video_codec_state_unref (thiz->input_state);
893   }
894   thiz->input_state = gst_video_codec_state_ref (state);
895 
896   /* we don't set output state here to avoid caching of mismatched
897    * video information if there is dynamic resolution change in the stream.
898    * All negotiation code is consolidated in gst_msdkdec_negotiate() and
899    * this will be invoked from handle_frame() */
900 
901   gst_msdkdec_set_latency (thiz);
902   return TRUE;
903 }
904 
905 static void
release_msdk_surfaces(GstMsdkDec * thiz)906 release_msdk_surfaces (GstMsdkDec * thiz)
907 {
908   GList *l;
909   MsdkSurface *surface;
910   gint locked = 0;
911   gst_msdkdec_free_unlocked_msdk_surfaces (thiz);
912 
913   for (l = thiz->locked_msdk_surfaces; l; l = l->next) {
914     surface = (MsdkSurface *) l->data;
915     unmap_frame (thiz, surface);
916     free_surface (surface);
917     locked++;
918   }
919   if (locked)
920     GST_ERROR_OBJECT (thiz, "msdk still locked %d surfaces", locked);
921   g_list_free (thiz->locked_msdk_surfaces);
922   thiz->locked_msdk_surfaces = NULL;
923 }
924 
925 /* This will get invoked in the following situations:
926  * 1: beginning of the stream, which requires initialization (== complete reset)
927  * 2: upstream notified a resolution change and set do_renego to TRUE.
928  *    new resolution may or may not requires full reset
929  * 3: upstream failed to notify the resolution change but
930  *    msdk detected the change (eg: vp9 stream in ivf elementary form
931  *     with varying resolution frames).
932  *
933  * for any input configuration change, we deal with notification
934  * from upstream and also use msdk APIs to handle the parameter initialization
935  * efficiently
936  */
937 static gboolean
gst_msdkdec_negotiate(GstMsdkDec * thiz,gboolean hard_reset)938 gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset)
939 {
940   GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
941   GST_DEBUG_OBJECT (thiz,
942       "Start Negotiating caps, pool and Init the msdk decdoer subsystem");
943 
944   if (hard_reset) {
945     /* Retrieve any pending frames and push them downstream */
946     if (gst_msdkdec_drain (GST_VIDEO_DECODER (thiz)) != GST_FLOW_OK)
947       goto error_drain;
948 
949     /* This will initiate the allocation query which will help to flush
950      * all the pending buffers in the pipeline so that we can stop
951      * the active bufferpool and safely invoke gst_msdk_frame_free() */
952     if (thiz->initialized) {
953       GstCaps *caps = gst_pad_get_current_caps (decoder->srcpad);
954       GstQuery *query = NULL;
955       if (caps) {
956         query = gst_query_new_allocation (caps, FALSE);
957         gst_pad_peer_query (decoder->srcpad, query);
958         gst_query_unref (query);
959         gst_caps_unref (caps);
960       }
961     }
962 
963     /* De-initialize the decoder if it is already active */
964     /* Do not reset the mfxVideoParam since it already
965      * has the required parameters for new session decode */
966     gst_msdkdec_close_decoder (thiz, FALSE);
967 
968     /* request for pool re-negotiation by setting do_realloc */
969     thiz->do_realloc = TRUE;
970   }
971 
972   /* At this point all pending frames (if there are any) are pushed downstream
973    * and we are ready to negotiate the output caps */
974   if (!gst_msdkdec_set_src_caps (thiz, hard_reset))
975     return FALSE;
976 
977   /* this will initiate the allocation query, we create the
978    * bufferpool in decide_allocation in order to account
979    * for the downstream min_buffer requirement
980    * Required initializations for MediaSDK operations
981    * will all be initialized from decide_allocation after considering
982    * some of the downstream requirements */
983   if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (thiz)))
984     goto error_negotiate;
985 
986   thiz->do_renego = FALSE;
987   thiz->do_realloc = FALSE;
988 
989   return TRUE;
990 
991 error_drain:
992   GST_ERROR_OBJECT (thiz, "Failed to Drain the queued decoded frames");
993   return FALSE;
994 
995 error_negotiate:
996   GST_ERROR_OBJECT (thiz, "Failed to re-negotiate");
997   return FALSE;
998 }
999 
1000 static inline gboolean
find_msdk_surface(GstMsdkDec * thiz,MsdkDecTask * task,mfxFrameSurface1 * out_surface)1001 find_msdk_surface (GstMsdkDec * thiz, MsdkDecTask * task,
1002     mfxFrameSurface1 * out_surface)
1003 {
1004   GList *l;
1005   task->surface = NULL;
1006   if (!out_surface)
1007     return TRUE;
1008   l = g_list_find_custom (thiz->locked_msdk_surfaces, out_surface,
1009       _find_msdk_surface);
1010   if (!l) {
1011     GST_ERROR_OBJECT (thiz, "msdk return an invalid surface %p", out_surface);
1012     return FALSE;
1013   }
1014   task->surface = (MsdkSurface *) l->data;
1015   thiz->locked_msdk_surfaces =
1016       g_list_delete_link (thiz->locked_msdk_surfaces, l);
1017   return TRUE;
1018 }
1019 
1020 static void
gst_msdkdec_error_report(GstMsdkDec * thiz)1021 gst_msdkdec_error_report (GstMsdkDec * thiz)
1022 {
1023   if (!thiz->report_error)
1024     return;
1025 
1026 #if (MFX_VERSION >= 1025)
1027   else {
1028     if (thiz->error_report.ErrorTypes & MFX_ERROR_SPS)
1029       GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1030           ("[Error] SPS Error detected!"), (NULL));
1031 
1032     if (thiz->error_report.ErrorTypes & MFX_ERROR_PPS)
1033       GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1034           ("[Error] PPS Error detected!"), (NULL));
1035 
1036     if (thiz->error_report.ErrorTypes & MFX_ERROR_SLICEHEADER)
1037       GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1038           ("[Error] SliceHeader Error detected!"), (NULL));
1039 
1040     if (thiz->error_report.ErrorTypes & MFX_ERROR_FRAME_GAP)
1041       GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1042           ("[Error] Frame Gap Error detected!"), (NULL));
1043   }
1044 #endif
1045 }
1046 
1047 static GstFlowReturn
gst_msdkdec_handle_frame(GstVideoDecoder * decoder,GstVideoCodecFrame * frame)1048 gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
1049 {
1050   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1051   GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
1052   GstFlowReturn flow;
1053   GstBuffer *buffer, *input_buffer = NULL;
1054   GstVideoInfo alloc_info;
1055   MsdkDecTask *task = NULL;
1056   mfxBitstream bitstream;
1057   MsdkSurface *surface = NULL;
1058   mfxFrameSurface1 *out_surface = NULL;
1059   mfxSession session;
1060   mfxStatus status;
1061   GstMapInfo map_info;
1062   guint i, retry_err_incompatible = 0;
1063   gsize data_size;
1064   gboolean hard_reset = FALSE;
1065   GstClockTime pts = GST_CLOCK_TIME_NONE;
1066 
1067   /* configure the subclass in order to fill the CodecID field of
1068    * mfxVideoParam and also to load the PluginID for some of the
1069    * codecs which is mandatory to invoke the
1070    * MFXVideoDECODE_DecodeHeader API.
1071    *
1072    * For non packetized formats (currently only vc1), there
1073    * could be headers received as codec_data which are not available
1074    * instream and in that case subclass implementation will
1075    * push it to the internal adapter. We invoke the subclass configure
1076    * well early to make sure the codec_data received has been correctly
1077    * pushed to the adapter by the subclasses before doing
1078    * the DecodeHeader() later on
1079    */
1080   if (!thiz->initialized || thiz->do_renego) {
1081     /* Clear the internal adapter in re-negotiation for non-packetized
1082      * formats */
1083     if (!gst_video_decoder_get_packetized (decoder))
1084       gst_adapter_clear (thiz->adapter);
1085 
1086     if (!klass->configure || !klass->configure (thiz)) {
1087       flow = GST_FLOW_OK;
1088       goto error;
1089     }
1090   }
1091 
1092   /* Current frame-codec could be pushed and released before this
1093    * function ends -- because msdkdec pushes the oldest frame,
1094    * according its PTS, and it could be this very same frame-codec
1095    * among others pending frame-codecs.
1096    *
1097    * Instead of copying the input data into the mfxBitstream, let's
1098    * keep an extra reference to frame-codec's input buffer */
1099   input_buffer = gst_buffer_ref (frame->input_buffer);
1100   if (!gst_buffer_map (input_buffer, &map_info, GST_MAP_READ)) {
1101     gst_buffer_unref (input_buffer);
1102     return GST_FLOW_ERROR;
1103   }
1104 
1105   memset (&bitstream, 0, sizeof (bitstream));
1106 
1107   /* Add extended buffers */
1108   if (thiz->num_bs_extra_params) {
1109     bitstream.NumExtParam = thiz->num_bs_extra_params;
1110     bitstream.ExtParam = thiz->bs_extra_params;
1111   }
1112 
1113   if (gst_video_decoder_get_packetized (decoder)) {
1114     /* Packetized stream: we prefer to have a parser as a connected upstream
1115      * element to the decoder */
1116     pts = frame->pts;
1117     bitstream.Data = map_info.data;
1118     bitstream.DataLength = map_info.size;
1119     bitstream.MaxLength = map_info.size;
1120     bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
1121 
1122     /*
1123      * MFX_BITSTREAM_COMPLETE_FRAME was removed since commit df59db9, however
1124      * some customers still use DecodedOrder (deprecated in msdk-2017 version)
1125      * for low-latency streaming of non-b-frame encoded streams, which needs to
1126      * output the frame at once, so add it back for this case
1127      */
1128     if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1129       bitstream.DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME;
1130   } else {
1131     /* Non packetized streams: eg: vc1 advanced profile with per buffer bdu */
1132     gst_adapter_push (thiz->adapter, gst_buffer_ref (input_buffer));
1133     data_size = gst_adapter_available (thiz->adapter);
1134 
1135     bitstream.Data = (mfxU8 *) gst_adapter_map (thiz->adapter, data_size);
1136     bitstream.DataLength = (mfxU32) data_size;
1137     bitstream.MaxLength = bitstream.DataLength;
1138     bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
1139   }
1140   GST_DEBUG_OBJECT (thiz,
1141       "mfxBitStream=> DataLength:%d DataOffset:%d MaxLength:%d "
1142       "PTS: %" GST_TIME_FORMAT " MFX TimeStamp %" G_GUINT64_FORMAT,
1143       bitstream.DataLength, bitstream.DataOffset, bitstream.MaxLength,
1144       GST_TIME_ARGS (pts), (guint64) bitstream.TimeStamp);
1145 
1146   session = gst_msdk_context_get_session (thiz->context);
1147 
1148   if (!thiz->initialized || thiz->do_renego) {
1149 
1150     /* gstreamer caps will not provide all the necessary parameters
1151      * required for optimal decode configuration. For example: the required number
1152      * of surfaces to be allocated can be calculated based on H264 SEI header
1153      * and this information can't be retrieved from the negotiated caps.
1154      * So instead of introducing a codecparser dependency to parse the headers
1155      * inside msdk plugin, we simply use the mfx APIs to extract header information */
1156 #if (MFX_VERSION >= 1025)
1157     if (thiz->report_error)
1158       thiz->error_report.ErrorTypes = 0;
1159 #endif
1160 
1161     status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1162     GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1163     gst_msdkdec_error_report (thiz);
1164 
1165     if (status == MFX_ERR_MORE_DATA) {
1166       flow = GST_FLOW_OK;
1167       goto done;
1168     }
1169 
1170     if (!klass->post_configure (thiz)) {
1171       flow = GST_FLOW_ERROR;
1172       goto error;
1173     }
1174 
1175     if (!thiz->initialized)
1176       hard_reset = TRUE;
1177     else {
1178       GstVideoCodecState *output_state =
1179           gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1180       if (output_state) {
1181         if (output_state->allocation_caps) {
1182           gst_video_info_from_caps (&alloc_info, output_state->allocation_caps);
1183 
1184           /* Check whether we need complete reset for dynamic resolution change */
1185           if (thiz->param.mfx.FrameInfo.Width >
1186               GST_VIDEO_INFO_WIDTH (&alloc_info)
1187               || thiz->param.mfx.FrameInfo.Height >
1188               GST_VIDEO_INFO_HEIGHT (&alloc_info))
1189             hard_reset = TRUE;
1190         }
1191         gst_video_codec_state_unref (output_state);
1192       }
1193 
1194     }
1195 
1196     /* if subclass requested for the force reset */
1197     if (thiz->force_reset_on_res_change)
1198       hard_reset = TRUE;
1199 
1200     if (!gst_msdkdec_negotiate (thiz, hard_reset)) {
1201       GST_ELEMENT_ERROR (thiz, CORE, NEGOTIATION,
1202           ("Could not negotiate the stream"), (NULL));
1203       flow = GST_FLOW_ERROR;
1204       goto error;
1205     }
1206   }
1207 
1208   /* gst_msdkdec_handle_frame owns one ref on input argument |frame|. At this
1209    * point this frame is not used so just unref it right away.
1210    * gst_msdkdec_finish_task is fetching the frames itself.  */
1211   gst_video_codec_frame_unref (frame);
1212   frame = NULL;
1213   for (;;) {
1214     task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1215     flow = gst_msdkdec_finish_task (thiz, task);
1216     if (flow != GST_FLOW_OK) {
1217       if (flow == GST_FLOW_ERROR)
1218         GST_ERROR_OBJECT (thiz, "Failed to finish a task");
1219       goto error;
1220     }
1221     if (!surface) {
1222       flow = allocate_output_buffer (thiz, &buffer);
1223       if (flow == GST_FLOW_CUSTOM_SUCCESS) {
1224         flow = GST_FLOW_OK;
1225         break;
1226       } else if (flow != GST_FLOW_OK)
1227         goto error;
1228       surface = get_surface (thiz, buffer);
1229       if (!surface) {
1230         /* Can't get a surface for some reason; finish tasks, then see if
1231            a surface becomes available. */
1232         for (i = 0; i < thiz->tasks->len - 1; i++) {
1233           thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1234           task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1235           flow = gst_msdkdec_finish_task (thiz, task);
1236           if (flow != GST_FLOW_OK)
1237             goto error;
1238           surface = get_surface (thiz, buffer);
1239           if (surface)
1240             break;
1241         }
1242         if (!surface) {
1243           GST_ERROR_OBJECT (thiz, "Couldn't get a surface");
1244           flow = GST_FLOW_ERROR;
1245           goto error;
1246         }
1247       }
1248     }
1249 #if (MFX_VERSION >= 1025)
1250     if (thiz->report_error)
1251       thiz->error_report.ErrorTypes = 0;
1252 #endif
1253 
1254     status =
1255         MFXVideoDECODE_DecodeFrameAsync (session, &bitstream, surface->surface,
1256         &out_surface, &task->sync_point);
1257 
1258     if (!find_msdk_surface (thiz, task, out_surface)) {
1259       flow = GST_FLOW_ERROR;
1260       goto done;
1261     }
1262 
1263     GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1264     gst_msdkdec_error_report (thiz);
1265 
1266     /* media-sdk requires complete reset since the surface is inadequate
1267      * for further decoding */
1268     if (status == MFX_ERR_INCOMPATIBLE_VIDEO_PARAM &&
1269         retry_err_incompatible++ < 1) {
1270       /* MFX_ERR_INCOMPATIBLE_VIDEO_PARAM means the current mfx surface is not
1271        * suitable for the current frame. Call MFXVideoDECODE_DecodeHeader to get
1272        * the current frame size, then do memory re-allocation, otherwise
1273        * MFXVideoDECODE_DecodeFrameAsync will still fail on next call */
1274 #if (MFX_VERSION >= 1025)
1275       if (thiz->report_error)
1276         thiz->error_report.ErrorTypes = 0;
1277 #endif
1278       status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1279       GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1280       gst_msdkdec_error_report (thiz);
1281 
1282       if (status == MFX_ERR_MORE_DATA) {
1283         flow = GST_FLOW_OK;
1284         goto done;
1285       }
1286 
1287       /* Requires memory re-allocation, do a hard reset */
1288       if (!gst_msdkdec_negotiate (thiz, TRUE))
1289         goto error;
1290 
1291       /* The current surface is freed when doing a hard reset; a new surface is
1292        * required for the new resolution */
1293       surface = NULL;
1294       continue;
1295     }
1296 
1297     retry_err_incompatible = 0;
1298 
1299     if (G_LIKELY (status == MFX_ERR_NONE)
1300         || (status == MFX_WRN_VIDEO_PARAM_CHANGED)) {
1301       thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1302 
1303       if (surface->surface->Data.Locked > 0)
1304         surface = NULL;
1305 
1306       if (bitstream.DataLength == 0) {
1307         flow = GST_FLOW_OK;
1308 
1309         /* Don't release it if the current surface is in use */
1310         if (surface && task->surface->surface == surface->surface)
1311           surface = NULL;
1312 
1313         break;
1314       }
1315     } else if (status == MFX_ERR_MORE_DATA) {
1316       if (task->surface) {
1317         task->decode_only = TRUE;
1318         thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1319       }
1320 
1321       if (surface->surface->Data.Locked > 0)
1322         surface = NULL;
1323       flow = GST_VIDEO_DECODER_FLOW_NEED_DATA;
1324       break;
1325     } else if (status == MFX_ERR_MORE_SURFACE) {
1326       surface = NULL;
1327       continue;
1328     } else if (status == MFX_WRN_DEVICE_BUSY) {
1329       /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
1330       g_usleep (1000);
1331 
1332       if (surface->surface->Data.Locked > 0)
1333         surface = NULL;
1334 
1335       /* If the current surface is still busy, we should do sync operation,
1336        * then try to decode again
1337        */
1338       thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1339     } else if (status < MFX_ERR_NONE) {
1340       GST_ERROR_OBJECT (thiz, "DecodeFrameAsync failed (%s)",
1341           msdk_status_to_string (status));
1342       flow = GST_FLOW_ERROR;
1343       break;
1344     }
1345   }
1346 
1347   if (!gst_video_decoder_get_packetized (decoder)) {
1348     /* flush out the data which has already been consumed by msdk */
1349     gst_adapter_flush (thiz->adapter, bitstream.DataOffset);
1350   }
1351 
1352   /*
1353    * DecodedOrder was deprecated in msdk-2017 version, but some
1354    * customers still using this for low-latency streaming of non-b-frame
1355    * encoded streams, which needs to output the frame at once
1356    */
1357   if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1358     gst_msdkdec_finish_task (thiz, task);
1359 
1360 done:
1361   gst_buffer_unmap (input_buffer, &map_info);
1362   gst_buffer_unref (input_buffer);
1363   return flow;
1364 
1365 error:
1366   if (input_buffer) {
1367     gst_buffer_unmap (input_buffer, &map_info);
1368     gst_buffer_unref (input_buffer);
1369   }
1370   if (frame)
1371     gst_video_decoder_drop_frame (decoder, frame);
1372 
1373   return flow;
1374 }
1375 
1376 static GstFlowReturn
gst_msdkdec_parse(GstVideoDecoder * decoder,GstVideoCodecFrame * frame,GstAdapter * adapter,gboolean at_eos)1377 gst_msdkdec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
1378     GstAdapter * adapter, gboolean at_eos)
1379 {
1380   gsize size;
1381   GstFlowReturn ret;
1382   GstBuffer *buffer;
1383   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1384 
1385   /* Don't parse the input buffer indeed, it will invoke
1386    * gst_msdkdec_handle_frame to handle the input buffer */
1387   size = gst_adapter_available (adapter);
1388   gst_video_decoder_add_to_frame (decoder, size);
1389   ret = gst_video_decoder_have_frame (decoder);
1390   size = gst_adapter_available (thiz->adapter);
1391 
1392   if (size) {
1393     /* The base class will set up a new frame for parsing as
1394      * soon as there is valid data in the buffer */
1395     buffer = gst_adapter_get_buffer (thiz->adapter, size);
1396     gst_adapter_flush (thiz->adapter, size);
1397     gst_adapter_push (adapter, buffer);
1398   }
1399 
1400   return ret;
1401 }
1402 
1403 static GstBufferPool *
gst_msdkdec_create_buffer_pool(GstMsdkDec * thiz,GstVideoInfo * info,guint num_buffers)1404 gst_msdkdec_create_buffer_pool (GstMsdkDec * thiz, GstVideoInfo * info,
1405     guint num_buffers)
1406 {
1407   GstBufferPool *pool = NULL;
1408   GstStructure *config;
1409   GstAllocator *allocator = NULL;
1410   GstVideoAlignment align;
1411   GstCaps *caps = NULL;
1412   GstAllocationParams params = { 0, 31, 0, 0, };
1413   mfxFrameAllocResponse *alloc_resp = NULL;
1414 
1415   g_return_val_if_fail (info, NULL);
1416   g_return_val_if_fail (GST_VIDEO_INFO_WIDTH (info)
1417       && GST_VIDEO_INFO_HEIGHT (info), NULL);
1418 
1419   alloc_resp = &thiz->alloc_resp;
1420 
1421   pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
1422   if (!pool)
1423     goto error_no_pool;
1424 
1425   caps = gst_video_info_to_caps (info);
1426 
1427   /* allocators should use the same width/height/stride/height_alignment of
1428    * negotiated output caps, which is what we configure in msdk_allocator */
1429   if (thiz->use_dmabuf)
1430     allocator = gst_msdk_dmabuf_allocator_new (thiz->context, info, alloc_resp);
1431   else if (thiz->use_video_memory)
1432     allocator = gst_msdk_video_allocator_new (thiz->context, info, alloc_resp);
1433   else
1434     allocator = gst_msdk_system_allocator_new (info);
1435 
1436   if (!allocator) {
1437     gst_caps_unref (caps);
1438     goto error_no_allocator;
1439   }
1440 
1441   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1442   /* we need register all bufffers when we create the msdk context, so the buffer pool is not resize able */
1443   gst_buffer_pool_config_set_params (config, caps,
1444       GST_VIDEO_INFO_SIZE (info), num_buffers, num_buffers);
1445   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1446   gst_buffer_pool_config_add_option (config,
1447       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1448   gst_caps_unref (caps);
1449 
1450   if (thiz->use_video_memory) {
1451     gst_buffer_pool_config_add_option (config,
1452         GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1453     if (thiz->use_dmabuf)
1454       gst_buffer_pool_config_add_option (config,
1455           GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1456   }
1457 
1458 
1459   gst_buffer_pool_config_set_video_alignment (config, &align);
1460   gst_buffer_pool_config_set_allocator (config, allocator, &params);
1461   gst_object_unref (allocator);
1462 
1463   if (!gst_buffer_pool_set_config (pool, config))
1464     goto error_pool_config;
1465 
1466   return pool;
1467 
1468 error_no_pool:
1469   {
1470     GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1471     return NULL;
1472   }
1473 error_no_allocator:
1474   {
1475     GST_INFO_OBJECT (thiz, "failed to create allocator");
1476     gst_object_unref (pool);
1477     return NULL;
1478   }
1479 error_pool_config:
1480   {
1481     GST_INFO_OBJECT (thiz, "failed to set config");
1482     gst_object_unref (pool);
1483     gst_object_unref (allocator);
1484     return NULL;
1485   }
1486 }
1487 
1488 static gboolean
gst_msdkdec_decide_allocation(GstVideoDecoder * decoder,GstQuery * query)1489 gst_msdkdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1490 {
1491   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1492   GstBufferPool *pool = NULL;
1493   GstStructure *pool_config = NULL;
1494   GstCaps *pool_caps /*, *negotiated_caps */ ;
1495   guint size, min_buffers, max_buffers;
1496 
1497   if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
1498           query))
1499     return FALSE;
1500 
1501   /* Get the buffer pool config decided on by the base class. The base
1502      class ensures that there will always be at least a 0th pool in
1503      the query. */
1504   gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1505   pool_config = gst_buffer_pool_get_config (pool);
1506 
1507   /* Get the caps of pool and increase the min and max buffers by async_depth.
1508    * We will always have that number of decode operations in-flight */
1509   gst_buffer_pool_config_get_params (pool_config, &pool_caps, &size,
1510       &min_buffers, &max_buffers);
1511   min_buffers += thiz->async_depth;
1512   if (max_buffers)
1513     max_buffers += thiz->async_depth;
1514 
1515   /* increase the min_buffers by 1 for smooth display in render pipeline */
1516   min_buffers += 1;
1517 
1518   /* this will get updated with msdk requirement */
1519   thiz->min_prealloc_buffers = min_buffers;
1520 
1521   if (_gst_caps_has_feature (pool_caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
1522     GST_INFO_OBJECT (decoder, "This MSDK decoder uses DMABuf memory");
1523     thiz->use_video_memory = thiz->use_dmabuf = TRUE;
1524   }
1525 
1526   /* Initialize MSDK decoder before new bufferpool tries to alloc each buffer,
1527    * which requires information about frame allocation.
1528    * No effect if already initialized.
1529    */
1530   if (!gst_msdkdec_init_decoder (thiz))
1531     return FALSE;
1532 
1533   /* get the updated min_buffers, which account for the msdk requirement as well */
1534   min_buffers = thiz->min_prealloc_buffers;
1535 
1536   /* Decoder always use its own pool. So we create a pool if msdk APIs
1537    * previously requested for allocation (do_realloc = TRUE) */
1538   if (thiz->do_realloc || !thiz->pool) {
1539     GstVideoCodecState *output_state =
1540         gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1541     gst_clear_object (&thiz->pool);
1542     GST_INFO_OBJECT (decoder, "create new MSDK bufferpool");
1543     thiz->pool =
1544         gst_msdkdec_create_buffer_pool (thiz, &output_state->info, min_buffers);
1545     gst_video_codec_state_unref (output_state);
1546     if (!thiz->pool) {
1547       GST_ERROR_OBJECT (decoder, "failed to create new pool");
1548       goto failed_to_create_pool;
1549     }
1550   }
1551 
1552   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)
1553       && gst_buffer_pool_has_option (pool,
1554           GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
1555     GstStructure *config;
1556     GstAllocator *allocator;
1557 
1558     /* If downstream supports video meta and video alignment,
1559      * we can replace with our own msdk bufferpool and use it
1560      */
1561     /* Remove downstream's pool */
1562     gst_structure_free (pool_config);
1563     gst_object_unref (pool);
1564 
1565     pool = gst_object_ref (thiz->pool);
1566 
1567     /* Set the allocator of new msdk bufferpool */
1568     config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1569 
1570     if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1571       gst_query_set_nth_allocation_param (query, 0, allocator, NULL);
1572     gst_structure_free (config);
1573   } else {
1574     /* Unfortunately, downstream doesn't have videometa or alignment support,
1575      * we keep msdk pool as a side-pool that will be decoded into and
1576      * then copied from.
1577      */
1578     GstVideoCodecState *output_state = NULL;
1579 
1580     GST_INFO_OBJECT (decoder, "Keep MSDK bufferpool as a side-pool");
1581 
1582     /* Update params to downstream's pool */
1583     gst_buffer_pool_config_set_params (pool_config, pool_caps, size,
1584         min_buffers, max_buffers);
1585     if (!gst_buffer_pool_set_config (pool, pool_config))
1586       goto error_set_config;
1587     gst_video_info_from_caps (&thiz->non_msdk_pool_info, pool_caps);
1588 
1589     /* update width and height with actual negotiated values */
1590     output_state =
1591         gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1592     GST_VIDEO_INFO_WIDTH (&thiz->non_msdk_pool_info) =
1593         GST_VIDEO_INFO_WIDTH (&output_state->info);
1594     GST_VIDEO_INFO_HEIGHT (&thiz->non_msdk_pool_info) =
1595         GST_VIDEO_INFO_HEIGHT (&output_state->info);
1596     gst_video_codec_state_unref (output_state);
1597   }
1598 
1599   gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
1600       max_buffers);
1601 
1602   if (pool)
1603     gst_object_unref (pool);
1604 
1605 
1606   return TRUE;
1607 
1608 failed_to_create_pool:
1609   GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1610   if (pool)
1611     gst_object_unref (pool);
1612   return FALSE;
1613 
1614 error_set_config:
1615   GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1616   if (pool)
1617     gst_object_unref (pool);
1618   return FALSE;
1619 }
1620 
1621 static GstFlowReturn
gst_msdkdec_drain(GstVideoDecoder * decoder)1622 gst_msdkdec_drain (GstVideoDecoder * decoder)
1623 {
1624   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1625   GstFlowReturn flow;
1626   GstBuffer *buffer;
1627   MsdkDecTask *task;
1628   MsdkSurface *surface = NULL;
1629   mfxFrameSurface1 *out_surface;
1630   mfxSession session;
1631   mfxStatus status;
1632   guint i;
1633 
1634   if (!thiz->initialized)
1635     return GST_FLOW_OK;
1636   session = gst_msdk_context_get_session (thiz->context);
1637 
1638   for (;;) {
1639     task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1640     if ((flow = gst_msdkdec_finish_task (thiz, task)) != GST_FLOW_OK) {
1641       if (flow != GST_FLOW_FLUSHING)
1642         GST_WARNING_OBJECT (decoder,
1643             "failed to finish the task %p, but keep draining for the remaining frames",
1644             task);
1645     }
1646 
1647     if (!surface) {
1648       flow = allocate_output_buffer (thiz, &buffer);
1649       if (flow != GST_FLOW_OK)
1650         return flow;
1651       surface = get_surface (thiz, buffer);
1652       if (!surface)
1653         return GST_FLOW_ERROR;
1654     }
1655 #if (MFX_VERSION >= 1025)
1656     if (thiz->report_error)
1657       thiz->error_report.ErrorTypes = 0;
1658 #endif
1659 
1660     status =
1661         MFXVideoDECODE_DecodeFrameAsync (session, NULL, surface->surface,
1662         &out_surface, &task->sync_point);
1663 
1664     if (!find_msdk_surface (thiz, task, out_surface)) {
1665       return GST_FLOW_ERROR;
1666     }
1667 
1668     GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1669     gst_msdkdec_error_report (thiz);
1670 
1671     if (G_LIKELY (status == MFX_ERR_NONE)) {
1672       thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1673       surface = NULL;
1674     } else if (status == MFX_WRN_VIDEO_PARAM_CHANGED) {
1675       continue;
1676     } else if (status == MFX_WRN_DEVICE_BUSY) {
1677       /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1678       g_usleep (1000);
1679 
1680       /* If the current surface is still busy, we should do sync operation,
1681        * then try to decode again
1682        */
1683       thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1684     } else if (status == MFX_ERR_MORE_DATA) {
1685       break;
1686     } else if (status == MFX_ERR_MORE_SURFACE) {
1687       surface = NULL;
1688       continue;
1689     } else if (status < MFX_ERR_NONE)
1690       return GST_FLOW_ERROR;
1691   }
1692 
1693   for (i = 0; i < thiz->tasks->len; i++) {
1694     task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1695     gst_msdkdec_finish_task (thiz, task);
1696     thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1697   }
1698 
1699   return GST_FLOW_OK;
1700 }
1701 
1702 static gboolean
gst_msdkdec_flush(GstVideoDecoder * decoder)1703 gst_msdkdec_flush (GstVideoDecoder * decoder)
1704 {
1705   GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1706   GstFlowReturn ret;
1707 
1708   ret = gst_msdkdec_drain (GST_VIDEO_DECODER_CAST (thiz));
1709 
1710   return ret == GST_FLOW_OK;
1711 }
1712 
1713 static GstFlowReturn
gst_msdkdec_finish(GstVideoDecoder * decoder)1714 gst_msdkdec_finish (GstVideoDecoder * decoder)
1715 {
1716   return gst_msdkdec_drain (decoder);
1717 }
1718 
1719 static void
gst_msdkdec_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1720 gst_msdkdec_set_property (GObject * object, guint prop_id, const GValue * value,
1721     GParamSpec * pspec)
1722 {
1723   GstMsdkDec *thiz = GST_MSDKDEC (object);
1724   GstState state;
1725 
1726   GST_OBJECT_LOCK (thiz);
1727 
1728   state = GST_STATE (thiz);
1729   if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1730       !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
1731     goto wrong_state;
1732 
1733   switch (prop_id) {
1734     case GST_MSDKDEC_PROP_HARDWARE:
1735       thiz->hardware = g_value_get_boolean (value);
1736       break;
1737     case GST_MSDKDEC_PROP_ASYNC_DEPTH:
1738       thiz->async_depth = g_value_get_uint (value);
1739       break;
1740     default:
1741       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1742       break;
1743   }
1744   GST_OBJECT_UNLOCK (thiz);
1745   return;
1746 
1747   /* ERROR */
1748 wrong_state:
1749   {
1750     GST_WARNING_OBJECT (thiz, "setting property in wrong state");
1751     GST_OBJECT_UNLOCK (thiz);
1752   }
1753 }
1754 
1755 static void
gst_msdkdec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1756 gst_msdkdec_get_property (GObject * object, guint prop_id, GValue * value,
1757     GParamSpec * pspec)
1758 {
1759   GstMsdkDec *thiz = GST_MSDKDEC (object);
1760 
1761   GST_OBJECT_LOCK (thiz);
1762   switch (prop_id) {
1763     case GST_MSDKDEC_PROP_HARDWARE:
1764       g_value_set_boolean (value, thiz->hardware);
1765       break;
1766     case GST_MSDKDEC_PROP_ASYNC_DEPTH:
1767       g_value_set_uint (value, thiz->async_depth);
1768       break;
1769     default:
1770       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1771       break;
1772   }
1773   GST_OBJECT_UNLOCK (thiz);
1774 }
1775 
1776 static void
gst_msdkdec_dispose(GObject * object)1777 gst_msdkdec_dispose (GObject * object)
1778 {
1779   GstMsdkDec *thiz = GST_MSDKDEC (object);
1780 
1781   g_clear_object (&thiz->adapter);
1782   gst_clear_object (&thiz->context);
1783   gst_clear_object (&thiz->old_context);
1784 
1785   G_OBJECT_CLASS (parent_class)->dispose (object);
1786 }
1787 
1788 static void
gst_msdkdec_finalize(GObject * object)1789 gst_msdkdec_finalize (GObject * object)
1790 {
1791   GstMsdkDec *thiz = GST_MSDKDEC (object);
1792 
1793   g_array_unref (thiz->tasks);
1794   thiz->tasks = NULL;
1795 
1796   release_msdk_surfaces (thiz);
1797 
1798   G_OBJECT_CLASS (parent_class)->finalize (object);
1799 }
1800 
1801 static gboolean
gst_msdkdec_post_configure(GstMsdkDec * decoder)1802 gst_msdkdec_post_configure (GstMsdkDec * decoder)
1803 {
1804   /* Do nothing */
1805   return TRUE;
1806 }
1807 
1808 static gboolean
gst_msdkdec_preinit_decoder(GstMsdkDec * decoder)1809 gst_msdkdec_preinit_decoder (GstMsdkDec * decoder)
1810 {
1811   decoder->param.mfx.FrameInfo.Width =
1812       GST_ROUND_UP_16 (decoder->param.mfx.FrameInfo.Width);
1813   decoder->param.mfx.FrameInfo.Height =
1814       GST_ROUND_UP_32 (decoder->param.mfx.FrameInfo.Height);
1815 
1816   decoder->param.mfx.FrameInfo.PicStruct =
1817       decoder->param.mfx.FrameInfo.PicStruct ? decoder->param.mfx.
1818       FrameInfo.PicStruct : MFX_PICSTRUCT_PROGRESSIVE;
1819 
1820   return TRUE;
1821 }
1822 
1823 static gboolean
gst_msdkdec_postinit_decoder(GstMsdkDec * decoder)1824 gst_msdkdec_postinit_decoder (GstMsdkDec * decoder)
1825 {
1826   /* Do nothing */
1827   return TRUE;
1828 }
1829 
1830 static gboolean
gst_msdkdec_transform_meta(GstVideoDecoder * decoder,GstVideoCodecFrame * frame,GstMeta * meta)1831 gst_msdkdec_transform_meta (GstVideoDecoder * decoder,
1832     GstVideoCodecFrame * frame, GstMeta * meta)
1833 {
1834   const GstMetaInfo *info = meta->info;
1835 
1836   if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (decoder, frame,
1837           meta))
1838     return TRUE;
1839 
1840   if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
1841     return TRUE;
1842 
1843   return FALSE;
1844 }
1845 
1846 static void
gst_msdkdec_class_init(GstMsdkDecClass * klass)1847 gst_msdkdec_class_init (GstMsdkDecClass * klass)
1848 {
1849   GObjectClass *gobject_class;
1850   GstElementClass *element_class;
1851   GstVideoDecoderClass *decoder_class;
1852 
1853   gobject_class = G_OBJECT_CLASS (klass);
1854   element_class = GST_ELEMENT_CLASS (klass);
1855   decoder_class = GST_VIDEO_DECODER_CLASS (klass);
1856 
1857   gobject_class->set_property = gst_msdkdec_set_property;
1858   gobject_class->get_property = gst_msdkdec_get_property;
1859   gobject_class->dispose = gst_msdkdec_dispose;
1860   gobject_class->finalize = gst_msdkdec_finalize;
1861 
1862   element_class->set_context = gst_msdkdec_set_context;
1863 
1864   decoder_class->close = GST_DEBUG_FUNCPTR (gst_msdkdec_close);
1865   decoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkdec_start);
1866   decoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkdec_stop);
1867   decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkdec_set_format);
1868   decoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkdec_finish);
1869   decoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkdec_handle_frame);
1870   decoder_class->parse = GST_DEBUG_FUNCPTR (gst_msdkdec_parse);
1871   decoder_class->decide_allocation =
1872       GST_DEBUG_FUNCPTR (gst_msdkdec_decide_allocation);
1873   decoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkdec_flush);
1874   decoder_class->drain = GST_DEBUG_FUNCPTR (gst_msdkdec_drain);
1875   decoder_class->transform_meta =
1876       GST_DEBUG_FUNCPTR (gst_msdkdec_transform_meta);
1877 
1878   klass->post_configure = GST_DEBUG_FUNCPTR (gst_msdkdec_post_configure);
1879   klass->preinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_preinit_decoder);
1880   klass->postinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_postinit_decoder);
1881 
1882   g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_HARDWARE,
1883       g_param_spec_boolean ("hardware", "Hardware", "Enable hardware decoders",
1884           PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1885 
1886   g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_ASYNC_DEPTH,
1887       g_param_spec_uint ("async-depth", "Async Depth",
1888           "Depth of asynchronous pipeline",
1889           1, 20, PROP_ASYNC_DEPTH_DEFAULT,
1890           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1891 
1892   gst_element_class_add_static_pad_template (element_class, &src_factory);
1893 }
1894 
1895 static void
gst_msdkdec_init(GstMsdkDec * thiz)1896 gst_msdkdec_init (GstMsdkDec * thiz)
1897 {
1898   gst_video_info_init (&thiz->non_msdk_pool_info);
1899   thiz->tasks = g_array_new (FALSE, TRUE, sizeof (MsdkDecTask));
1900   thiz->hardware = PROP_HARDWARE_DEFAULT;
1901   thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1902   thiz->do_renego = TRUE;
1903   thiz->do_realloc = TRUE;
1904   thiz->force_reset_on_res_change = TRUE;
1905   thiz->report_error = FALSE;
1906   thiz->adapter = gst_adapter_new ();
1907   thiz->input_state = NULL;
1908   thiz->pool = NULL;
1909   thiz->context = NULL;
1910 }
1911