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