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