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