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