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