MSDK: Import VA surface as encoder's input.
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / msdk / gstmsdkenc.c
1 /* GStreamer Intel MSDK plugin
2  * Copyright (c) 2016, Oblong Industries, Inc.
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 /* TODO:
33  *  - Add support for interlaced content
34  *  - Add support for MVC AVC
35  *  - Wrap more configuration options and maybe move properties to derived
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #  include <config.h>
40 #endif
41 #ifdef _WIN32
42 #  include <malloc.h>
43 #endif
44
45 #include <stdlib.h>
46
47 #include "gstmsdkenc.h"
48 #include "gstmsdkbufferpool.h"
49 #include "gstmsdkvideomemory.h"
50 #include "gstmsdksystemmemory.h"
51 #include "gstmsdkcontextutil.h"
52 #include "mfxjpeg.h"
53
54 #ifndef _WIN32
55 #include "gstmsdkallocator_libva.h"
56 #include "gstmsdk_va.h"
57 #endif
58
59 static inline void *
60 _aligned_alloc (size_t alignment, size_t size)
61 {
62 #ifdef _WIN32
63   return _aligned_malloc (size, alignment);
64 #else
65   void *out;
66   if (posix_memalign (&out, alignment, size) != 0)
67     out = NULL;
68   return out;
69 #endif
70 }
71
72 #ifndef _WIN32
73 #define _aligned_free free
74 #endif
75
76 static void gst_msdkenc_close_encoder (GstMsdkEnc * thiz);
77
78 GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug);
79 #define GST_CAT_DEFAULT gst_msdkenc_debug
80
81 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
82     GST_PAD_SINK,
83     GST_PAD_ALWAYS,
84     GST_STATIC_CAPS (GST_MSDK_CAPS_STR
85         ("{ NV12, I420, YV12, YUY2, UYVY, BGRA }", "NV12") "; "
86         GST_MSDK_CAPS_MAKE_WITH_VA_FEATURE ("NV12"))
87     );
88
89 #define PROP_HARDWARE_DEFAULT            TRUE
90 #define PROP_ASYNC_DEPTH_DEFAULT         4
91 #define PROP_TARGET_USAGE_DEFAULT        (MFX_TARGETUSAGE_BALANCED)
92 #define PROP_RATE_CONTROL_DEFAULT        (MFX_RATECONTROL_CBR)
93 #define PROP_BITRATE_DEFAULT             (2 * 1024)
94 #define PROP_QPI_DEFAULT                 0
95 #define PROP_QPP_DEFAULT                 0
96 #define PROP_QPB_DEFAULT                 0
97 #define PROP_GOP_SIZE_DEFAULT            256
98 #define PROP_REF_FRAMES_DEFAULT          1
99 #define PROP_I_FRAMES_DEFAULT            0
100 #define PROP_B_FRAMES_DEFAULT            0
101 #define PROP_NUM_SLICES_DEFAULT          0
102 #define PROP_AVBR_ACCURACY_DEFAULT       0
103 #define PROP_AVBR_CONVERGENCE_DEFAULT    0
104 #define PROP_RC_LOOKAHEAD_DEPTH_DEFAULT  10
105 #define PROP_MAX_VBV_BITRATE_DEFAULT     0
106 #define PROP_MAX_FRAME_SIZE_DEFAULT      0
107 #define PROP_MBBRC_DEFAULT               MFX_CODINGOPTION_OFF
108 #define PROP_ADAPTIVE_I_DEFAULT          MFX_CODINGOPTION_OFF
109 #define PROP_ADAPTIVE_B_DEFAULT          MFX_CODINGOPTION_OFF
110
111 /* External coding properties */
112 #define EC_PROPS_STRUCT_NAME             "props"
113 #define EC_PROPS_EXTBRC                  "extbrc"
114
115 #define gst_msdkenc_parent_class parent_class
116 G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER);
117
118 typedef struct
119 {
120   mfxFrameSurface1 *surface;
121   GstBuffer *buf;
122   GstBuffer *buf_external;
123   VASurfaceID cache_surface;
124 } MsdkSurface;
125
126 void
127 gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param)
128 {
129   if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
130     thiz->extra_params[thiz->num_extra_params] = param;
131     thiz->num_extra_params++;
132   }
133 }
134
135 static void
136 gst_msdkenc_set_context (GstElement * element, GstContext * context)
137 {
138   GstMsdkContext *msdk_context = NULL;
139   GstMsdkEnc *thiz = GST_MSDKENC (element);
140
141   if (gst_msdk_context_get_context (context, &msdk_context)) {
142     gst_object_replace ((GstObject **) & thiz->context,
143         (GstObject *) msdk_context);
144     gst_object_unref (msdk_context);
145   } else if (gst_msdk_context_from_external_display (context,
146           thiz->hardware, 0 /* GST_MSDK_JOB_ENCODER will be set later */ ,
147           &msdk_context)) {
148     gst_object_replace ((GstObject **) & thiz->context,
149         (GstObject *) msdk_context);
150     gst_object_unref (msdk_context);
151   }
152
153   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
154 }
155
156 static void
157 ensure_bitrate_control (GstMsdkEnc * thiz)
158 {
159   mfxInfoMFX *mfx = &thiz->param.mfx;
160   mfxExtCodingOption2 *option2 = &thiz->option2;
161   mfxExtCodingOption3 *option3 = &thiz->option3;
162
163   GST_DEBUG_OBJECT (thiz, "set target bitrate: %u kbit/sec", thiz->bitrate);
164
165   mfx->RateControlMethod = thiz->rate_control;
166   /* No effect in CQP variant algorithms */
167   if ((mfx->RateControlMethod != MFX_RATECONTROL_CQP) &&
168       (thiz->bitrate > G_MAXUINT16 || thiz->max_vbv_bitrate > G_MAXUINT16)) {
169     mfxU32 max_val = MAX (thiz->max_vbv_bitrate, thiz->bitrate);
170
171     mfx->BRCParamMultiplier = (mfxU16) ((max_val + 0x10000) / 0x10000);
172     mfx->TargetKbps = (mfxU16) (thiz->bitrate / mfx->BRCParamMultiplier);
173     mfx->MaxKbps = (mfxU16) (thiz->max_vbv_bitrate / mfx->BRCParamMultiplier);
174     mfx->BufferSizeInKB =
175         (mfxU16) (mfx->BufferSizeInKB / mfx->BRCParamMultiplier);
176     /* Currently InitialDelayInKB is not used in this plugin */
177     mfx->InitialDelayInKB =
178         (mfxU16) (mfx->InitialDelayInKB / mfx->BRCParamMultiplier);
179   } else {
180     mfx->TargetKbps = thiz->bitrate;
181     mfx->MaxKbps = thiz->max_vbv_bitrate;
182     mfx->BRCParamMultiplier = 1;
183   }
184
185   switch (mfx->RateControlMethod) {
186     case MFX_RATECONTROL_CQP:
187       mfx->QPI = thiz->qpi;
188       mfx->QPP = thiz->qpp;
189       mfx->QPB = thiz->qpb;
190       break;
191
192     case MFX_RATECONTROL_LA_ICQ:
193       option2->LookAheadDepth = thiz->lookahead_depth;
194     case MFX_RATECONTROL_ICQ:
195       mfx->ICQQuality = CLAMP (thiz->qpi, 1, 51);
196       break;
197
198     case MFX_RATECONTROL_LA:   /* VBR with LA. Only supported in H264?? */
199     case MFX_RATECONTROL_LA_HRD:       /* VBR with LA, HRD compliant */
200       option2->LookAheadDepth = thiz->lookahead_depth;
201       break;
202
203     case MFX_RATECONTROL_QVBR:
204       option3->QVBRQuality = CLAMP (thiz->qpi, 1, 51);
205       thiz->enable_extopt3 = TRUE;
206       break;
207
208     case MFX_RATECONTROL_AVBR:
209       mfx->Accuracy = thiz->accuracy;
210       mfx->Convergence = thiz->convergence;
211       break;
212
213     case MFX_RATECONTROL_VBR:
214       option2->MaxFrameSize = thiz->max_frame_size * 1000;
215       break;
216
217     case MFX_RATECONTROL_VCM:
218       /*Non HRD compliant mode with no B-frame and interlaced support */
219       thiz->param.mfx.GopRefDist = 0;
220       break;
221
222     case MFX_RATECONTROL_CBR:
223       break;
224
225     default:
226       GST_ERROR ("Unsupported RateControl!");
227       break;
228   }
229 }
230
231 static gint16
232 coding_option_get_value (const gchar * key, const gchar * nickname)
233 {
234   if (!g_strcmp0 (nickname, "on")) {
235     return MFX_CODINGOPTION_ON;
236   } else if (!g_strcmp0 (nickname, "off")) {
237     return MFX_CODINGOPTION_OFF;
238   } else if (!g_strcmp0 (nickname, "auto")) {
239     return MFX_CODINGOPTION_UNKNOWN;
240   }
241
242   GST_ERROR ("\"%s\" illegal option \"%s\", set to \"off\"", key, nickname);
243
244   return MFX_CODINGOPTION_OFF;
245 }
246
247 static gboolean
248 structure_transform (const GstStructure * src, GstStructure * dst)
249 {
250   guint len;
251   GValue dst_value = G_VALUE_INIT;
252   gboolean ret = TRUE;
253
254   g_return_val_if_fail (src != NULL, FALSE);
255   g_return_val_if_fail (dst != NULL, FALSE);
256
257   len = gst_structure_n_fields (src);
258
259   for (guint i = 0; i < len; i++) {
260     const gchar *key = gst_structure_nth_field_name (src, i);
261     const GValue *src_value = gst_structure_get_value (src, key);
262
263     if (!gst_structure_has_field (dst, key)) {
264       GST_ERROR ("structure \"%s\" does not support \"%s\"",
265           gst_structure_get_name (dst), key);
266       ret = FALSE;
267       continue;
268     }
269
270     g_value_init (&dst_value, gst_structure_get_field_type (dst, key));
271
272     if (g_value_transform (src_value, &dst_value)) {
273       gst_structure_set_value (dst, key, &dst_value);
274     } else {
275       GST_ERROR ("\"%s\" transform %s to %s failed", key,
276           G_VALUE_TYPE_NAME (src_value), G_VALUE_TYPE_NAME (&dst_value));
277       ret = FALSE;
278     }
279
280     g_value_unset (&dst_value);
281   }
282
283   return ret;
284 }
285
286 /* Supported types: gchar*, gboolean, gint, guint, gfloat, gdouble */
287 static gboolean
288 structure_get_value (const GstStructure * s, const gchar * key, gpointer value)
289 {
290   const GValue *gvalue = gst_structure_get_value (s, key);
291   if (!gvalue) {
292     GST_ERROR ("structure \"%s\" does not support \"%s\"",
293         gst_structure_get_name (s), key);
294     return FALSE;
295   }
296
297   switch (G_VALUE_TYPE (gvalue)) {
298     case G_TYPE_STRING:{
299       const gchar **val = (const gchar **) value;
300       *val = g_value_get_string (gvalue);
301       break;
302     }
303     case G_TYPE_BOOLEAN:{
304       gboolean *val = (gboolean *) value;
305       *val = g_value_get_boolean (gvalue);
306       break;
307     }
308     case G_TYPE_INT:{
309       gint *val = (gint *) value;
310       *val = g_value_get_int (gvalue);
311       break;
312     }
313     case G_TYPE_UINT:{
314       guint *val = (guint *) value;
315       *val = g_value_get_uint (gvalue);
316       break;
317     }
318     case G_TYPE_FLOAT:{
319       gfloat *val = (gfloat *) value;
320       *val = g_value_get_float (gvalue);
321       break;
322     }
323     case G_TYPE_DOUBLE:{
324       gdouble *val = (gdouble *) value;
325       *val = g_value_get_double (gvalue);
326       break;
327     }
328     default:
329       GST_ERROR ("\"%s\" unsupported type %s", key, G_VALUE_TYPE_NAME (gvalue));
330       return FALSE;
331   }
332
333   return TRUE;
334 }
335
336 static gboolean
337 ext_coding_props_get_value (GstMsdkEnc * thiz,
338     const gchar * key, gpointer value)
339 {
340   gboolean ret;
341   if (!(ret = structure_get_value (thiz->ext_coding_props, key, value))) {
342     GST_ERROR_OBJECT (thiz, "structure \"%s\" failed to get value for \"%s\"",
343         gst_structure_get_name (thiz->ext_coding_props), key);
344   }
345
346   return ret;
347 }
348
349 void
350 gst_msdkenc_ensure_extended_coding_options (GstMsdkEnc * thiz)
351 {
352   mfxExtCodingOption2 *option2 = &thiz->option2;
353   mfxExtCodingOption3 *option3 = &thiz->option3;
354
355   gchar *extbrc;
356   ext_coding_props_get_value (thiz, EC_PROPS_EXTBRC, &extbrc);
357
358   /* Fill ExtendedCodingOption2, set non-zero defaults too */
359   option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
360   option2->Header.BufferSz = sizeof (thiz->option2);
361   option2->MBBRC = thiz->mbbrc;
362   option2->ExtBRC = coding_option_get_value (EC_PROPS_EXTBRC, extbrc);
363   option2->AdaptiveI = thiz->adaptive_i;
364   option2->AdaptiveB = thiz->adaptive_b;
365   option2->BitrateLimit = MFX_CODINGOPTION_OFF;
366   option2->EnableMAD = MFX_CODINGOPTION_OFF;
367   option2->UseRawRef = MFX_CODINGOPTION_OFF;
368   gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option2);
369
370   if (thiz->enable_extopt3) {
371     option3->Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
372     option3->Header.BufferSz = sizeof (thiz->option3);
373     gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option3);
374   }
375 }
376
377 /* Return TRUE if ROI is changed and update ROI parameters in encoder_roi */
378 gboolean
379 gst_msdkenc_get_roi_params (GstMsdkEnc * thiz,
380     GstVideoCodecFrame * frame, mfxExtEncoderROI * encoder_roi)
381 {
382   GstBuffer *input;
383   guint num_roi, i, num_valid_roi = 0;
384   gushort roi_mode = G_MAXUINT16;
385   gpointer state = NULL;
386   mfxExtEncoderROI *curr_roi = encoder_roi;
387   mfxExtEncoderROI *prev_roi = encoder_roi + 1;
388
389   if (!frame || !frame->input_buffer)
390     return FALSE;
391
392   memset (curr_roi, 0, sizeof (mfxExtEncoderROI));
393   input = frame->input_buffer;
394
395   num_roi =
396       gst_buffer_get_n_meta (input, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
397
398   if (num_roi == 0)
399     goto end;
400
401   curr_roi->Header.BufferId = MFX_EXTBUFF_ENCODER_ROI;
402   curr_roi->Header.BufferSz = sizeof (mfxExtEncoderROI);
403
404   for (i = 0; i < num_roi && num_valid_roi < 256; i++) {
405     GstVideoRegionOfInterestMeta *roi;
406     GstStructure *s;
407
408     roi = (GstVideoRegionOfInterestMeta *)
409         gst_buffer_iterate_meta_filtered (input, &state,
410         GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
411
412     if (!roi)
413       continue;
414
415     /* ignore roi if overflow */
416     if ((roi->x > G_MAXINT16) || (roi->y > G_MAXINT16)
417         || (roi->w > G_MAXUINT16) || (roi->h > G_MAXUINT16)) {
418       GST_DEBUG_OBJECT (thiz, "Ignoring ROI... ROI overflow");
419       continue;
420     }
421
422     GST_LOG ("Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
423         g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
424         roi->h);
425
426     curr_roi->ROI[num_valid_roi].Left = roi->x;
427     curr_roi->ROI[num_valid_roi].Top = roi->y;
428     curr_roi->ROI[num_valid_roi].Right = roi->x + roi->w;
429     curr_roi->ROI[num_valid_roi].Bottom = roi->y + roi->h;
430
431     s = gst_video_region_of_interest_meta_get_param (roi, "roi/msdk");
432
433     if (s) {
434       int value = 0;
435
436       if (roi_mode == G_MAXUINT16) {
437         if (gst_structure_get_int (s, "delta-qp", &value)) {
438 #if (MFX_VERSION >= 1022)
439           roi_mode = MFX_ROI_MODE_QP_DELTA;
440           curr_roi->ROI[num_valid_roi].DeltaQP = CLAMP (value, -51, 51);
441           GST_LOG ("Use delta-qp %d", value);
442 #else
443           GST_WARNING
444               ("Ignore delta QP because the MFX doesn't support delta QP mode");
445 #endif
446         } else if (gst_structure_get_int (s, "priority", &value)) {
447           roi_mode = MFX_ROI_MODE_PRIORITY;
448           curr_roi->ROI[num_valid_roi].Priority = CLAMP (value, -3, 3);
449           GST_LOG ("Use priority %d", value);
450         } else
451           continue;
452 #if (MFX_VERSION >= 1022)
453       } else if (roi_mode == MFX_ROI_MODE_QP_DELTA &&
454           gst_structure_get_int (s, "delta-qp", &value)) {
455         curr_roi->ROI[num_valid_roi].DeltaQP = CLAMP (value, -51, 51);
456 #endif
457       } else if (roi_mode == MFX_ROI_MODE_PRIORITY &&
458           gst_structure_get_int (s, "priority", &value)) {
459         curr_roi->ROI[num_valid_roi].Priority = CLAMP (value, -3, 3);
460       } else
461         continue;
462
463       num_valid_roi++;
464     }
465   }
466
467 #if (MFX_VERSION >= 1022)
468   curr_roi->ROIMode = roi_mode;
469 #endif
470
471   curr_roi->NumROI = num_valid_roi;
472
473 end:
474   if (curr_roi->NumROI == 0 && prev_roi->NumROI == 0)
475     return FALSE;
476
477   if (curr_roi->NumROI != prev_roi->NumROI ||
478       memcmp (curr_roi, prev_roi, sizeof (mfxExtEncoderROI)) != 0) {
479     *prev_roi = *curr_roi;
480     return TRUE;
481   }
482
483   return FALSE;
484 }
485
486 static gboolean
487 gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
488 {
489   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
490   GstVideoInfo *info;
491   mfxSession session;
492   mfxStatus status;
493   mfxFrameAllocRequest request[2];
494   guint i;
495   gboolean need_vpp = TRUE;
496   GstVideoFormat encoder_input_fmt;
497   mfxExtVideoSignalInfo ext_vsi;
498
499   if (thiz->initialized) {
500     GST_DEBUG_OBJECT (thiz, "Already initialized");
501     return TRUE;
502   }
503
504   if (!thiz->context) {
505     GST_WARNING_OBJECT (thiz, "No MSDK Context");
506     return FALSE;
507   }
508
509   if (!thiz->input_state) {
510     GST_DEBUG_OBJECT (thiz, "Have no input state yet");
511     return FALSE;
512   }
513   info = &thiz->input_state->info;
514
515   GST_OBJECT_LOCK (thiz);
516   session = gst_msdk_context_get_session (thiz->context);
517   thiz->codename = msdk_get_platform_codename (session);
518
519   thiz->has_vpp = FALSE;
520   if (thiz->use_video_memory)
521     gst_msdk_set_frame_allocator (thiz->context);
522
523   encoder_input_fmt = GST_VIDEO_INFO_FORMAT (info);
524   need_vpp = klass->need_conversion (thiz, info, &encoder_input_fmt);
525
526   if (need_vpp) {
527     switch (GST_VIDEO_INFO_FORMAT (info)) {
528       case GST_VIDEO_FORMAT_YV12:
529       case GST_VIDEO_FORMAT_I420:
530         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YV12;
531         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
532         break;
533       case GST_VIDEO_FORMAT_YUY2:
534         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YUY2;
535         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
536         break;
537       case GST_VIDEO_FORMAT_UYVY:
538         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_UYVY;
539         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
540         break;
541       case GST_VIDEO_FORMAT_BGRA:
542         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_RGB4;
543         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
544         break;
545       default:
546         g_assert_not_reached ();
547         break;
548     }
549
550     if (thiz->use_video_memory)
551       thiz->vpp_param.IOPattern =
552           MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
553     else
554       thiz->vpp_param.IOPattern =
555           MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
556
557     thiz->vpp_param.vpp.In.Width = GST_ROUND_UP_16 (info->width);
558     thiz->vpp_param.vpp.In.Height = GST_ROUND_UP_32 (info->height);
559     thiz->vpp_param.vpp.In.CropW = info->width;
560     thiz->vpp_param.vpp.In.CropH = info->height;
561     thiz->vpp_param.vpp.In.FrameRateExtN = info->fps_n;
562     thiz->vpp_param.vpp.In.FrameRateExtD = info->fps_d;
563     thiz->vpp_param.vpp.In.AspectRatioW = info->par_n;
564     thiz->vpp_param.vpp.In.AspectRatioH = info->par_d;
565     thiz->vpp_param.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
566
567     /* work-around to avoid zero fps in msdk structure */
568     if (0 == thiz->vpp_param.vpp.In.FrameRateExtN)
569       thiz->vpp_param.vpp.In.FrameRateExtN = 30;
570
571     thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
572
573     switch (encoder_input_fmt) {
574       case GST_VIDEO_FORMAT_P010_10LE:
575         thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_P010;
576         thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
577         break;
578
579       case GST_VIDEO_FORMAT_YUY2:
580         thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_YUY2;
581         thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
582         break;
583
584       default:
585         thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
586         thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
587         break;
588     }
589
590     /* validate parameters and allow MFX to make adjustments */
591     status = MFXVideoVPP_Query (session, &thiz->vpp_param, &thiz->vpp_param);
592     if (status < MFX_ERR_NONE) {
593       GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
594           msdk_status_to_string (status));
595       goto failed;
596     } else if (status > MFX_ERR_NONE) {
597       GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
598           msdk_status_to_string (status));
599     }
600
601     status = MFXVideoVPP_QueryIOSurf (session, &thiz->vpp_param, request);
602     if (status < MFX_ERR_NONE) {
603       GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
604           msdk_status_to_string (status));
605       goto failed;
606     } else if (status > MFX_ERR_NONE) {
607       GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
608           msdk_status_to_string (status));
609     }
610
611     if (thiz->use_video_memory)
612       request[0].NumFrameSuggested +=
613           gst_msdk_context_get_shared_async_depth (thiz->context);
614     thiz->num_vpp_surfaces = request[0].NumFrameSuggested;
615
616     if (thiz->use_video_memory)
617       gst_msdk_frame_alloc (thiz->context, &(request[0]),
618           &thiz->vpp_alloc_resp);
619
620     status = MFXVideoVPP_Init (session, &thiz->vpp_param);
621     if (status < MFX_ERR_NONE) {
622       GST_ERROR_OBJECT (thiz, "Init failed (%s)",
623           msdk_status_to_string (status));
624       goto no_vpp_free_resource;
625     } else if (status > MFX_ERR_NONE) {
626       GST_WARNING_OBJECT (thiz, "Init returned: %s",
627           msdk_status_to_string (status));
628     }
629
630     status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
631     if (status < MFX_ERR_NONE) {
632       mfxStatus status1;
633       GST_ERROR_OBJECT (thiz, "Get VPP Parameters failed (%s)",
634           msdk_status_to_string (status));
635       status1 = MFXVideoVPP_Close (session);
636       if (status1 != MFX_ERR_NONE && status1 != MFX_ERR_NOT_INITIALIZED)
637         GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
638             msdk_status_to_string (status1));
639
640       goto no_vpp_free_resource;
641     } else if (status > MFX_ERR_NONE) {
642       GST_WARNING_OBJECT (thiz, "Get VPP Parameters returned: %s",
643           msdk_status_to_string (status));
644     }
645
646     thiz->has_vpp = TRUE;
647   }
648
649   thiz->param.AsyncDepth = thiz->async_depth;
650   if (thiz->use_video_memory)
651     thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
652   else
653     thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
654
655   thiz->param.mfx.TargetUsage = thiz->target_usage;
656   thiz->param.mfx.GopPicSize = thiz->gop_size;
657   thiz->param.mfx.GopRefDist = thiz->b_frames + 1;
658   thiz->param.mfx.IdrInterval = thiz->i_frames;
659   thiz->param.mfx.NumSlice = thiz->num_slices;
660   thiz->param.mfx.NumRefFrame = thiz->ref_frames;
661   thiz->param.mfx.EncodedOrder = 0;     /* Take input frames in display order */
662
663   thiz->param.mfx.FrameInfo.Width = GST_ROUND_UP_16 (info->width);
664   thiz->param.mfx.FrameInfo.Height = GST_ROUND_UP_32 (info->height);
665   thiz->param.mfx.FrameInfo.CropW = info->width;
666   thiz->param.mfx.FrameInfo.CropH = info->height;
667   thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
668   thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
669   thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
670   thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
671   thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
672   thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
673
674   switch (encoder_input_fmt) {
675     case GST_VIDEO_FORMAT_P010_10LE:
676       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P010;
677       thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
678       thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
679       thiz->param.mfx.FrameInfo.Shift = 1;
680       break;
681     case GST_VIDEO_FORMAT_VUYA:
682       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_AYUV;
683       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
684       thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
685       thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
686       break;
687 #if (MFX_VERSION >= 1027)
688     case GST_VIDEO_FORMAT_Y410:
689       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_Y410;
690       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
691       thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
692       thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
693       break;
694     case GST_VIDEO_FORMAT_Y210:
695       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_Y210;
696       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
697       thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
698       thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
699       thiz->param.mfx.FrameInfo.Shift = 1;
700       break;
701 #endif
702     case GST_VIDEO_FORMAT_BGRA:
703       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_RGB4;
704       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
705       thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
706       thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
707       break;
708     case GST_VIDEO_FORMAT_BGR10A2_LE:
709       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_A2RGB10;
710       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
711       thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
712       thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
713       break;
714     case GST_VIDEO_FORMAT_YUY2:
715       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_YUY2;
716       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
717       thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
718       thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
719       break;
720 #if (MFX_VERSION >= 1031)
721     case GST_VIDEO_FORMAT_P012_LE:
722       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P016;
723       thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
724       thiz->param.mfx.FrameInfo.BitDepthLuma = 12;
725       thiz->param.mfx.FrameInfo.BitDepthChroma = 12;
726       thiz->param.mfx.FrameInfo.Shift = 1;
727       break;
728 #endif
729     default:
730       thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
731       thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
732       thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
733   }
734
735   /* work-around to avoid zero fps in msdk structure */
736   if (0 == thiz->param.mfx.FrameInfo.FrameRateExtN)
737     thiz->param.mfx.FrameInfo.FrameRateExtN = 30;
738
739   /* ensure bitrate control parameters */
740   ensure_bitrate_control (thiz);
741
742   /* allow subclass configure further */
743   if (klass->configure) {
744     if (!klass->configure (thiz))
745       goto failed;
746   }
747
748   /* If color properties are available from upstream, set it and pass to MediaSDK here.
749    * MJPEG and VP9 are excluded as MediaSDK does not support to handle video param
750    * extbuff with buffer id equals to MFX_EXTBUFF_VIDEO_SIGNAL_INFO.
751    */
752   if (thiz->param.mfx.CodecId != MFX_CODEC_JPEG &&
753       thiz->param.mfx.CodecId != MFX_CODEC_VP9 &&
754       (info->colorimetry.primaries || info->colorimetry.transfer
755           || info->colorimetry.matrix)) {
756     memset (&ext_vsi, 0, sizeof (ext_vsi));
757     ext_vsi.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
758     ext_vsi.Header.BufferSz = sizeof (ext_vsi);
759     ext_vsi.ColourDescriptionPresent = 1;
760     ext_vsi.ColourPrimaries =
761         gst_video_color_primaries_to_iso (info->colorimetry.primaries);
762     ext_vsi.TransferCharacteristics =
763         gst_video_transfer_function_to_iso (info->colorimetry.transfer);
764     ext_vsi.MatrixCoefficients =
765         gst_video_color_matrix_to_iso (info->colorimetry.matrix);
766     gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) & ext_vsi);
767   }
768
769   if (thiz->num_extra_params) {
770     thiz->param.NumExtParam = thiz->num_extra_params;
771     thiz->param.ExtParam = thiz->extra_params;
772   }
773
774   /* validate parameters and allow MFX to make adjustments */
775   status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param);
776   if (status < MFX_ERR_NONE) {
777     GST_ERROR_OBJECT (thiz, "Video Encode Query failed (%s)",
778         msdk_status_to_string (status));
779     goto failed;
780   } else if (status > MFX_ERR_NONE) {
781     GST_WARNING_OBJECT (thiz, "Video Encode Query returned: %s",
782         msdk_status_to_string (status));
783   }
784
785   status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, request);
786   if (status < MFX_ERR_NONE) {
787     GST_ERROR_OBJECT (thiz, "Encode Query IO surfaces failed (%s)",
788         msdk_status_to_string (status));
789     goto failed;
790   } else if (status > MFX_ERR_NONE) {
791     GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
792         msdk_status_to_string (status));
793   }
794
795   request[0].NumFrameSuggested += thiz->num_extra_frames;
796
797   if (thiz->has_vpp)
798     request[0].NumFrameSuggested += thiz->num_vpp_surfaces + 1 - 4;
799
800   if (thiz->use_video_memory) {
801     if (thiz->use_dmabuf && !thiz->has_vpp)
802       request[0].Type |= MFX_MEMTYPE_EXPORT_FRAME;
803     gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->alloc_resp);
804   }
805
806   /* Maximum of VPP output and encoder input, if using VPP */
807   if (thiz->has_vpp)
808     request[0].NumFrameSuggested =
809         MAX (request[0].NumFrameSuggested, request[1].NumFrameSuggested);
810   if (request[0].NumFrameSuggested < thiz->param.AsyncDepth) {
811     GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
812         request[0].NumFrameMin, request[0].NumFrameSuggested,
813         thiz->param.AsyncDepth);
814     goto failed;
815   }
816
817   /* This is VPP output (if any) and encoder input */
818   thiz->num_surfaces = request[0].NumFrameSuggested;
819
820   GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
821       request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
822
823   status = MFXVideoENCODE_Init (session, &thiz->param);
824   if (status < MFX_ERR_NONE) {
825     GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
826     goto failed;
827   } else if (status > MFX_ERR_NONE) {
828     GST_WARNING_OBJECT (thiz, "Init returned: %s",
829         msdk_status_to_string (status));
830   }
831
832   status = MFXVideoENCODE_GetVideoParam (session, &thiz->param);
833   if (status < MFX_ERR_NONE) {
834     GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
835         msdk_status_to_string (status));
836     goto failed;
837   } else if (status > MFX_ERR_NONE) {
838     GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
839         msdk_status_to_string (status));
840   }
841
842   thiz->num_tasks = thiz->param.AsyncDepth;
843   thiz->tasks = g_new0 (MsdkEncTask, thiz->num_tasks);
844   for (i = 0; i < thiz->num_tasks; i++) {
845     thiz->tasks[i].output_bitstream.Data = _aligned_alloc (32,
846         thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
847         1024);
848     if (!thiz->tasks[i].output_bitstream.Data) {
849       GST_ERROR_OBJECT (thiz, "Memory allocation failed");
850       goto failed;
851     }
852     thiz->tasks[i].output_bitstream.MaxLength =
853         thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
854         1024;
855   }
856   thiz->next_task = 0;
857
858   thiz->reconfig = FALSE;
859   thiz->initialized = TRUE;
860
861   GST_OBJECT_UNLOCK (thiz);
862
863   return TRUE;
864
865 no_vpp_free_resource:
866   if (thiz->use_video_memory)
867     gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
868 failed:
869   GST_OBJECT_UNLOCK (thiz);
870   return FALSE;
871 }
872
873 static void
874 gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
875 {
876   guint i;
877   mfxStatus status;
878
879   if (!thiz->context || !thiz->initialized)
880     return;
881
882   GST_DEBUG_OBJECT (thiz, "Closing encoder with context %" GST_PTR_FORMAT,
883       thiz->context);
884
885   gst_clear_object (&thiz->msdk_pool);
886   gst_clear_object (&thiz->msdk_converted_pool);
887
888   if (thiz->use_video_memory)
889     gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
890
891   status = MFXVideoENCODE_Close (gst_msdk_context_get_session (thiz->context));
892   if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
893     GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
894         msdk_status_to_string (status));
895   }
896
897   if (thiz->tasks) {
898     for (i = 0; i < thiz->num_tasks; i++) {
899       MsdkEncTask *task = &thiz->tasks[i];
900       if (task->output_bitstream.Data) {
901         _aligned_free (task->output_bitstream.Data);
902       }
903     }
904   }
905   g_free (thiz->tasks);
906   thiz->tasks = NULL;
907
908   /* Close VPP before freeing the surfaces. They are shared between encoder
909    * and VPP */
910   if (thiz->has_vpp) {
911     if (thiz->use_video_memory)
912       gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
913
914     status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
915     if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
916       GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
917           msdk_status_to_string (status));
918     }
919   }
920
921   memset (&thiz->param, 0, sizeof (thiz->param));
922   thiz->num_extra_params = 0;
923   thiz->initialized = FALSE;
924 }
925
926 typedef struct
927 {
928   GstVideoCodecFrame *frame;
929   MsdkSurface *frame_surface;
930   MsdkSurface *converted_surface;
931 } FrameData;
932
933 static FrameData *
934 gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame,
935     GstVideoInfo * info)
936 {
937   FrameData *fdata;
938
939   fdata = g_slice_new (FrameData);
940   fdata->frame = gst_video_codec_frame_ref (frame);
941
942   thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
943
944   return fdata;
945 }
946
947 static MsdkSurface *
948 gst_msdkenc_create_surface (mfxFrameSurface1 * surface, GstBuffer * buf)
949 {
950   MsdkSurface *msdk_surface;
951   msdk_surface = g_slice_new0 (MsdkSurface);
952   msdk_surface->surface = surface;
953   msdk_surface->buf = buf;
954
955   return msdk_surface;
956 }
957
958 static void
959 gst_msdkenc_free_surface (MsdkSurface * surface)
960 {
961   if (surface->buf_external) {
962     GstMsdkMemoryID *msdk_mid = NULL;
963     mfxFrameSurface1 *mfx_surface = NULL;
964
965     mfx_surface = surface->surface;
966     msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
967     *msdk_mid->surface = surface->cache_surface;
968
969     gst_buffer_unref (surface->buf_external);
970   }
971
972   if (surface->buf)
973     gst_buffer_unref (surface->buf);
974
975   g_slice_free (MsdkSurface, surface);
976 }
977
978 static void
979 gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata)
980 {
981   if (fdata->frame_surface)
982     gst_msdkenc_free_surface (fdata->frame_surface);
983   if (thiz->has_vpp)
984     gst_msdkenc_free_surface (fdata->converted_surface);
985
986   gst_video_codec_frame_unref (fdata->frame);
987   g_slice_free (FrameData, fdata);
988 }
989
990 static void
991 gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
992 {
993   GList *l;
994
995   for (l = thiz->pending_frames; l;) {
996     FrameData *fdata = l->data;
997     GList *l1 = l;
998
999     l = l->next;
1000
1001     if (fdata->frame != frame)
1002       continue;
1003
1004     gst_msdkenc_free_frame_data (thiz, fdata);
1005
1006     thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l1);
1007     return;
1008   }
1009 }
1010
1011 static void
1012 gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz)
1013 {
1014   GList *l;
1015
1016   for (l = thiz->pending_frames; l; l = l->next) {
1017     FrameData *fdata = l->data;
1018
1019     gst_msdkenc_free_frame_data (thiz, fdata);
1020   }
1021   g_list_free (thiz->pending_frames);
1022   thiz->pending_frames = NULL;
1023 }
1024
1025 static MsdkEncTask *
1026 gst_msdkenc_get_free_task (GstMsdkEnc * thiz)
1027 {
1028   MsdkEncTask *tasks = thiz->tasks;
1029   guint size = thiz->num_tasks;
1030   guint start = thiz->next_task;
1031   guint i;
1032
1033   if (tasks) {
1034     for (i = 0; i < size; i++) {
1035       guint t = (start + i) % size;
1036       if (tasks[t].sync_point == NULL)
1037         return &tasks[t];
1038     }
1039   }
1040   return NULL;
1041 }
1042
1043 static void
1044 gst_msdkenc_reset_task (MsdkEncTask * task)
1045 {
1046   task->output_bitstream.DataLength = 0;
1047   task->sync_point = NULL;
1048 }
1049
1050 static GstVideoCodecFrame *
1051 gst_msdkenc_find_best_frame (GstMsdkEnc * thiz, GList * frames,
1052     mfxBitstream * bitstream)
1053 {
1054   GList *iter;
1055   GstVideoCodecFrame *ret = NULL;
1056   GstClockTime pts;
1057   GstClockTimeDiff best_diff = GST_CLOCK_STIME_NONE;
1058
1059   if (!bitstream)
1060     return NULL;
1061
1062   if (bitstream->TimeStamp == MFX_TIMESTAMP_UNKNOWN) {
1063     pts = GST_CLOCK_TIME_NONE;
1064   } else {
1065     pts = gst_util_uint64_scale (bitstream->TimeStamp, GST_SECOND, 90000);
1066   }
1067
1068   for (iter = frames; iter; iter = g_list_next (iter)) {
1069     GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
1070
1071     /* if we don't know the time stamp, find the first frame which
1072      * has unknown timestamp */
1073     if (!GST_CLOCK_TIME_IS_VALID (pts)) {
1074       if (!GST_CLOCK_TIME_IS_VALID (frame->pts)) {
1075         ret = frame;
1076         break;
1077       }
1078     } else {
1079       GstClockTimeDiff abs_diff = ABS (GST_CLOCK_DIFF (frame->pts, pts));
1080       if (abs_diff == 0) {
1081         ret = frame;
1082         break;
1083       }
1084
1085       if (!GST_CLOCK_STIME_IS_VALID (best_diff) || abs_diff < best_diff) {
1086         ret = frame;
1087         best_diff = abs_diff;
1088       }
1089     }
1090   }
1091
1092   if (ret)
1093     gst_video_codec_frame_ref (ret);
1094
1095   return ret;
1096 }
1097
1098 static GstFlowReturn
1099 gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task,
1100     gboolean discard)
1101 {
1102   GstVideoCodecFrame *frame;
1103   GList *list;
1104
1105   if (!task->sync_point)
1106     return GST_FLOW_OK;
1107
1108   list = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (thiz));
1109
1110   if (!list) {
1111     GST_ERROR_OBJECT (thiz, "failed to get list of frame");
1112     return GST_FLOW_ERROR;
1113   }
1114
1115   /* Wait for encoding operation to complete, the magic number 300000 below
1116    * is used in MSDK samples
1117    * #define MSDK_ENC_WAIT_INTERVAL 300000
1118    */
1119   if (MFXVideoCORE_SyncOperation (gst_msdk_context_get_session (thiz->context),
1120           task->sync_point, 300000) != MFX_ERR_NONE)
1121     GST_WARNING_OBJECT (thiz, "failed to do sync operation");
1122
1123   if (!discard && task->output_bitstream.DataLength) {
1124     GstBuffer *out_buf = NULL;
1125     guint8 *data =
1126         task->output_bitstream.Data + task->output_bitstream.DataOffset;
1127     gsize size = task->output_bitstream.DataLength;
1128
1129     frame = gst_msdkenc_find_best_frame (thiz, list, &task->output_bitstream);
1130     if (!frame) {
1131       /* just pick the oldest one */
1132       frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
1133     }
1134
1135     out_buf = gst_buffer_new_allocate (NULL, size, NULL);
1136     gst_buffer_fill (out_buf, 0, data, size);
1137     frame->output_buffer = out_buf;
1138     frame->pts =
1139         gst_util_uint64_scale (task->output_bitstream.TimeStamp, GST_SECOND,
1140         90000);
1141     frame->dts =
1142         gst_util_uint64_scale (task->output_bitstream.DecodeTimeStamp,
1143         GST_SECOND, 90000);
1144
1145     if ((task->output_bitstream.FrameType & MFX_FRAMETYPE_IDR) != 0 ||
1146         (task->output_bitstream.FrameType & MFX_FRAMETYPE_xIDR) != 0) {
1147       GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1148     }
1149
1150     /* Mark task as available */
1151     gst_msdkenc_reset_task (task);
1152   } else {
1153     frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
1154   }
1155
1156   g_list_free_full (list, (GDestroyNotify) gst_video_codec_frame_unref);
1157
1158   gst_video_codec_frame_unref (frame);
1159   gst_msdkenc_dequeue_frame (thiz, frame);
1160
1161   return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1162 }
1163
1164 static GstFlowReturn
1165 gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
1166     GstVideoCodecFrame * input_frame)
1167 {
1168   mfxSession session;
1169   MsdkEncTask *task;
1170   mfxStatus status;
1171
1172   if (G_UNLIKELY (thiz->context == NULL)) {
1173     gst_msdkenc_dequeue_frame (thiz, input_frame);
1174     gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
1175     return GST_FLOW_NOT_NEGOTIATED;
1176   }
1177   session = gst_msdk_context_get_session (thiz->context);
1178
1179   task = gst_msdkenc_get_free_task (thiz);
1180
1181   for (;;) {
1182     /* Force key-frame if needed */
1183     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame))
1184       thiz->enc_cntrl.FrameType =
1185           MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF;
1186     else
1187       thiz->enc_cntrl.FrameType = MFX_FRAMETYPE_UNKNOWN;
1188
1189     status =
1190         MFXVideoENCODE_EncodeFrameAsync (session, &thiz->enc_cntrl, surface,
1191         &task->output_bitstream, &task->sync_point);
1192     if (status != MFX_WRN_DEVICE_BUSY)
1193       break;
1194     /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1195     g_usleep (1000);
1196   };
1197
1198   if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1199     GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
1200         ("MSDK encode error (%s)", msdk_status_to_string (status)));
1201     gst_msdkenc_dequeue_frame (thiz, input_frame);
1202     gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
1203     return GST_FLOW_ERROR;
1204   }
1205
1206   if (task->sync_point) {
1207     thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
1208   } else if (status == MFX_ERR_MORE_DATA) {
1209     gst_msdkenc_dequeue_frame (thiz, input_frame);
1210   }
1211
1212   /* Ensure that next task is available */
1213   task = thiz->tasks + thiz->next_task;
1214   return gst_msdkenc_finish_frame (thiz, task, FALSE);
1215 }
1216
1217 static guint
1218 gst_msdkenc_maximum_delayed_frames (GstMsdkEnc * thiz)
1219 {
1220   return thiz->num_tasks;
1221 }
1222
1223 static void
1224 gst_msdkenc_set_latency (GstMsdkEnc * thiz)
1225 {
1226   GstVideoInfo *info = &thiz->input_state->info;
1227   gint max_delayed_frames;
1228   GstClockTime latency;
1229
1230   max_delayed_frames = gst_msdkenc_maximum_delayed_frames (thiz);
1231
1232   if (info->fps_n) {
1233     latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
1234         max_delayed_frames, info->fps_n);
1235   } else {
1236     /* FIXME: Assume 25fps. This is better than reporting no latency at
1237      * all and then later failing in live pipelines
1238      */
1239     latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
1240         max_delayed_frames, 25);
1241   }
1242
1243   GST_INFO_OBJECT (thiz,
1244       "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
1245       GST_TIME_ARGS (latency), max_delayed_frames);
1246
1247   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (thiz), latency, latency);
1248 }
1249
1250 static void
1251 gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard)
1252 {
1253   mfxStatus status;
1254   mfxSession session;
1255   MsdkEncTask *task;
1256   guint i, t;
1257
1258   if (!thiz->tasks)
1259     return;
1260
1261   GST_DEBUG_OBJECT (thiz, "flush frames");
1262
1263   session = gst_msdk_context_get_session (thiz->context);
1264
1265   for (;;) {
1266     task = thiz->tasks + thiz->next_task;
1267     gst_msdkenc_finish_frame (thiz, task, FALSE);
1268
1269     status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL,
1270         &task->output_bitstream, &task->sync_point);
1271
1272     if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1273       GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
1274           ("MSDK encode error (%s)", msdk_status_to_string (status)));
1275       break;
1276     }
1277
1278     if (task->sync_point) {
1279       thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
1280     } else if (status == MFX_ERR_MORE_DATA) {
1281       break;
1282     }
1283   };
1284
1285   t = thiz->next_task;
1286   for (i = 0; i < thiz->num_tasks; i++) {
1287     gst_msdkenc_finish_frame (thiz, &thiz->tasks[t], discard);
1288     t = (t + 1) % thiz->num_tasks;
1289   }
1290 }
1291
1292 static gboolean
1293 gst_msdkenc_set_src_caps (GstMsdkEnc * thiz)
1294 {
1295   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1296   GstCaps *outcaps = NULL;
1297   GstVideoCodecState *state;
1298   GstTagList *tags;
1299
1300   if (klass->set_src_caps)
1301     outcaps = klass->set_src_caps (thiz);
1302
1303   if (!outcaps)
1304     return FALSE;
1305
1306   state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (thiz),
1307       outcaps, thiz->input_state);
1308   GST_DEBUG_OBJECT (thiz, "output caps: %" GST_PTR_FORMAT, state->caps);
1309
1310   gst_video_codec_state_unref (state);
1311
1312   tags = gst_tag_list_new_empty ();
1313   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "msdkenc",
1314       GST_TAG_MAXIMUM_BITRATE, thiz->bitrate * 1024,
1315       GST_TAG_NOMINAL_BITRATE, thiz->bitrate * 1024, NULL);
1316   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (thiz), tags,
1317       GST_TAG_MERGE_REPLACE);
1318   gst_tag_list_unref (tags);
1319
1320   return TRUE;
1321 }
1322
1323 static GstBufferPool *
1324 gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps,
1325     guint num_buffers, gboolean set_align)
1326 {
1327   GstBufferPool *pool = NULL;
1328   GstStructure *config;
1329   GstAllocator *allocator = NULL;
1330   GstVideoInfo info;
1331   GstVideoAlignment align;
1332   GstAllocationParams params = { 0, 31, 0, 0, };
1333   mfxFrameAllocResponse *alloc_resp = NULL;
1334
1335   if (thiz->has_vpp)
1336     alloc_resp = set_align ? &thiz->vpp_alloc_resp : &thiz->alloc_resp;
1337   else
1338     alloc_resp = &thiz->alloc_resp;
1339
1340   pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
1341   if (!pool)
1342     goto error_no_pool;
1343
1344   if (!gst_video_info_from_caps (&info, caps)) {
1345     GST_INFO_OBJECT (thiz, "failed to get video info");
1346     return NULL;
1347   }
1348
1349   gst_msdk_set_video_alignment (&info, 0, 0, &align);
1350   gst_video_info_align (&info, &align);
1351
1352   if (thiz->use_dmabuf)
1353     allocator =
1354         gst_msdk_dmabuf_allocator_new (thiz->context, &info, alloc_resp);
1355   else if (thiz->use_video_memory)
1356     allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
1357   else
1358     allocator = gst_msdk_system_allocator_new (&info);
1359
1360   if (!allocator)
1361     goto error_no_allocator;
1362
1363   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1364   gst_buffer_pool_config_set_params (config, caps, info.size, num_buffers, 0);
1365   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1366   gst_buffer_pool_config_add_option (config,
1367       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1368
1369   if (thiz->use_video_memory) {
1370     gst_buffer_pool_config_add_option (config,
1371         GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1372     if (thiz->use_dmabuf)
1373       gst_buffer_pool_config_add_option (config,
1374           GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1375   }
1376
1377   gst_buffer_pool_config_set_video_alignment (config, &align);
1378   gst_buffer_pool_config_set_allocator (config, allocator, &params);
1379   gst_object_unref (allocator);
1380
1381   if (!gst_buffer_pool_set_config (pool, config))
1382     goto error_pool_config;
1383
1384   if (set_align)
1385     thiz->aligned_info = info;
1386
1387   return pool;
1388
1389 error_no_pool:
1390   {
1391     GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1392     return NULL;
1393   }
1394 error_no_allocator:
1395   {
1396     GST_INFO_OBJECT (thiz, "failed to create allocator");
1397     gst_object_unref (pool);
1398     return NULL;
1399   }
1400 error_pool_config:
1401   {
1402     GST_INFO_OBJECT (thiz, "failed to set config");
1403     gst_object_unref (pool);
1404     gst_object_unref (allocator);
1405     return NULL;
1406   }
1407 }
1408
1409 /* Fixme: Common routine used by all msdk elements, should be
1410  * moved to a common util file */
1411 static gboolean
1412 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
1413 {
1414   guint i;
1415
1416   for (i = 0; i < gst_caps_get_size (caps); i++) {
1417     GstCapsFeatures *const features = gst_caps_get_features (caps, i);
1418     /* Skip ANY features, we need an exact match for correct evaluation */
1419     if (gst_caps_features_is_any (features))
1420       continue;
1421     if (gst_caps_features_contains (features, feature))
1422       return TRUE;
1423   }
1424   return FALSE;
1425 }
1426
1427 static gboolean
1428 sinkpad_can_dmabuf (GstMsdkEnc * thiz)
1429 {
1430   gboolean ret = FALSE;
1431   GstCaps *caps, *allowed_caps;
1432   GstPad *sinkpad;
1433
1434   sinkpad = GST_VIDEO_ENCODER_SINK_PAD (thiz);
1435   caps = gst_pad_get_pad_template_caps (sinkpad);
1436
1437   allowed_caps = gst_pad_peer_query_caps (sinkpad, caps);
1438   if (!allowed_caps)
1439     goto done;
1440   if (gst_caps_is_any (allowed_caps) || gst_caps_is_empty (allowed_caps)
1441       || allowed_caps == caps)
1442     goto done;
1443
1444   if (_gst_caps_has_feature (allowed_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
1445     ret = TRUE;
1446
1447 done:
1448   if (caps)
1449     gst_caps_unref (caps);
1450   if (allowed_caps)
1451     gst_caps_unref (allowed_caps);
1452   return ret;
1453 }
1454
1455 static gboolean
1456 sinkpad_is_va (GstMsdkEnc * thiz)
1457 {
1458   GstCapsFeatures *const features =
1459       gst_caps_get_features (thiz->input_state->caps, 0);
1460   if (gst_caps_features_contains (features, "memory:VAMemory"))
1461     return TRUE;
1462
1463   return FALSE;
1464 }
1465
1466 static gboolean
1467 gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
1468 {
1469   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1470   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1471
1472   if (state) {
1473     if (thiz->input_state) {
1474       if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
1475         GST_INFO_OBJECT (thiz, "Re-init the encoder as info changed");
1476         gst_msdkenc_flush_frames (thiz, FALSE);
1477         gst_msdkenc_close_encoder (thiz);
1478       }
1479       gst_video_codec_state_unref (thiz->input_state);
1480     }
1481     thiz->input_state = gst_video_codec_state_ref (state);
1482   }
1483
1484   /* TODO: Currently d3d allocator is not implemented.
1485    * So encoder uses system memory by default on Windows.
1486    */
1487 #ifndef _WIN32
1488   thiz->use_video_memory = TRUE;
1489   if (sinkpad_is_va (thiz))
1490     thiz->use_va = TRUE;
1491 #else
1492   thiz->use_video_memory = FALSE;
1493 #endif
1494
1495   GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory",
1496       thiz->use_video_memory ? "video" : "system");
1497
1498   if (klass->set_format) {
1499     if (!klass->set_format (thiz))
1500       return FALSE;
1501   }
1502
1503   /* If upstream supports DMABufCapsfeatures, then we request for the dmabuf
1504    * based pipeline usage. Ideally we should have dmabuf support even with
1505    * raw-caps negotiation, but we don't have dmabuf-import support in msdk
1506    * plugin yet */
1507   /* If VA is set, we do not fallback to DMA. */
1508   if (!thiz->use_va && sinkpad_can_dmabuf (thiz)) {
1509     thiz->input_state->caps = gst_caps_make_writable (thiz->input_state->caps);
1510     gst_caps_set_features (thiz->input_state->caps, 0,
1511         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1512     thiz->use_dmabuf = TRUE;
1513   }
1514
1515   if (!gst_msdkenc_init_encoder (thiz))
1516     return FALSE;
1517
1518   if (!gst_msdkenc_set_src_caps (thiz)) {
1519     gst_msdkenc_close_encoder (thiz);
1520     return FALSE;
1521   }
1522
1523   if (!thiz->msdk_pool) {
1524     guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1525     thiz->msdk_pool =
1526         gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps,
1527         num_buffers, TRUE);
1528   }
1529
1530   gst_msdkenc_set_latency (thiz);
1531
1532   /* Create another bufferpool if VPP requires */
1533   if (thiz->has_vpp) {
1534     GstVideoInfo *info = &thiz->input_state->info;
1535     GstVideoInfo out_info;
1536     GstVideoFormat out_fmt;
1537     GstCaps *caps;
1538     GstBufferPool *pool = NULL;
1539
1540     gst_video_info_init (&out_info);
1541     out_fmt =
1542         gst_msdk_get_video_format_from_mfx_fourcc (thiz->vpp_param.vpp.
1543         Out.FourCC);
1544     gst_video_info_set_format (&out_info, out_fmt, info->width, info->height);
1545     caps = gst_video_info_to_caps (&out_info);
1546
1547     /* If there's an existing pool try to reuse it when is compatible */
1548     if (thiz->msdk_converted_pool) {
1549       GstStructure *config;
1550       GstCaps *pool_caps;
1551       gboolean is_pool_compatible = FALSE;
1552
1553       config = gst_buffer_pool_get_config (thiz->msdk_converted_pool);
1554       gst_buffer_pool_config_get_params (config, &pool_caps, NULL, NULL, NULL);
1555       if (caps && pool_caps)
1556         is_pool_compatible = gst_caps_is_equal (caps, pool_caps);
1557       gst_structure_free (config);
1558
1559       /* If caps are the same then we are done */
1560       if (is_pool_compatible) {
1561         gst_caps_unref (caps);
1562         goto done;
1563       }
1564       /* Release current pool because we are going to create a new one */
1565       gst_clear_object (&thiz->msdk_converted_pool);
1566     }
1567
1568     /* Otherwise create a new pool */
1569     pool =
1570         gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE);
1571
1572     thiz->msdk_converted_pool = pool;
1573     gst_caps_unref (caps);
1574   }
1575
1576 done:
1577   return TRUE;
1578 }
1579
1580 static MsdkSurface *
1581 gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool,
1582     GstBufferPoolAcquireParams * params)
1583 {
1584   GstBuffer *new_buffer;
1585   mfxFrameSurface1 *new_surface;
1586   MsdkSurface *msdk_surface;
1587
1588   if (!gst_buffer_pool_is_active (pool) &&
1589       !gst_buffer_pool_set_active (pool, TRUE)) {
1590     GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
1591     return NULL;
1592   }
1593
1594   if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
1595     GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
1596     return NULL;
1597   }
1598
1599   if (gst_msdk_is_msdk_buffer (new_buffer))
1600     new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
1601   else {
1602     GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
1603     return NULL;
1604   }
1605
1606   msdk_surface = gst_msdkenc_create_surface (new_surface, new_buffer);
1607
1608   return msdk_surface;
1609 }
1610
1611 #ifndef _WIN32
1612 static gboolean
1613 import_dmabuf_to_msdk_surface (GstMsdkEnc * thiz, GstBuffer * buf,
1614     MsdkSurface * msdk_surface)
1615 {
1616   GstMemory *mem = NULL;
1617   GstVideoInfo vinfo;
1618   GstVideoMeta *vmeta;
1619   GstMsdkMemoryID *msdk_mid = NULL;
1620   mfxFrameSurface1 *mfx_surface = NULL;
1621   gint fd, i;
1622   mem = gst_buffer_peek_memory (buf, 0);
1623   fd = gst_dmabuf_memory_get_fd (mem);
1624   if (fd < 0)
1625     return FALSE;
1626
1627   vinfo = thiz->input_state->info;
1628   /* Update offset/stride/size if there is VideoMeta attached to
1629    * the buffer */
1630   vmeta = gst_buffer_get_video_meta (buf);
1631   if (vmeta) {
1632     if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
1633         GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
1634         GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
1635         GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
1636       GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
1637           "the negotiated width/height/format");
1638       return FALSE;
1639     }
1640     for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
1641       GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
1642       GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
1643     }
1644     GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
1645   }
1646
1647   /* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions.
1648    * Current media-driver and GMMLib will fail due to strict memory size restrictions.
1649    * Ideally, media-driver should accept what ever memory coming from other drivers
1650    * in case of dmabuf-import and this is how the intel-vaapi-driver works.
1651    * For now, in order to avoid any crash we check the buffer size and fallback
1652    * to copy frame method.
1653    *
1654    * See this: https://github.com/intel/media-driver/issues/169
1655    * */
1656   if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1657     return FALSE;
1658
1659   mfx_surface = msdk_surface->surface;
1660   msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1661
1662   /* release the internal memory storage of associated mfxSurface */
1663   gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);
1664
1665   /* export dmabuf to vasurface */
1666   if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
1667           msdk_mid->surface))
1668     return FALSE;
1669
1670   return TRUE;
1671 }
1672
1673 static gboolean
1674 import_va_surface_to_msdk (GstMsdkEnc * thiz, GstBuffer * buf,
1675     MsdkSurface * msdk_surface)
1676 {
1677   GstVideoInfo vinfo;
1678   GstVideoMeta *vmeta;
1679   GstMsdkMemoryID *msdk_mid = NULL;
1680   mfxFrameSurface1 *mfx_surface = NULL;
1681   VASurfaceID surface;
1682   gint i;
1683
1684   surface = gst_msdk_va_peek_buffer_surface (buf);
1685   if (surface == VA_INVALID_SURFACE)
1686     return FALSE;
1687
1688   vinfo = thiz->input_state->info;
1689   /* Update offset/stride/size if there is VideoMeta attached to
1690    * the buffer */
1691   vmeta = gst_buffer_get_video_meta (buf);
1692   if (vmeta) {
1693     if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
1694         GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
1695         GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
1696         GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
1697       GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
1698           "the negotiated width/height/format");
1699       return FALSE;
1700     }
1701     for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
1702       GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
1703       GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
1704     }
1705     GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
1706   }
1707
1708   if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1709     return FALSE;
1710
1711   msdk_surface->buf_external = gst_buffer_ref (buf);
1712
1713   mfx_surface = msdk_surface->surface;
1714   msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1715
1716   msdk_surface->cache_surface = *msdk_mid->surface;
1717   *msdk_mid->surface = surface;
1718   return TRUE;
1719 }
1720 #endif
1721
1722 static MsdkSurface *
1723 gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
1724     GstVideoCodecFrame * frame)
1725 {
1726   GstVideoFrame src_frame, out_frame;
1727   MsdkSurface *msdk_surface;
1728   GstBuffer *inbuf;
1729 #ifndef _WIN32
1730   GstMemory *mem = NULL;
1731 #endif
1732
1733   inbuf = frame->input_buffer;
1734   if (gst_msdk_is_msdk_buffer (inbuf)) {
1735     msdk_surface = g_slice_new0 (MsdkSurface);
1736     msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
1737     return msdk_surface;
1738   }
1739
1740   /* If upstream hasn't accpeted the proposed msdk bufferpool,
1741    * just copy frame (if not dmabuf backed )to msdk buffer and take a surface from it.
1742    */
1743   if (!(msdk_surface =
1744           gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL)))
1745     goto error;
1746
1747 #ifndef _WIN32
1748     /************** VA import *****************/
1749   if (thiz->use_va) {
1750     if (import_va_surface_to_msdk (thiz, inbuf, msdk_surface)) {
1751       return msdk_surface;
1752     }
1753   }
1754
1755   /************ dmabuf-import ************* */
1756   /* if upstream provided a dmabuf backed memory, but not an msdk
1757    * buffer, we could try to export the dmabuf to underlined vasurface */
1758   mem = gst_buffer_peek_memory (inbuf, 0);
1759   if (gst_is_dmabuf_memory (mem)) {
1760     if (import_dmabuf_to_msdk_surface (thiz, inbuf, msdk_surface))
1761       return msdk_surface;
1762     else
1763       GST_INFO_OBJECT (thiz, "Upstream dmabuf-backed memory is not imported"
1764           "to the msdk surface, fall back to the copy input frame method");
1765   }
1766 #endif
1767
1768   if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, inbuf,
1769           GST_MAP_READ)) {
1770     GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
1771     goto error;
1772   }
1773
1774   if (!gst_video_frame_map (&out_frame, &thiz->aligned_info, msdk_surface->buf,
1775           GST_MAP_WRITE)) {
1776     GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
1777     gst_video_frame_unmap (&src_frame);
1778     goto error;
1779   }
1780
1781   if (!gst_video_frame_copy (&out_frame, &src_frame)) {
1782     GST_ERROR_OBJECT (thiz, "failed to copy frame");
1783     gst_video_frame_unmap (&out_frame);
1784     gst_video_frame_unmap (&src_frame);
1785     goto error;
1786   }
1787
1788   gst_video_frame_unmap (&out_frame);
1789   gst_video_frame_unmap (&src_frame);
1790
1791   gst_buffer_replace (&frame->input_buffer, msdk_surface->buf);
1792   gst_buffer_unref (msdk_surface->buf);
1793   msdk_surface->buf = NULL;
1794
1795   return msdk_surface;
1796
1797 error:
1798   if (msdk_surface) {
1799     if (msdk_surface->buf)
1800       gst_buffer_unref (msdk_surface->buf);
1801     g_slice_free (MsdkSurface, msdk_surface);
1802   }
1803   return NULL;
1804 }
1805
1806 static GstFlowReturn
1807 gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1808 {
1809   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1810   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1811   GstVideoInfo *info = &thiz->input_state->info;
1812   FrameData *fdata;
1813   MsdkSurface *surface;
1814
1815   if (thiz->reconfig || klass->need_reconfig (thiz, frame)) {
1816     gst_msdkenc_flush_frames (thiz, FALSE);
1817     gst_msdkenc_close_encoder (thiz);
1818
1819     klass->set_extra_params (thiz, frame);
1820
1821     // This will reinitialized the encoder but keep same input format.
1822     gst_msdkenc_set_format (encoder, NULL);
1823   }
1824
1825   if (G_UNLIKELY (thiz->context == NULL))
1826     goto not_inited;
1827
1828   if (thiz->has_vpp) {
1829     MsdkSurface *vpp_surface;
1830     GstVideoFrame vframe;
1831     mfxSession session;
1832     mfxSyncPoint vpp_sync_point = NULL;
1833     mfxStatus status;
1834
1835     vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1836     if (!vpp_surface)
1837       goto invalid_surface;
1838     surface =
1839         gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_converted_pool,
1840         NULL);
1841     if (!surface)
1842       goto invalid_surface;
1843
1844     if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
1845       goto invalid_frame;
1846
1847     if (frame->pts != GST_CLOCK_TIME_NONE) {
1848       vpp_surface->surface->Data.TimeStamp =
1849           gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1850       surface->surface->Data.TimeStamp =
1851           gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1852     } else {
1853       vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1854       surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1855     }
1856
1857     session = gst_msdk_context_get_session (thiz->context);
1858     for (;;) {
1859       status =
1860           MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface,
1861           surface->surface, NULL, &vpp_sync_point);
1862       if (status != MFX_WRN_DEVICE_BUSY)
1863         break;
1864       /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1865       g_usleep (1000);
1866     };
1867
1868     gst_video_frame_unmap (&vframe);
1869
1870     if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1871       GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Converting frame failed."),
1872           ("MSDK VPP error (%s)", msdk_status_to_string (status)));
1873       gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1874       return GST_FLOW_ERROR;
1875     }
1876
1877     fdata = g_slice_new0 (FrameData);
1878     fdata->frame = gst_video_codec_frame_ref (frame);
1879     fdata->frame_surface = vpp_surface;
1880     fdata->converted_surface = surface;
1881
1882     thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
1883   } else {
1884     surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1885     if (!surface)
1886       goto invalid_surface;
1887
1888     fdata = gst_msdkenc_queue_frame (thiz, frame, info);
1889     if (!fdata)
1890       goto invalid_frame;
1891
1892     fdata->frame_surface = surface;
1893
1894     if (frame->pts != GST_CLOCK_TIME_NONE) {
1895       surface->surface->Data.TimeStamp =
1896           gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1897     } else {
1898       surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1899     }
1900   }
1901
1902   return gst_msdkenc_encode_frame (thiz, surface->surface, frame);
1903
1904 /* ERRORS */
1905 not_inited:
1906   {
1907     GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1908     return GST_FLOW_NOT_NEGOTIATED;
1909   }
1910 invalid_surface:
1911   {
1912     GST_ERROR_OBJECT (encoder, "Surface pool is full");
1913     return GST_FLOW_ERROR;
1914   }
1915 invalid_frame:
1916   {
1917     GST_WARNING_OBJECT (encoder, "Failed to map frame");
1918     return GST_FLOW_OK;
1919   }
1920 }
1921
1922 static gboolean
1923 gst_msdkenc_context_prepare (GstMsdkEnc * thiz)
1924 {
1925   /* Try to find an existing context from the pipeline. This may (indirectly)
1926    * invoke gst_msdkenc_set_context, which will set thiz->context. */
1927   if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
1928     return FALSE;
1929
1930   if (thiz->context == thiz->old_context) {
1931     GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
1932         ", reusing as-is", thiz->context);
1933     return TRUE;
1934   }
1935
1936   GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
1937       thiz->context);
1938
1939   /* Check GST_MSDK_JOB_VPP and GST_MSDK_JOB_ENCODER together to avoid sharing context
1940    * between VPP and ENCODER
1941    * Example:
1942    * gst-launch-1.0 videotestsrc ! video/x-raw,format=I420 ! msdkh264enc ! \
1943    * msdkh264dec ! msdkvpp ! video/x-raw,format=YUY2 ! fakesink
1944    */
1945   if (!(gst_msdk_context_get_job_type (thiz->context) & (GST_MSDK_JOB_VPP |
1946               GST_MSDK_JOB_ENCODER))) {
1947     gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_ENCODER);
1948     return TRUE;
1949   }
1950
1951   /* Found an existing context that's already being used as an encoder, clone
1952    * the MFX session inside it to create a new one */
1953   {
1954     GstMsdkContext *parent_context, *msdk_context;
1955
1956     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
1957         "joined session", thiz->context);
1958     parent_context = thiz->context;
1959     msdk_context = gst_msdk_context_new_with_parent (parent_context);
1960
1961     if (!msdk_context) {
1962       GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
1963           "as %" GST_PTR_FORMAT, parent_context);
1964       return FALSE;
1965     }
1966
1967     thiz->context = msdk_context;
1968     gst_object_unref (parent_context);
1969   }
1970
1971   return TRUE;
1972 }
1973
1974 static gboolean
1975 gst_msdkenc_start (GstVideoEncoder * encoder)
1976 {
1977   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1978
1979   if (!gst_msdkenc_context_prepare (thiz)) {
1980     if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
1981             thiz->hardware, GST_MSDK_JOB_ENCODER, &thiz->context))
1982       return FALSE;
1983     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1984         thiz->context);
1985   }
1986
1987   /* Save the current context in a separate field so that we know whether it
1988    * has changed between calls to _start() */
1989   gst_object_replace ((GstObject **) & thiz->old_context,
1990       (GstObject *) thiz->context);
1991
1992   gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
1993
1994   /* Set the minimum pts to some huge value (1000 hours). This keeps
1995      the dts at the start of the stream from needing to be
1996      negative. */
1997   gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
1998
1999   return TRUE;
2000 }
2001
2002 static gboolean
2003 gst_msdkenc_stop (GstVideoEncoder * encoder)
2004 {
2005   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2006
2007   gst_msdkenc_flush_frames (thiz, TRUE);
2008   gst_msdkenc_close_encoder (thiz);
2009   gst_msdkenc_dequeue_all_frames (thiz);
2010
2011   if (thiz->input_state)
2012     gst_video_codec_state_unref (thiz->input_state);
2013   thiz->input_state = NULL;
2014
2015   gst_clear_object (&thiz->context);
2016
2017   return TRUE;
2018 }
2019
2020 static gboolean
2021 gst_msdkenc_flush (GstVideoEncoder * encoder)
2022 {
2023   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2024
2025   GST_DEBUG_OBJECT (encoder, "flush and close encoder");
2026
2027   gst_msdkenc_flush_frames (thiz, TRUE);
2028   gst_msdkenc_close_encoder (thiz);
2029   gst_msdkenc_dequeue_all_frames (thiz);
2030
2031   gst_msdkenc_init_encoder (thiz);
2032
2033   return TRUE;
2034 }
2035
2036 static GstFlowReturn
2037 gst_msdkenc_finish (GstVideoEncoder * encoder)
2038 {
2039   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2040
2041   gst_msdkenc_flush_frames (thiz, FALSE);
2042
2043   return GST_FLOW_OK;
2044 }
2045
2046
2047 static gboolean
2048 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
2049 {
2050   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2051   GstVideoInfo info;
2052   GstBufferPool *pool = NULL;
2053   GstAllocator *allocator = NULL;
2054   GstCaps *caps;
2055   guint num_buffers;
2056
2057   if (!thiz->input_state)
2058     return FALSE;
2059
2060   gst_query_parse_allocation (query, &caps, NULL);
2061
2062   if (!caps) {
2063     GST_INFO_OBJECT (encoder, "failed to get caps");
2064     return FALSE;
2065   }
2066
2067   if (!gst_video_info_from_caps (&info, caps)) {
2068     GST_INFO_OBJECT (encoder, "failed to get video info");
2069     return FALSE;
2070   }
2071
2072   /* if upstream allocation query supports dmabuf-capsfeatures,
2073    *  we do allocate dmabuf backed memory */
2074   if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
2075     GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
2076     thiz->use_dmabuf = TRUE;
2077   }
2078
2079   num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
2080   pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, TRUE);
2081
2082   gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info),
2083       num_buffers, 0);
2084   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2085
2086   if (pool) {
2087     GstStructure *config;
2088     GstAllocationParams params = { 0, 31, 0, 0, };
2089
2090     config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
2091
2092     if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
2093       gst_query_add_allocation_param (query, allocator, &params);
2094     gst_structure_free (config);
2095   }
2096
2097   gst_object_unref (pool);
2098
2099   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
2100       query);
2101 }
2102
2103 static gboolean
2104 gst_msdkenc_query (GstVideoEncoder * encoder, GstQuery * query,
2105     GstPadDirection dir)
2106 {
2107   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2108   gboolean ret = FALSE;
2109
2110   switch (GST_QUERY_TYPE (query)) {
2111     case GST_QUERY_CONTEXT:{
2112       GstMsdkContext *msdk_context = NULL;
2113
2114       gst_object_replace ((GstObject **) & msdk_context,
2115           (GstObject *) thiz->context);
2116       ret = gst_msdk_handle_context_query (GST_ELEMENT_CAST (encoder),
2117           query, msdk_context);
2118       gst_clear_object (&msdk_context);
2119       break;
2120     }
2121     default:
2122       if (dir == GST_PAD_SRC) {
2123         ret =
2124             GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
2125       } else {
2126         ret =
2127             GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
2128       }
2129       break;
2130   }
2131
2132   return ret;
2133 }
2134
2135 static gboolean
2136 gst_msdkenc_src_query (GstVideoEncoder * encoder, GstQuery * query)
2137 {
2138   return gst_msdkenc_query (encoder, query, GST_PAD_SRC);
2139 }
2140
2141 static gboolean
2142 gst_msdkenc_sink_query (GstVideoEncoder * encoder, GstQuery * query)
2143 {
2144   return gst_msdkenc_query (encoder, query, GST_PAD_SINK);
2145 }
2146
2147 static void
2148 gst_msdkenc_dispose (GObject * object)
2149 {
2150   GstMsdkEnc *thiz = GST_MSDKENC (object);
2151
2152   if (thiz->input_state)
2153     gst_video_codec_state_unref (thiz->input_state);
2154   thiz->input_state = NULL;
2155
2156   gst_clear_object (&thiz->msdk_pool);
2157   gst_clear_object (&thiz->msdk_converted_pool);
2158   gst_clear_object (&thiz->old_context);
2159
2160   gst_clear_structure (&thiz->ext_coding_props);
2161
2162   G_OBJECT_CLASS (parent_class)->dispose (object);
2163 }
2164
2165 static gboolean
2166 gst_msdkenc_need_conversion (GstMsdkEnc * encoder, GstVideoInfo * info,
2167     GstVideoFormat * out_format)
2168 {
2169   switch (GST_VIDEO_INFO_FORMAT (info)) {
2170     case GST_VIDEO_FORMAT_NV12:
2171     case GST_VIDEO_FORMAT_P010_10LE:
2172     case GST_VIDEO_FORMAT_VUYA:
2173 #if (MFX_VERSION >= 1027)
2174     case GST_VIDEO_FORMAT_Y410:
2175     case GST_VIDEO_FORMAT_Y210:
2176 #endif
2177       return FALSE;
2178
2179     default:
2180       if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10)
2181         *out_format = GST_VIDEO_FORMAT_P010_10LE;
2182       else
2183         *out_format = GST_VIDEO_FORMAT_NV12;
2184       return TRUE;
2185   }
2186 }
2187
2188 static gboolean
2189 gst_msdkenc_need_reconfig (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
2190 {
2191   return FALSE;
2192 }
2193
2194 static void
2195 gst_msdkenc_set_extra_params (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
2196 {
2197   /* Do nothing */
2198 }
2199
2200 static void
2201 gst_msdkenc_class_init (GstMsdkEncClass * klass)
2202 {
2203   GObjectClass *gobject_class;
2204   GstElementClass *element_class;
2205   GstVideoEncoderClass *gstencoder_class;
2206
2207   gobject_class = G_OBJECT_CLASS (klass);
2208   element_class = GST_ELEMENT_CLASS (klass);
2209   gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
2210
2211   klass->need_conversion = gst_msdkenc_need_conversion;
2212   klass->need_reconfig = gst_msdkenc_need_reconfig;
2213   klass->set_extra_params = gst_msdkenc_set_extra_params;
2214   klass->qp_max = 51;
2215   klass->qp_min = 0;
2216
2217   gobject_class->dispose = gst_msdkenc_dispose;
2218
2219   element_class->set_context = gst_msdkenc_set_context;
2220
2221   gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkenc_set_format);
2222   gstencoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkenc_handle_frame);
2223   gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkenc_start);
2224   gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkenc_stop);
2225   gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkenc_flush);
2226   gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkenc_finish);
2227   gstencoder_class->propose_allocation =
2228       GST_DEBUG_FUNCPTR (gst_msdkenc_propose_allocation);
2229   gstencoder_class->src_query = GST_DEBUG_FUNCPTR (gst_msdkenc_src_query);
2230   gstencoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_msdkenc_sink_query);
2231
2232   gst_element_class_add_static_pad_template (element_class, &sink_factory);
2233 }
2234
2235 static void
2236 gst_msdkenc_init (GstMsdkEnc * thiz)
2237 {
2238   thiz->hardware = PROP_HARDWARE_DEFAULT;
2239   thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
2240   thiz->target_usage = PROP_TARGET_USAGE_DEFAULT;
2241   thiz->rate_control = PROP_RATE_CONTROL_DEFAULT;
2242   thiz->bitrate = PROP_BITRATE_DEFAULT;
2243   thiz->max_frame_size = PROP_MAX_FRAME_SIZE_DEFAULT;
2244   thiz->max_vbv_bitrate = PROP_MAX_VBV_BITRATE_DEFAULT;
2245   thiz->accuracy = PROP_AVBR_ACCURACY_DEFAULT;
2246   thiz->convergence = PROP_AVBR_ACCURACY_DEFAULT;
2247   thiz->lookahead_depth = PROP_RC_LOOKAHEAD_DEPTH_DEFAULT;
2248   thiz->qpi = PROP_QPI_DEFAULT;
2249   thiz->qpp = PROP_QPP_DEFAULT;
2250   thiz->qpb = PROP_QPB_DEFAULT;
2251   thiz->gop_size = PROP_GOP_SIZE_DEFAULT;
2252   thiz->ref_frames = PROP_REF_FRAMES_DEFAULT;
2253   thiz->i_frames = PROP_I_FRAMES_DEFAULT;
2254   thiz->b_frames = PROP_B_FRAMES_DEFAULT;
2255   thiz->num_slices = PROP_NUM_SLICES_DEFAULT;
2256   thiz->mbbrc = PROP_MBBRC_DEFAULT;
2257   thiz->adaptive_i = PROP_ADAPTIVE_I_DEFAULT;
2258   thiz->adaptive_b = PROP_ADAPTIVE_B_DEFAULT;
2259
2260   thiz->ext_coding_props = gst_structure_new (EC_PROPS_STRUCT_NAME,
2261       EC_PROPS_EXTBRC, G_TYPE_STRING, "off", NULL);
2262 }
2263
2264 /* gst_msdkenc_set_common_property:
2265  *
2266  * This is a helper function to set the common property
2267  * of base encoder from subclass implementation.
2268  */
2269 gboolean
2270 gst_msdkenc_set_common_property (GObject * object, guint prop_id,
2271     const GValue * value, GParamSpec * pspec)
2272 {
2273   GstMsdkEnc *thiz = GST_MSDKENC (object);
2274   GstState state;
2275   gboolean ret = TRUE;
2276
2277   GST_OBJECT_LOCK (thiz);
2278
2279   state = GST_STATE (thiz);
2280   if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
2281       !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) {
2282     ret = FALSE;
2283     goto wrong_state;
2284   }
2285
2286   switch (prop_id) {
2287     case GST_MSDKENC_PROP_HARDWARE:
2288       thiz->hardware = g_value_get_boolean (value);
2289       break;
2290     case GST_MSDKENC_PROP_ASYNC_DEPTH:
2291       thiz->async_depth = g_value_get_uint (value);
2292       break;
2293     case GST_MSDKENC_PROP_TARGET_USAGE:
2294       thiz->target_usage = g_value_get_uint (value);
2295       break;
2296     case GST_MSDKENC_PROP_RATE_CONTROL:
2297       thiz->rate_control = g_value_get_enum (value);
2298       break;
2299     case GST_MSDKENC_PROP_BITRATE:
2300     {
2301       guint bitrate = g_value_get_uint (value);
2302       /* Ensure that bitrate changed before triggering a reconfig */
2303       if (bitrate != thiz->bitrate) {
2304         thiz->bitrate = bitrate;
2305         thiz->reconfig = TRUE;
2306         GST_DEBUG_OBJECT (thiz, "changed bitrate to %u", bitrate);
2307       }
2308       break;
2309     }
2310     case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
2311       thiz->max_frame_size = g_value_get_uint (value);
2312       break;
2313     case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
2314       thiz->max_vbv_bitrate = g_value_get_uint (value);
2315       break;
2316     case GST_MSDKENC_PROP_AVBR_ACCURACY:
2317       thiz->accuracy = g_value_get_uint (value);
2318       break;
2319     case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
2320       thiz->convergence = g_value_get_uint (value);
2321       break;
2322     case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
2323       thiz->lookahead_depth = g_value_get_uint (value);
2324       break;
2325     case GST_MSDKENC_PROP_QPI:
2326       thiz->qpi = g_value_get_uint (value);
2327       break;
2328     case GST_MSDKENC_PROP_QPP:
2329       thiz->qpp = g_value_get_uint (value);
2330       break;
2331     case GST_MSDKENC_PROP_QPB:
2332       thiz->qpb = g_value_get_uint (value);
2333       break;
2334     case GST_MSDKENC_PROP_GOP_SIZE:
2335       thiz->gop_size = g_value_get_uint (value);
2336       break;
2337     case GST_MSDKENC_PROP_REF_FRAMES:
2338       thiz->ref_frames = g_value_get_uint (value);
2339       break;
2340     case GST_MSDKENC_PROP_I_FRAMES:
2341       thiz->i_frames = g_value_get_uint (value);
2342       break;
2343     case GST_MSDKENC_PROP_B_FRAMES:
2344       thiz->b_frames = g_value_get_uint (value);
2345       break;
2346     case GST_MSDKENC_PROP_NUM_SLICES:
2347       thiz->num_slices = g_value_get_uint (value);
2348       break;
2349     case GST_MSDKENC_PROP_MBBRC:
2350       thiz->mbbrc = g_value_get_enum (value);
2351       break;
2352     case GST_MSDKENC_PROP_ADAPTIVE_I:
2353       thiz->adaptive_i = g_value_get_enum (value);
2354       break;
2355     case GST_MSDKENC_PROP_ADAPTIVE_B:
2356       thiz->adaptive_b = g_value_get_enum (value);
2357       break;
2358     case GST_MSDKENC_PROP_EXT_CODING_PROPS:
2359     {
2360       const GstStructure *s = gst_value_get_structure (value);
2361       const gchar *name = gst_structure_get_name (s);
2362       gst_structure_set_name (thiz->ext_coding_props, name);
2363       if (!structure_transform (s, thiz->ext_coding_props)) {
2364         GST_ERROR_OBJECT (thiz, "failed to transform structure");
2365       }
2366       break;
2367     }
2368     default:
2369       ret = FALSE;
2370       break;
2371   }
2372   GST_OBJECT_UNLOCK (thiz);
2373   return ret;
2374
2375   /* ERROR */
2376 wrong_state:
2377   {
2378     GST_WARNING_OBJECT (thiz, "setting property in wrong state");
2379     GST_OBJECT_UNLOCK (thiz);
2380     return ret;
2381   }
2382 }
2383
2384 /* gst_msdkenc_get_common_property:
2385  *
2386  * This is a helper function to get the common property
2387  * of base encoder from subclass implementation.
2388  */
2389 gboolean
2390 gst_msdkenc_get_common_property (GObject * object, guint prop_id,
2391     GValue * value, GParamSpec * pspec)
2392 {
2393   GstMsdkEnc *thiz = GST_MSDKENC (object);
2394   gboolean ret = TRUE;
2395
2396   GST_OBJECT_LOCK (thiz);
2397   switch (prop_id) {
2398     case GST_MSDKENC_PROP_HARDWARE:
2399       g_value_set_boolean (value, thiz->hardware);
2400       break;
2401     case GST_MSDKENC_PROP_ASYNC_DEPTH:
2402       g_value_set_uint (value, thiz->async_depth);
2403       break;
2404     case GST_MSDKENC_PROP_TARGET_USAGE:
2405       g_value_set_uint (value, thiz->target_usage);
2406       break;
2407     case GST_MSDKENC_PROP_RATE_CONTROL:
2408       g_value_set_enum (value, thiz->rate_control);
2409       break;
2410     case GST_MSDKENC_PROP_BITRATE:
2411       g_value_set_uint (value, thiz->bitrate);
2412       break;
2413     case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
2414       g_value_set_uint (value, thiz->max_frame_size);
2415       break;
2416     case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
2417       g_value_set_uint (value, thiz->max_vbv_bitrate);
2418       break;
2419     case GST_MSDKENC_PROP_AVBR_ACCURACY:
2420       g_value_set_uint (value, thiz->accuracy);
2421       break;
2422     case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
2423       g_value_set_uint (value, thiz->convergence);
2424       break;
2425     case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
2426       g_value_set_uint (value, thiz->lookahead_depth);
2427       break;
2428     case GST_MSDKENC_PROP_QPI:
2429       g_value_set_uint (value, thiz->qpi);
2430       break;
2431     case GST_MSDKENC_PROP_QPP:
2432       g_value_set_uint (value, thiz->qpp);
2433       break;
2434     case GST_MSDKENC_PROP_QPB:
2435       g_value_set_uint (value, thiz->qpb);
2436       break;
2437     case GST_MSDKENC_PROP_GOP_SIZE:
2438       g_value_set_uint (value, thiz->gop_size);
2439       break;
2440     case GST_MSDKENC_PROP_REF_FRAMES:
2441       g_value_set_uint (value, thiz->ref_frames);
2442       break;
2443     case GST_MSDKENC_PROP_I_FRAMES:
2444       g_value_set_uint (value, thiz->i_frames);
2445       break;
2446     case GST_MSDKENC_PROP_B_FRAMES:
2447       g_value_set_uint (value, thiz->b_frames);
2448       break;
2449     case GST_MSDKENC_PROP_NUM_SLICES:
2450       g_value_set_uint (value, thiz->num_slices);
2451       break;
2452     case GST_MSDKENC_PROP_MBBRC:
2453       g_value_set_enum (value, thiz->mbbrc);
2454       break;
2455     case GST_MSDKENC_PROP_ADAPTIVE_I:
2456       g_value_set_enum (value, thiz->adaptive_i);
2457       break;
2458     case GST_MSDKENC_PROP_ADAPTIVE_B:
2459       g_value_set_enum (value, thiz->adaptive_b);
2460       break;
2461     case GST_MSDKENC_PROP_EXT_CODING_PROPS:
2462       gst_value_set_structure (value, thiz->ext_coding_props);
2463       break;
2464     default:
2465       ret = FALSE;
2466       break;
2467   }
2468   GST_OBJECT_UNLOCK (thiz);
2469   return ret;
2470 }
2471
2472 /* gst_msdkenc_install_common_properties:
2473  * @thiz: a #GstMsdkEnc
2474  *
2475  * This is a helper function to install common properties
2476  * of base encoder from subclass implementation.
2477  * Encoders like jpeg do't require all the common properties
2478  * and they can avoid installing it into base gobject.
2479  */
2480 void
2481 gst_msdkenc_install_common_properties (GstMsdkEncClass * klass)
2482 {
2483   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2484   GParamSpec *obj_properties[GST_MSDKENC_PROP_MAX] = { NULL, };
2485   guint qp_range_max = klass->qp_max;
2486   guint qp_range_min = klass->qp_min;
2487
2488   obj_properties[GST_MSDKENC_PROP_HARDWARE] =
2489       g_param_spec_boolean ("hardware", "Hardware", "Enable hardware encoders",
2490       PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2491
2492   obj_properties[GST_MSDKENC_PROP_ASYNC_DEPTH] =
2493       g_param_spec_uint ("async-depth", "Async Depth",
2494       "Depth of asynchronous pipeline",
2495       1, 20, PROP_ASYNC_DEPTH_DEFAULT,
2496       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2497
2498   obj_properties[GST_MSDKENC_PROP_TARGET_USAGE] =
2499       g_param_spec_uint ("target-usage", "Target Usage",
2500       "1: Best quality, 4: Balanced, 7: Best speed",
2501       1, 7, PROP_TARGET_USAGE_DEFAULT,
2502       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2503
2504   obj_properties[GST_MSDKENC_PROP_RATE_CONTROL] =
2505       g_param_spec_enum ("rate-control", "Rate Control",
2506       "Rate control method", gst_msdkenc_rate_control_get_type (),
2507       PROP_RATE_CONTROL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2508
2509   obj_properties[GST_MSDKENC_PROP_BITRATE] =
2510       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
2511       2000 * 1024, PROP_BITRATE_DEFAULT,
2512       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING);
2513
2514   obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE] =
2515       g_param_spec_uint ("max-frame-size", "Max Frame Size",
2516       "Maximum possible size (in kbyte) of any compressed frames (0: auto-calculate)",
2517       0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_DEFAULT,
2518       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2519
2520   /* Set the same upper bound with bitrate */
2521   obj_properties[GST_MSDKENC_PROP_MAX_VBV_BITRATE] =
2522       g_param_spec_uint ("max-vbv-bitrate", "Max VBV Bitrate",
2523       "Maximum bitrate(kbit/sec) at which data enters Video Buffering Verifier (0: auto-calculate)",
2524       0, 2000 * 1024, PROP_MAX_VBV_BITRATE_DEFAULT,
2525       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2526
2527   obj_properties[GST_MSDKENC_PROP_AVBR_ACCURACY] =
2528       g_param_spec_uint ("accuracy", "Accuracy", "The AVBR Accuracy in "
2529       "the unit of tenth of percent", 0, G_MAXUINT16,
2530       PROP_AVBR_ACCURACY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2531
2532   obj_properties[GST_MSDKENC_PROP_AVBR_CONVERGENCE] =
2533       g_param_spec_uint ("convergence", "Convergence",
2534       "The AVBR Convergence in the unit of 100 frames", 0, G_MAXUINT16,
2535       PROP_AVBR_CONVERGENCE_DEFAULT,
2536       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2537
2538   obj_properties[GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH] =
2539       g_param_spec_uint ("rc-lookahead", "Look-ahead depth",
2540       "Number of frames to look ahead for Rate control", 10, 100,
2541       PROP_RC_LOOKAHEAD_DEPTH_DEFAULT,
2542       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2543
2544   obj_properties[GST_MSDKENC_PROP_QPI] =
2545       g_param_spec_uint ("qpi", "QPI",
2546       "Constant quantizer for I frames (0 unlimited). Also used as "
2547       "ICQQuality or QVBRQuality for different RateControl methods",
2548       qp_range_min, qp_range_max, PROP_QPI_DEFAULT,
2549       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2550
2551   obj_properties[GST_MSDKENC_PROP_QPP] =
2552       g_param_spec_uint ("qpp", "QPP",
2553       "Constant quantizer for P frames (0 unlimited)",
2554       qp_range_min, qp_range_max, PROP_QPP_DEFAULT,
2555       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2556
2557   obj_properties[GST_MSDKENC_PROP_QPB] =
2558       g_param_spec_uint ("qpb", "QPB",
2559       "Constant quantizer for B frames (0 unlimited)",
2560       qp_range_min, qp_range_max, PROP_QPB_DEFAULT,
2561       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2562
2563   obj_properties[GST_MSDKENC_PROP_GOP_SIZE] =
2564       g_param_spec_uint ("gop-size", "GOP Size", "GOP Size", 0,
2565       G_MAXINT, PROP_GOP_SIZE_DEFAULT,
2566       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2567
2568   obj_properties[GST_MSDKENC_PROP_REF_FRAMES] =
2569       g_param_spec_uint ("ref-frames", "Reference Frames",
2570       "Number of reference frames",
2571       0, G_MAXINT, PROP_REF_FRAMES_DEFAULT,
2572       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2573
2574   obj_properties[GST_MSDKENC_PROP_I_FRAMES] =
2575       g_param_spec_uint ("i-frames", "I Frames",
2576       "Number of I frames between IDR frames",
2577       0, G_MAXINT, PROP_I_FRAMES_DEFAULT,
2578       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2579
2580   obj_properties[GST_MSDKENC_PROP_B_FRAMES] =
2581       g_param_spec_uint ("b-frames", "B Frames",
2582       "Number of B frames between I and P frames",
2583       0, G_MAXINT, PROP_B_FRAMES_DEFAULT,
2584       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2585
2586   obj_properties[GST_MSDKENC_PROP_NUM_SLICES] =
2587       g_param_spec_uint ("num-slices", "Number of Slices",
2588       "Number of slices per frame, Zero tells the encoder to "
2589       "choose any slice partitioning allowed by the codec standard",
2590       0, G_MAXINT, PROP_NUM_SLICES_DEFAULT,
2591       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2592
2593   obj_properties[GST_MSDKENC_PROP_MBBRC] =
2594       g_param_spec_enum ("mbbrc", "MB level bitrate control",
2595       "Macroblock level bitrate control",
2596       gst_msdkenc_mbbrc_get_type (),
2597       PROP_MBBRC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2598
2599   obj_properties[GST_MSDKENC_PROP_ADAPTIVE_I] =
2600       g_param_spec_enum ("i-adapt", "Adaptive I-Frame Insertion",
2601       "Adaptive I-Frame Insertion control",
2602       gst_msdkenc_adaptive_i_get_type (),
2603       PROP_ADAPTIVE_I_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2604
2605   obj_properties[GST_MSDKENC_PROP_ADAPTIVE_B] =
2606       g_param_spec_enum ("b-adapt", "Adaptive B-Frame Insertion",
2607       "Adaptive B-Frame Insertion control",
2608       gst_msdkenc_adaptive_b_get_type (),
2609       PROP_ADAPTIVE_B_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2610
2611   /**
2612    * GstMsdkEnc:ext-coding-props
2613    *
2614    * The properties for the external coding.
2615    *
2616    * Supported properties:
2617    * ```
2618    * extbrc         : External bitrate control
2619    *                  String. Range: { auto, on, off } Default: off
2620    * ```
2621    *
2622    * Example:
2623    * ```
2624    * ext-coding-props="props,extbrc=on"
2625    * ```
2626    *
2627    * Since: 1.20
2628    *
2629    */
2630   obj_properties[GST_MSDKENC_PROP_EXT_CODING_PROPS] =
2631       g_param_spec_boxed ("ext-coding-props", "External coding properties",
2632       "The properties for the external coding, refer to the hotdoc for the "
2633       "supported properties",
2634       GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2635
2636   g_object_class_install_properties (gobject_class,
2637       GST_MSDKENC_PROP_MAX, obj_properties);
2638 }