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 
53 #ifndef _WIN32
54 #include "gstmsdkallocator_libva.h"
55 #endif
56 
57 static inline void *
_aligned_alloc(size_t alignment,size_t size)58 _aligned_alloc (size_t alignment, size_t size)
59 {
60 #ifdef _WIN32
61   return _aligned_malloc (size, alignment);
62 #else
63   void *out;
64   if (posix_memalign (&out, alignment, size) != 0)
65     out = NULL;
66   return out;
67 #endif
68 }
69 
70 #ifndef _WIN32
71 #define _aligned_free free
72 #endif
73 
74 static void gst_msdkenc_close_encoder (GstMsdkEnc * thiz);
75 
76 GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug);
77 #define GST_CAT_DEFAULT gst_msdkenc_debug
78 
79 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
80     GST_PAD_SINK,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS ("video/x-raw, "
83         "format = (string) { NV12, I420, YV12, YUY2, UYVY, BGRA }, "
84         "framerate = (fraction) [0, MAX], "
85         "width = (int) [ 16, MAX ], height = (int) [ 16, MAX ],"
86         "interlace-mode = (string) progressive" ";"
87         GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_DMABUF,
88             "{ NV12 }")));
89 
90 #define PROP_HARDWARE_DEFAULT            TRUE
91 #define PROP_ASYNC_DEPTH_DEFAULT         4
92 #define PROP_TARGET_USAGE_DEFAULT        (MFX_TARGETUSAGE_BALANCED)
93 #define PROP_RATE_CONTROL_DEFAULT        (MFX_RATECONTROL_CBR)
94 #define PROP_BITRATE_DEFAULT             (2 * 1024)
95 #define PROP_QPI_DEFAULT                 0
96 #define PROP_QPP_DEFAULT                 0
97 #define PROP_QPB_DEFAULT                 0
98 #define PROP_GOP_SIZE_DEFAULT            256
99 #define PROP_REF_FRAMES_DEFAULT          1
100 #define PROP_I_FRAMES_DEFAULT            0
101 #define PROP_B_FRAMES_DEFAULT            0
102 #define PROP_NUM_SLICES_DEFAULT          0
103 #define PROP_AVBR_ACCURACY_DEFAULT       0
104 #define PROP_AVBR_CONVERGENCE_DEFAULT    0
105 #define PROP_RC_LOOKAHEAD_DEPTH_DEFAULT  10
106 #define PROP_MAX_VBV_BITRATE_DEFAULT     0
107 #define PROP_MAX_FRAME_SIZE_DEFAULT      0
108 #define PROP_MBBRC_DEFAULT               MFX_CODINGOPTION_OFF
109 #define PROP_ADAPTIVE_I_DEFAULT          MFX_CODINGOPTION_OFF
110 #define PROP_ADAPTIVE_B_DEFAULT          MFX_CODINGOPTION_OFF
111 
112 #define gst_msdkenc_parent_class parent_class
113 G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER);
114 
115 typedef struct
116 {
117   mfxFrameSurface1 *surface;
118   GstBuffer *buf;
119 } MsdkSurface;
120 
121 void
gst_msdkenc_add_extra_param(GstMsdkEnc * thiz,mfxExtBuffer * param)122 gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param)
123 {
124   if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
125     thiz->extra_params[thiz->num_extra_params] = param;
126     thiz->num_extra_params++;
127   }
128 }
129 
130 static void
gst_msdkenc_set_context(GstElement * element,GstContext * context)131 gst_msdkenc_set_context (GstElement * element, GstContext * context)
132 {
133   GstMsdkContext *msdk_context = NULL;
134   GstMsdkEnc *thiz = GST_MSDKENC (element);
135 
136   if (gst_msdk_context_get_context (context, &msdk_context)) {
137     gst_object_replace ((GstObject **) & thiz->context,
138         (GstObject *) msdk_context);
139     gst_object_unref (msdk_context);
140   }
141 
142   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
143 }
144 
145 static void
ensure_bitrate_control(GstMsdkEnc * thiz)146 ensure_bitrate_control (GstMsdkEnc * thiz)
147 {
148   mfxInfoMFX *mfx = &thiz->param.mfx;
149   mfxExtCodingOption2 *option2 = &thiz->option2;
150   mfxExtCodingOption3 *option3 = &thiz->option3;
151 
152   mfx->RateControlMethod = thiz->rate_control;
153   /* No effect in CQP varient algorithms */
154   if ((mfx->RateControlMethod != MFX_RATECONTROL_CQP) &&
155       (thiz->bitrate > G_MAXUINT16 || thiz->max_vbv_bitrate > G_MAXUINT16)) {
156     mfxU32 max_val = MAX (thiz->max_vbv_bitrate, thiz->bitrate);
157 
158     mfx->BRCParamMultiplier = (mfxU16) ((max_val + 0x10000) / 0x10000);
159     mfx->TargetKbps = (mfxU16) (thiz->bitrate / mfx->BRCParamMultiplier);
160     mfx->MaxKbps = (mfxU16) (thiz->max_vbv_bitrate / mfx->BRCParamMultiplier);
161     mfx->BufferSizeInKB =
162         (mfxU16) (mfx->BufferSizeInKB / mfx->BRCParamMultiplier);
163     /* Currently InitialDelayInKB is not used in this plugin */
164     mfx->InitialDelayInKB =
165         (mfxU16) (mfx->InitialDelayInKB / mfx->BRCParamMultiplier);
166   } else {
167     mfx->TargetKbps = thiz->bitrate;
168     mfx->MaxKbps = thiz->max_vbv_bitrate;
169     mfx->BRCParamMultiplier = 1;
170   }
171 
172   switch (mfx->RateControlMethod) {
173     case MFX_RATECONTROL_CQP:
174       mfx->QPI = thiz->qpi;
175       mfx->QPP = thiz->qpp;
176       mfx->QPB = thiz->qpb;
177       break;
178 
179     case MFX_RATECONTROL_LA_ICQ:
180       option2->LookAheadDepth = thiz->lookahead_depth;
181     case MFX_RATECONTROL_ICQ:
182       mfx->ICQQuality = CLAMP (thiz->qpi, 1, 51);
183       break;
184 
185     case MFX_RATECONTROL_LA:   /* VBR with LA. Only supported in H264?? */
186     case MFX_RATECONTROL_LA_HRD:       /* VBR with LA, HRD compliant */
187       option2->LookAheadDepth = thiz->lookahead_depth;
188       break;
189 
190     case MFX_RATECONTROL_QVBR:
191       option3->QVBRQuality = CLAMP (thiz->qpi, 1, 51);
192       thiz->enable_extopt3 = TRUE;
193       break;
194 
195     case MFX_RATECONTROL_AVBR:
196       mfx->Accuracy = thiz->accuracy;
197       mfx->Convergence = thiz->convergence;
198       break;
199 
200     case MFX_RATECONTROL_VBR:
201       option2->MaxFrameSize = thiz->max_frame_size * 1000;
202       break;
203 
204     case MFX_RATECONTROL_VCM:
205       /*Non HRD compliant mode with no B-frame and interlaced support */
206       thiz->param.mfx.GopRefDist = 0;
207       break;
208 
209     case MFX_RATECONTROL_CBR:
210       break;
211 
212     default:
213       GST_ERROR ("Unsupported RateControl!");
214       break;
215   }
216 }
217 
218 void
gst_msdkenc_ensure_extended_coding_options(GstMsdkEnc * thiz)219 gst_msdkenc_ensure_extended_coding_options (GstMsdkEnc * thiz)
220 {
221   mfxExtCodingOption2 *option2 = &thiz->option2;
222   mfxExtCodingOption3 *option3 = &thiz->option3;
223 
224   /* Fill ExtendedCodingOption2, set non-zero defaults too */
225   option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
226   option2->Header.BufferSz = sizeof (thiz->option2);
227   option2->MBBRC = thiz->mbbrc;
228   option2->AdaptiveI = thiz->adaptive_i;
229   option2->AdaptiveB = thiz->adaptive_b;
230   option2->BitrateLimit = MFX_CODINGOPTION_OFF;
231   option2->EnableMAD = MFX_CODINGOPTION_OFF;
232   option2->UseRawRef = MFX_CODINGOPTION_OFF;
233   gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option2);
234 
235   if (thiz->enable_extopt3) {
236     option3->Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
237     option3->Header.BufferSz = sizeof (thiz->option3);
238     gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option3);
239   }
240 }
241 
242 static gboolean
gst_msdkenc_init_encoder(GstMsdkEnc * thiz)243 gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
244 {
245   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
246   GstVideoInfo *info;
247   mfxSession session;
248   mfxStatus status;
249   mfxFrameAllocRequest request[2];
250   guint i;
251 
252   if (thiz->initialized)
253     return TRUE;
254 
255   if (!thiz->context) {
256     GST_WARNING_OBJECT (thiz, "No MSDK Context");
257     return FALSE;
258   }
259 
260   if (!thiz->input_state) {
261     GST_DEBUG_OBJECT (thiz, "Have no input state yet");
262     return FALSE;
263   }
264   info = &thiz->input_state->info;
265 
266   GST_OBJECT_LOCK (thiz);
267   session = gst_msdk_context_get_session (thiz->context);
268 
269   thiz->has_vpp = FALSE;
270   if (thiz->use_video_memory)
271     gst_msdk_set_frame_allocator (thiz->context);
272 
273   /* Check 10bit input */
274   if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10) {
275     if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_P010_10LE) {
276       GST_WARNING_OBJECT (thiz,
277           "P010_10LE is the only supported 10bit format\n");
278       goto failed;
279     }
280   } else if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_NV12) {
281     if (thiz->use_video_memory)
282       thiz->vpp_param.IOPattern =
283           MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
284     else
285       thiz->vpp_param.IOPattern =
286           MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
287 
288     thiz->vpp_param.vpp.In.Width = GST_ROUND_UP_16 (info->width);
289     thiz->vpp_param.vpp.In.Height = GST_ROUND_UP_32 (info->height);
290     thiz->vpp_param.vpp.In.CropW = info->width;
291     thiz->vpp_param.vpp.In.CropH = info->height;
292     thiz->vpp_param.vpp.In.FrameRateExtN = info->fps_n;
293     thiz->vpp_param.vpp.In.FrameRateExtD = info->fps_d;
294     thiz->vpp_param.vpp.In.AspectRatioW = info->par_n;
295     thiz->vpp_param.vpp.In.AspectRatioH = info->par_d;
296     thiz->vpp_param.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
297     switch (GST_VIDEO_INFO_FORMAT (info)) {
298       case GST_VIDEO_FORMAT_NV12:
299         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_NV12;
300         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
301         break;
302       case GST_VIDEO_FORMAT_YV12:
303       case GST_VIDEO_FORMAT_I420:
304         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YV12;
305         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
306         break;
307       case GST_VIDEO_FORMAT_YUY2:
308         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YUY2;
309         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
310         break;
311       case GST_VIDEO_FORMAT_UYVY:
312         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_UYVY;
313         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
314         break;
315       case GST_VIDEO_FORMAT_BGRA:
316         thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_RGB4;
317         thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
318         break;
319       default:
320         g_assert_not_reached ();
321         break;
322     }
323     thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
324     thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
325     thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
326 
327     /* validate parameters and allow the Media SDK to make adjustments */
328     status = MFXVideoVPP_Query (session, &thiz->vpp_param, &thiz->vpp_param);
329     if (status < MFX_ERR_NONE) {
330       GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
331           msdk_status_to_string (status));
332       goto no_vpp;
333     } else if (status > MFX_ERR_NONE) {
334       GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
335           msdk_status_to_string (status));
336     }
337 
338     status = MFXVideoVPP_QueryIOSurf (session, &thiz->vpp_param, request);
339     if (status < MFX_ERR_NONE) {
340       GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
341           msdk_status_to_string (status));
342       goto no_vpp;
343     } else if (status > MFX_ERR_NONE) {
344       GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
345           msdk_status_to_string (status));
346     }
347 
348     if (thiz->use_video_memory)
349       request[0].NumFrameSuggested +=
350           gst_msdk_context_get_shared_async_depth (thiz->context);
351     thiz->num_vpp_surfaces = request[0].NumFrameSuggested;
352 
353     if (thiz->use_video_memory)
354       gst_msdk_frame_alloc (thiz->context, &(request[0]),
355           &thiz->vpp_alloc_resp);
356 
357     status = MFXVideoVPP_Init (session, &thiz->vpp_param);
358     if (status < MFX_ERR_NONE) {
359       GST_ERROR_OBJECT (thiz, "Init failed (%s)",
360           msdk_status_to_string (status));
361       goto no_vpp;
362     } else if (status > MFX_ERR_NONE) {
363       GST_WARNING_OBJECT (thiz, "Init returned: %s",
364           msdk_status_to_string (status));
365     }
366 
367     status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
368     if (status < MFX_ERR_NONE) {
369       mfxStatus status1;
370       GST_ERROR_OBJECT (thiz, "Get VPP Parameters failed (%s)",
371           msdk_status_to_string (status));
372       status1 = MFXVideoVPP_Close (session);
373       if (status1 != MFX_ERR_NONE && status1 != MFX_ERR_NOT_INITIALIZED)
374         GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
375             msdk_status_to_string (status1));
376 
377       goto no_vpp;
378     } else if (status > MFX_ERR_NONE) {
379       GST_WARNING_OBJECT (thiz, "Get VPP Parameters returned: %s",
380           msdk_status_to_string (status));
381     }
382 
383     thiz->has_vpp = TRUE;
384   }
385 
386   thiz->param.AsyncDepth = thiz->async_depth;
387   if (thiz->use_video_memory)
388     thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
389   else
390     thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
391 
392   thiz->param.mfx.TargetUsage = thiz->target_usage;
393   thiz->param.mfx.GopPicSize = thiz->gop_size;
394   thiz->param.mfx.GopRefDist = thiz->b_frames + 1;
395   thiz->param.mfx.IdrInterval = thiz->i_frames;
396   thiz->param.mfx.NumSlice = thiz->num_slices;
397   thiz->param.mfx.NumRefFrame = thiz->ref_frames;
398   thiz->param.mfx.EncodedOrder = 0;     /* Take input frames in display order */
399 
400   thiz->param.mfx.FrameInfo.Width = GST_ROUND_UP_16 (info->width);
401   thiz->param.mfx.FrameInfo.Height = GST_ROUND_UP_32 (info->height);
402   thiz->param.mfx.FrameInfo.CropW = info->width;
403   thiz->param.mfx.FrameInfo.CropH = info->height;
404   thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
405   thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
406   thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
407   thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
408   thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
409   thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
410 
411   if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_P010_10LE) {
412     thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P010;
413     thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
414     thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
415     thiz->param.mfx.FrameInfo.Shift = 1;
416   } else {
417     thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
418     thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
419     thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
420   }
421 
422   /* ensure bitrate control parameters */
423   ensure_bitrate_control (thiz);
424 
425   /* allow subclass configure further */
426   if (klass->configure) {
427     if (!klass->configure (thiz))
428       goto failed;
429   }
430 
431   if (thiz->num_extra_params) {
432     thiz->param.NumExtParam = thiz->num_extra_params;
433     thiz->param.ExtParam = thiz->extra_params;
434   }
435 
436   /* validate parameters and allow the Media SDK to make adjustments */
437   status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param);
438   if (status < MFX_ERR_NONE) {
439     GST_ERROR_OBJECT (thiz, "Video Encode Query failed (%s)",
440         msdk_status_to_string (status));
441     goto failed;
442   } else if (status > MFX_ERR_NONE) {
443     GST_WARNING_OBJECT (thiz, "Video Encode Query returned: %s",
444         msdk_status_to_string (status));
445   }
446 
447   status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, request);
448   if (status < MFX_ERR_NONE) {
449     GST_ERROR_OBJECT (thiz, "Encode Query IO surfaces failed (%s)",
450         msdk_status_to_string (status));
451     goto failed;
452   } else if (status > MFX_ERR_NONE) {
453     GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
454         msdk_status_to_string (status));
455   }
456 
457   if (thiz->has_vpp)
458     request[0].NumFrameSuggested += thiz->num_vpp_surfaces + 1 - 4;
459 
460   if (thiz->use_video_memory) {
461     if (thiz->use_dmabuf && !thiz->has_vpp)
462       request[0].Type |= MFX_MEMTYPE_EXPORT_FRAME;
463     gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->alloc_resp);
464   }
465 
466   /* Maximum of VPP output and encoder input, if using VPP */
467   if (thiz->has_vpp)
468     request[0].NumFrameSuggested =
469         MAX (request[0].NumFrameSuggested, request[1].NumFrameSuggested);
470   if (request[0].NumFrameSuggested < thiz->param.AsyncDepth) {
471     GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
472         request[0].NumFrameMin, request[0].NumFrameSuggested,
473         thiz->param.AsyncDepth);
474     goto failed;
475   }
476 
477   /* This is VPP output (if any) and encoder input */
478   thiz->num_surfaces = request[0].NumFrameSuggested;
479 
480   GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
481       request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
482 
483   status = MFXVideoENCODE_Init (session, &thiz->param);
484   if (status < MFX_ERR_NONE) {
485     GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
486     goto failed;
487   } else if (status > MFX_ERR_NONE) {
488     GST_WARNING_OBJECT (thiz, "Init returned: %s",
489         msdk_status_to_string (status));
490   }
491 
492   status = MFXVideoENCODE_GetVideoParam (session, &thiz->param);
493   if (status < MFX_ERR_NONE) {
494     GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
495         msdk_status_to_string (status));
496     goto failed;
497   } else if (status > MFX_ERR_NONE) {
498     GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
499         msdk_status_to_string (status));
500   }
501 
502   thiz->num_tasks = thiz->param.AsyncDepth;
503   thiz->tasks = g_new0 (MsdkEncTask, thiz->num_tasks);
504   for (i = 0; i < thiz->num_tasks; i++) {
505     thiz->tasks[i].output_bitstream.Data = _aligned_alloc (32,
506         thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
507         1024);
508     if (!thiz->tasks[i].output_bitstream.Data) {
509       GST_ERROR_OBJECT (thiz, "Memory allocation failed");
510       goto failed;
511     }
512     thiz->tasks[i].output_bitstream.MaxLength =
513         thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
514         1024;
515   }
516   thiz->next_task = 0;
517 
518   thiz->reconfig = FALSE;
519   thiz->initialized = TRUE;
520 
521   GST_OBJECT_UNLOCK (thiz);
522 
523   return TRUE;
524 
525 no_vpp:
526 failed:
527   GST_OBJECT_UNLOCK (thiz);
528   return FALSE;
529 }
530 
531 static void
gst_msdkenc_close_encoder(GstMsdkEnc * thiz)532 gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
533 {
534   guint i;
535   mfxStatus status;
536 
537   if (!thiz->context || !thiz->initialized)
538     return;
539 
540   GST_DEBUG_OBJECT (thiz, "Closing encoder with context %" GST_PTR_FORMAT,
541       thiz->context);
542 
543   gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL);
544   gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
545 
546   if (thiz->use_video_memory)
547     gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
548 
549   status = MFXVideoENCODE_Close (gst_msdk_context_get_session (thiz->context));
550   if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
551     GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
552         msdk_status_to_string (status));
553   }
554 
555   if (thiz->tasks) {
556     for (i = 0; i < thiz->num_tasks; i++) {
557       MsdkEncTask *task = &thiz->tasks[i];
558       if (task->output_bitstream.Data) {
559         _aligned_free (task->output_bitstream.Data);
560       }
561     }
562   }
563   g_free (thiz->tasks);
564   thiz->tasks = NULL;
565 
566   /* Close VPP before freeing the surfaces. They are shared between encoder
567    * and VPP */
568   if (thiz->has_vpp) {
569     if (thiz->use_video_memory)
570       gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
571 
572     status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
573     if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
574       GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
575           msdk_status_to_string (status));
576     }
577   }
578 
579   memset (&thiz->param, 0, sizeof (thiz->param));
580   thiz->num_extra_params = 0;
581   thiz->initialized = FALSE;
582 }
583 
584 typedef struct
585 {
586   GstVideoCodecFrame *frame;
587   MsdkSurface *frame_surface;
588   MsdkSurface *converted_surface;
589 } FrameData;
590 
591 static FrameData *
gst_msdkenc_queue_frame(GstMsdkEnc * thiz,GstVideoCodecFrame * frame,GstVideoInfo * info)592 gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame,
593     GstVideoInfo * info)
594 {
595   FrameData *fdata;
596 
597   fdata = g_slice_new (FrameData);
598   fdata->frame = gst_video_codec_frame_ref (frame);
599 
600   thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
601 
602   return fdata;
603 }
604 
605 static MsdkSurface *
gst_msdkenc_create_surface(mfxFrameSurface1 * surface,GstBuffer * buf)606 gst_msdkenc_create_surface (mfxFrameSurface1 * surface, GstBuffer * buf)
607 {
608   MsdkSurface *msdk_surface;
609   msdk_surface = g_slice_new0 (MsdkSurface);
610   msdk_surface->surface = surface;
611   msdk_surface->buf = buf;
612 
613   return msdk_surface;
614 }
615 
616 static void
gst_msdkenc_free_surface(MsdkSurface * surface)617 gst_msdkenc_free_surface (MsdkSurface * surface)
618 {
619   if (surface->buf)
620     gst_buffer_unref (surface->buf);
621 
622   g_slice_free (MsdkSurface, surface);
623 }
624 
625 static void
gst_msdkenc_free_frame_data(GstMsdkEnc * thiz,FrameData * fdata)626 gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata)
627 {
628   if (fdata->frame_surface)
629     gst_msdkenc_free_surface (fdata->frame_surface);
630   if (thiz->has_vpp)
631     gst_msdkenc_free_surface (fdata->converted_surface);
632 
633   gst_video_codec_frame_unref (fdata->frame);
634   g_slice_free (FrameData, fdata);
635 }
636 
637 static void
gst_msdkenc_dequeue_frame(GstMsdkEnc * thiz,GstVideoCodecFrame * frame)638 gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
639 {
640   GList *l;
641 
642   for (l = thiz->pending_frames; l; l = l->next) {
643     FrameData *fdata = l->data;
644 
645     if (fdata->frame != frame)
646       continue;
647 
648     gst_msdkenc_free_frame_data (thiz, fdata);
649 
650     thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l);
651     return;
652   }
653 }
654 
655 static void
gst_msdkenc_dequeue_all_frames(GstMsdkEnc * thiz)656 gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz)
657 {
658   GList *l;
659 
660   for (l = thiz->pending_frames; l; l = l->next) {
661     FrameData *fdata = l->data;
662 
663     gst_msdkenc_free_frame_data (thiz, fdata);
664   }
665   g_list_free (thiz->pending_frames);
666   thiz->pending_frames = NULL;
667 }
668 
669 static MsdkEncTask *
gst_msdkenc_get_free_task(GstMsdkEnc * thiz)670 gst_msdkenc_get_free_task (GstMsdkEnc * thiz)
671 {
672   MsdkEncTask *tasks = thiz->tasks;
673   guint size = thiz->num_tasks;
674   guint start = thiz->next_task;
675   guint i;
676 
677   if (tasks) {
678     for (i = 0; i < size; i++) {
679       guint t = (start + i) % size;
680       if (tasks[t].sync_point == NULL)
681         return &tasks[t];
682     }
683   }
684   return NULL;
685 }
686 
687 static void
gst_msdkenc_reset_task(MsdkEncTask * task)688 gst_msdkenc_reset_task (MsdkEncTask * task)
689 {
690   task->output_bitstream.DataLength = 0;
691   task->sync_point = NULL;
692 }
693 
694 static GstFlowReturn
gst_msdkenc_finish_frame(GstMsdkEnc * thiz,MsdkEncTask * task,gboolean discard)695 gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task,
696     gboolean discard)
697 {
698   GstVideoCodecFrame *frame;
699 
700   if (!task->sync_point)
701     return GST_FLOW_OK;
702 
703   frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
704 
705   if (!frame) {
706     GST_ERROR_OBJECT (thiz, "failed to get a frame");
707     return GST_FLOW_ERROR;
708   }
709 
710   /* Wait for encoding operation to complete, the magic number 300000 below
711    * is used in MSDK samples
712    * #define MSDK_ENC_WAIT_INTERVAL 300000
713    */
714   if (MFXVideoCORE_SyncOperation (gst_msdk_context_get_session (thiz->context),
715           task->sync_point, 300000) != MFX_ERR_NONE)
716     GST_WARNING_OBJECT (thiz, "failed to do sync operation");
717 
718   if (!discard && task->output_bitstream.DataLength) {
719     GstBuffer *out_buf = NULL;
720     guint8 *data =
721         task->output_bitstream.Data + task->output_bitstream.DataOffset;
722     gsize size = task->output_bitstream.DataLength;
723     out_buf = gst_buffer_new_allocate (NULL, size, NULL);
724     gst_buffer_fill (out_buf, 0, data, size);
725     frame->output_buffer = out_buf;
726     frame->pts =
727         gst_util_uint64_scale (task->output_bitstream.TimeStamp, GST_SECOND,
728         90000);
729     frame->dts =
730         gst_util_uint64_scale (task->output_bitstream.DecodeTimeStamp,
731         GST_SECOND, 90000);
732 
733     if ((task->output_bitstream.FrameType & MFX_FRAMETYPE_IDR) != 0 ||
734         (task->output_bitstream.FrameType & MFX_FRAMETYPE_xIDR) != 0) {
735       GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
736     }
737 
738     /* Mark task as available */
739     gst_msdkenc_reset_task (task);
740   }
741 
742   gst_video_codec_frame_unref (frame);
743   gst_msdkenc_dequeue_frame (thiz, frame);
744 
745   return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
746 }
747 
748 static GstFlowReturn
gst_msdkenc_encode_frame(GstMsdkEnc * thiz,mfxFrameSurface1 * surface,GstVideoCodecFrame * input_frame)749 gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
750     GstVideoCodecFrame * input_frame)
751 {
752   mfxSession session;
753   MsdkEncTask *task;
754   mfxStatus status;
755 
756   if (G_UNLIKELY (thiz->context == NULL)) {
757     gst_msdkenc_dequeue_frame (thiz, input_frame);
758     gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
759     return GST_FLOW_NOT_NEGOTIATED;
760   }
761   session = gst_msdk_context_get_session (thiz->context);
762 
763   task = gst_msdkenc_get_free_task (thiz);
764 
765   for (;;) {
766     /* Force key-frame if needed */
767     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame))
768       thiz->enc_cntrl.FrameType =
769           MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF;
770     else
771       thiz->enc_cntrl.FrameType = MFX_FRAMETYPE_UNKNOWN;
772 
773     status =
774         MFXVideoENCODE_EncodeFrameAsync (session, &thiz->enc_cntrl, surface,
775         &task->output_bitstream, &task->sync_point);
776     if (status != MFX_WRN_DEVICE_BUSY)
777       break;
778     /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
779     g_usleep (1000);
780   };
781 
782   if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
783     GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
784         ("MSDK encode error (%s)", msdk_status_to_string (status)));
785     gst_msdkenc_dequeue_frame (thiz, input_frame);
786     gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
787     return GST_FLOW_ERROR;
788   }
789 
790   if (task->sync_point) {
791     thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
792   } else if (status == MFX_ERR_MORE_DATA) {
793     gst_msdkenc_dequeue_frame (thiz, input_frame);
794   }
795 
796   /* Ensure that next task is available */
797   task = thiz->tasks + thiz->next_task;
798   return gst_msdkenc_finish_frame (thiz, task, FALSE);
799 }
800 
801 static guint
gst_msdkenc_maximum_delayed_frames(GstMsdkEnc * thiz)802 gst_msdkenc_maximum_delayed_frames (GstMsdkEnc * thiz)
803 {
804   return thiz->num_tasks;
805 }
806 
807 static void
gst_msdkenc_set_latency(GstMsdkEnc * thiz)808 gst_msdkenc_set_latency (GstMsdkEnc * thiz)
809 {
810   GstVideoInfo *info = &thiz->input_state->info;
811   gint max_delayed_frames;
812   GstClockTime latency;
813 
814   max_delayed_frames = gst_msdkenc_maximum_delayed_frames (thiz);
815 
816   if (info->fps_n) {
817     latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
818         max_delayed_frames, info->fps_n);
819   } else {
820     /* FIXME: Assume 25fps. This is better than reporting no latency at
821      * all and then later failing in live pipelines
822      */
823     latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
824         max_delayed_frames, 25);
825   }
826 
827   GST_INFO_OBJECT (thiz,
828       "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
829       GST_TIME_ARGS (latency), max_delayed_frames);
830 
831   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (thiz), latency, latency);
832 }
833 
834 static void
gst_msdkenc_flush_frames(GstMsdkEnc * thiz,gboolean discard)835 gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard)
836 {
837   mfxStatus status;
838   mfxSession session;
839   MsdkEncTask *task;
840   guint i, t;
841 
842   if (!thiz->tasks)
843     return;
844 
845   session = gst_msdk_context_get_session (thiz->context);
846 
847   for (;;) {
848     task = thiz->tasks + thiz->next_task;
849     gst_msdkenc_finish_frame (thiz, task, FALSE);
850 
851     status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL,
852         &task->output_bitstream, &task->sync_point);
853 
854     if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
855       GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
856           ("MSDK encode error (%s)", msdk_status_to_string (status)));
857       break;
858     }
859 
860     if (task->sync_point) {
861       thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
862     } else if (status == MFX_ERR_MORE_DATA) {
863       break;
864     }
865   };
866 
867   t = thiz->next_task;
868   for (i = 0; i < thiz->num_tasks; i++) {
869     gst_msdkenc_finish_frame (thiz, &thiz->tasks[t], discard);
870     t = (t + 1) % thiz->num_tasks;
871   }
872 }
873 
874 static gboolean
gst_msdkenc_set_src_caps(GstMsdkEnc * thiz)875 gst_msdkenc_set_src_caps (GstMsdkEnc * thiz)
876 {
877   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
878   GstCaps *outcaps = NULL;
879   GstVideoCodecState *state;
880   GstTagList *tags;
881 
882   if (klass->set_src_caps)
883     outcaps = klass->set_src_caps (thiz);
884 
885   if (!outcaps)
886     return FALSE;
887 
888   state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (thiz),
889       outcaps, thiz->input_state);
890   GST_DEBUG_OBJECT (thiz, "output caps: %" GST_PTR_FORMAT, state->caps);
891 
892   gst_video_codec_state_unref (state);
893 
894   tags = gst_tag_list_new_empty ();
895   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "msdkenc",
896       GST_TAG_MAXIMUM_BITRATE, thiz->bitrate * 1024,
897       GST_TAG_NOMINAL_BITRATE, thiz->bitrate * 1024, NULL);
898   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (thiz), tags,
899       GST_TAG_MERGE_REPLACE);
900   gst_tag_list_unref (tags);
901 
902   return TRUE;
903 }
904 
905 static GstBufferPool *
gst_msdkenc_create_buffer_pool(GstMsdkEnc * thiz,GstCaps * caps,guint num_buffers,gboolean set_align)906 gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps,
907     guint num_buffers, gboolean set_align)
908 {
909   GstBufferPool *pool = NULL;
910   GstStructure *config;
911   GstAllocator *allocator = NULL;
912   GstVideoInfo info;
913   GstVideoAlignment align;
914   GstAllocationParams params = { 0, 31, 0, 0, };
915   mfxFrameAllocResponse *alloc_resp = NULL;
916 
917   if (thiz->has_vpp)
918     alloc_resp = set_align ? &thiz->vpp_alloc_resp : &thiz->alloc_resp;
919   else
920     alloc_resp = &thiz->alloc_resp;
921 
922   pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
923   if (!pool)
924     goto error_no_pool;
925 
926   if (!gst_video_info_from_caps (&info, caps)) {
927     GST_INFO_OBJECT (thiz, "failed to get video info");
928     return NULL;
929   }
930 
931   gst_msdk_set_video_alignment (&info, &align);
932   gst_video_info_align (&info, &align);
933 
934   if (thiz->use_dmabuf)
935     allocator =
936         gst_msdk_dmabuf_allocator_new (thiz->context, &info, alloc_resp);
937   else if (thiz->use_video_memory)
938     allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
939   else
940     allocator = gst_msdk_system_allocator_new (&info);
941 
942   if (!allocator)
943     goto error_no_allocator;
944 
945   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
946   gst_buffer_pool_config_set_params (config, caps, info.size, num_buffers, 0);
947   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
948   gst_buffer_pool_config_add_option (config,
949       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
950 
951   if (thiz->use_video_memory) {
952     gst_buffer_pool_config_add_option (config,
953         GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
954     if (thiz->use_dmabuf)
955       gst_buffer_pool_config_add_option (config,
956           GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
957   }
958 
959   gst_buffer_pool_config_set_video_alignment (config, &align);
960   gst_buffer_pool_config_set_allocator (config, allocator, &params);
961   gst_object_unref (allocator);
962 
963   if (!gst_buffer_pool_set_config (pool, config))
964     goto error_pool_config;
965 
966   if (set_align)
967     thiz->aligned_info = info;
968 
969   return pool;
970 
971 error_no_pool:
972   {
973     GST_INFO_OBJECT (thiz, "failed to create bufferpool");
974     return NULL;
975   }
976 error_no_allocator:
977   {
978     GST_INFO_OBJECT (thiz, "failed to create allocator");
979     gst_object_unref (pool);
980     return NULL;
981   }
982 error_pool_config:
983   {
984     GST_INFO_OBJECT (thiz, "failed to set config");
985     gst_object_unref (pool);
986     gst_object_unref (allocator);
987     return NULL;
988   }
989 }
990 
991 /* Fixme: Common routine used by all msdk elements, should be
992  * moved to a common util file */
993 static gboolean
_gst_caps_has_feature(const GstCaps * caps,const gchar * feature)994 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
995 {
996   guint i;
997 
998   for (i = 0; i < gst_caps_get_size (caps); i++) {
999     GstCapsFeatures *const features = gst_caps_get_features (caps, i);
1000     /* Skip ANY features, we need an exact match for correct evaluation */
1001     if (gst_caps_features_is_any (features))
1002       continue;
1003     if (gst_caps_features_contains (features, feature))
1004       return TRUE;
1005   }
1006   return FALSE;
1007 }
1008 
1009 static gboolean
sinkpad_can_dmabuf(GstMsdkEnc * thiz)1010 sinkpad_can_dmabuf (GstMsdkEnc * thiz)
1011 {
1012   gboolean ret = FALSE;
1013   GstCaps *caps, *allowed_caps;
1014   GstPad *sinkpad;
1015 
1016   sinkpad = GST_VIDEO_ENCODER_SINK_PAD (thiz);
1017   caps = gst_pad_get_pad_template_caps (sinkpad);
1018 
1019   allowed_caps = gst_pad_peer_query_caps (sinkpad, caps);
1020   if (!allowed_caps)
1021     goto done;
1022   if (gst_caps_is_any (allowed_caps) || gst_caps_is_empty (allowed_caps)
1023       || allowed_caps == caps)
1024     goto done;
1025 
1026   if (_gst_caps_has_feature (allowed_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
1027     ret = TRUE;
1028 
1029 done:
1030   if (caps)
1031     gst_caps_unref (caps);
1032   if (allowed_caps)
1033     gst_caps_unref (allowed_caps);
1034   return ret;
1035 }
1036 
1037 static gboolean
gst_msdkenc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)1038 gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
1039 {
1040   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1041   GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1042 
1043   if (state) {
1044     if (thiz->input_state)
1045       gst_video_codec_state_unref (thiz->input_state);
1046     thiz->input_state = gst_video_codec_state_ref (state);
1047   }
1048 
1049   /* TODO: Currently d3d allocator is not implemented.
1050    * So encoder uses system memory by default on Windows.
1051    */
1052 #ifndef _WIN32
1053   thiz->use_video_memory = TRUE;
1054 #else
1055   thiz->use_video_memory = FALSE;
1056 #endif
1057 
1058   GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory",
1059       thiz->use_video_memory ? "video" : "system");
1060 
1061   if (klass->set_format) {
1062     if (!klass->set_format (thiz))
1063       return FALSE;
1064   }
1065 
1066   /* If upstream supports DMABufCapsfeatures, then we request for the dmabuf
1067    * based pipeline usage. Ideally we should have dmabuf support even with
1068    * raw-caps negotiation, but we don't have dmabuf-import support in msdk
1069    * plugin yet */
1070   if (sinkpad_can_dmabuf (thiz)) {
1071     thiz->input_state->caps = gst_caps_make_writable (thiz->input_state->caps);
1072     gst_caps_set_features (thiz->input_state->caps, 0,
1073         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1074     thiz->use_dmabuf = TRUE;
1075   }
1076 
1077   if (!gst_msdkenc_init_encoder (thiz))
1078     return FALSE;
1079 
1080   if (!gst_msdkenc_set_src_caps (thiz)) {
1081     gst_msdkenc_close_encoder (thiz);
1082     return FALSE;
1083   }
1084 
1085   if (!thiz->msdk_pool) {
1086     guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1087     thiz->msdk_pool =
1088         gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps,
1089         num_buffers, TRUE);
1090   }
1091 
1092   gst_msdkenc_set_latency (thiz);
1093 
1094   /* Create another bufferpool if VPP requires */
1095   if (thiz->has_vpp) {
1096     GstVideoInfo *info = &thiz->input_state->info;
1097     GstVideoInfo nv12_info;
1098     GstCaps *caps;
1099     GstBufferPool *pool = NULL;
1100 
1101     gst_video_info_init (&nv12_info);
1102     gst_video_info_set_format (&nv12_info, GST_VIDEO_FORMAT_NV12, info->width,
1103         info->height);
1104     caps = gst_video_info_to_caps (&nv12_info);
1105 
1106     pool =
1107         gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE);
1108 
1109     thiz->msdk_converted_pool = pool;
1110     gst_caps_unref (caps);
1111   }
1112 
1113   return TRUE;
1114 }
1115 
1116 static MsdkSurface *
gst_msdkenc_get_surface_from_pool(GstMsdkEnc * thiz,GstBufferPool * pool,GstBufferPoolAcquireParams * params)1117 gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool,
1118     GstBufferPoolAcquireParams * params)
1119 {
1120   GstBuffer *new_buffer;
1121   mfxFrameSurface1 *new_surface;
1122   MsdkSurface *msdk_surface;
1123 
1124   if (!gst_buffer_pool_is_active (pool) &&
1125       !gst_buffer_pool_set_active (pool, TRUE)) {
1126     GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
1127     return NULL;
1128   }
1129 
1130   if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
1131     GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
1132     return NULL;
1133   }
1134 
1135   if (gst_msdk_is_msdk_buffer (new_buffer))
1136     new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
1137   else {
1138     GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
1139     return NULL;
1140   }
1141 
1142   msdk_surface = gst_msdkenc_create_surface (new_surface, new_buffer);
1143 
1144   return msdk_surface;
1145 }
1146 
1147 #ifndef _WIN32
1148 static gboolean
import_dmabuf_to_msdk_surface(GstMsdkEnc * thiz,GstBuffer * buf,MsdkSurface * msdk_surface)1149 import_dmabuf_to_msdk_surface (GstMsdkEnc * thiz, GstBuffer * buf,
1150     MsdkSurface * msdk_surface)
1151 {
1152   GstMemory *mem = NULL;
1153   GstVideoInfo vinfo;
1154   GstVideoMeta *vmeta;
1155   GstMsdkMemoryID *msdk_mid = NULL;
1156   mfxFrameSurface1 *mfx_surface = NULL;
1157   gint fd, i;
1158   mem = gst_buffer_peek_memory (buf, 0);
1159   fd = gst_dmabuf_memory_get_fd (mem);
1160   if (fd < 0)
1161     return FALSE;
1162 
1163   vinfo = thiz->input_state->info;
1164   /* Update offset/stride/size if there is VideoMeta attached to
1165    * the buffer */
1166   vmeta = gst_buffer_get_video_meta (buf);
1167   if (vmeta) {
1168     if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
1169         GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
1170         GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
1171         GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
1172       GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
1173           "the negotiated width/height/format");
1174       return FALSE;
1175     }
1176     for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
1177       GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
1178       GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
1179     }
1180     GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
1181   }
1182 
1183   /* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions.
1184    * Current media-driver and GMMLib will fail due to strict memory size restrictions.
1185    * Ideally, media-driver should accept what ever memory coming from other drivers
1186    * in case of dmabuf-import and this is how the intel-vaapi-driver works.
1187    * For now, in order to avoid any crash we check the buffer size and fallback
1188    * to copy frame method.
1189    *
1190    * See this: https://github.com/intel/media-driver/issues/169
1191    * */
1192   if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1193     return FALSE;
1194 
1195   mfx_surface = msdk_surface->surface;
1196   msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1197 
1198   /* release the internal memory storage of associated mfxSurface */
1199   gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);
1200 
1201   /* export dmabuf to vasurface */
1202   if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
1203           msdk_mid->surface))
1204     return FALSE;
1205 
1206   return TRUE;
1207 }
1208 #endif
1209 
1210 static MsdkSurface *
gst_msdkenc_get_surface_from_frame(GstMsdkEnc * thiz,GstVideoCodecFrame * frame)1211 gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
1212     GstVideoCodecFrame * frame)
1213 {
1214   GstVideoFrame src_frame, out_frame;
1215   MsdkSurface *msdk_surface;
1216   GstBuffer *inbuf;
1217   GstMemory *mem = NULL;
1218 
1219   inbuf = frame->input_buffer;
1220   if (gst_msdk_is_msdk_buffer (inbuf)) {
1221     msdk_surface = g_slice_new0 (MsdkSurface);
1222     msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
1223     return msdk_surface;
1224   }
1225 
1226   /* If upstream hasn't accpeted the proposed msdk bufferpool,
1227    * just copy frame (if not dmabuf backed )to msdk buffer and take a surface from it.
1228    */
1229   if (!(msdk_surface =
1230           gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL)))
1231     goto error;
1232 
1233 #ifndef _WIN32
1234   /************ dmabuf-import ************* */
1235   /* if upstream provided a dmabuf backed memory, but not an msdk
1236    * buffer, we could try to export the dmabuf to underlined vasurface */
1237   mem = gst_buffer_peek_memory (inbuf, 0);
1238   if (gst_is_dmabuf_memory (mem)) {
1239     if (import_dmabuf_to_msdk_surface (thiz, inbuf, msdk_surface))
1240       return msdk_surface;
1241     else
1242       GST_INFO_OBJECT (thiz, "Upstream dmabuf-backed memory is not imported"
1243           "to the msdk surface, fall back to the copy input frame method");
1244   }
1245 #endif
1246 
1247   if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, inbuf,
1248           GST_MAP_READ)) {
1249     GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
1250     goto error;
1251   }
1252 
1253   if (!gst_video_frame_map (&out_frame, &thiz->aligned_info, msdk_surface->buf,
1254           GST_MAP_WRITE)) {
1255     GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
1256     gst_video_frame_unmap (&src_frame);
1257     goto error;
1258   }
1259 
1260   if (!gst_video_frame_copy (&out_frame, &src_frame)) {
1261     GST_ERROR_OBJECT (thiz, "failed to copy frame");
1262     gst_video_frame_unmap (&out_frame);
1263     gst_video_frame_unmap (&src_frame);
1264     goto error;
1265   }
1266 
1267   gst_video_frame_unmap (&out_frame);
1268   gst_video_frame_unmap (&src_frame);
1269 
1270   gst_buffer_replace (&frame->input_buffer, msdk_surface->buf);
1271   gst_buffer_unref (msdk_surface->buf);
1272   msdk_surface->buf = NULL;
1273 
1274   return msdk_surface;
1275 
1276 error:
1277   if (msdk_surface) {
1278     if (msdk_surface->buf)
1279       gst_buffer_unref (msdk_surface->buf);
1280     g_slice_free (MsdkSurface, msdk_surface);
1281   }
1282   return NULL;
1283 }
1284 
1285 static GstFlowReturn
gst_msdkenc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)1286 gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1287 {
1288   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1289   GstVideoInfo *info = &thiz->input_state->info;
1290   FrameData *fdata;
1291   MsdkSurface *surface;
1292 
1293   if (thiz->reconfig) {
1294     gst_msdkenc_flush_frames (thiz, FALSE);
1295     gst_msdkenc_set_format (encoder, NULL);
1296   }
1297 
1298   if (G_UNLIKELY (thiz->context == NULL))
1299     goto not_inited;
1300 
1301   if (thiz->has_vpp) {
1302     MsdkSurface *vpp_surface;
1303     GstVideoFrame vframe;
1304     mfxSession session;
1305     mfxSyncPoint vpp_sync_point = NULL;
1306     mfxStatus status;
1307 
1308     vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1309     if (!vpp_surface)
1310       goto invalid_surface;
1311     surface =
1312         gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_converted_pool,
1313         NULL);
1314     if (!surface)
1315       goto invalid_surface;
1316 
1317     if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
1318       goto invalid_frame;
1319 
1320     if (frame->pts != GST_CLOCK_TIME_NONE) {
1321       vpp_surface->surface->Data.TimeStamp =
1322           gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1323       surface->surface->Data.TimeStamp =
1324           gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1325     } else {
1326       vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1327       surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1328     }
1329 
1330     session = gst_msdk_context_get_session (thiz->context);
1331     for (;;) {
1332       status =
1333           MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface,
1334           surface->surface, NULL, &vpp_sync_point);
1335       if (status != MFX_WRN_DEVICE_BUSY)
1336         break;
1337       /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1338       g_usleep (1000);
1339     };
1340 
1341     gst_video_frame_unmap (&vframe);
1342 
1343     if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1344       GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Converting frame failed."),
1345           ("MSDK VPP error (%s)", msdk_status_to_string (status)));
1346       gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1347       return GST_FLOW_ERROR;
1348     }
1349 
1350     fdata = g_slice_new0 (FrameData);
1351     fdata->frame = gst_video_codec_frame_ref (frame);
1352     fdata->frame_surface = vpp_surface;
1353     fdata->converted_surface = surface;
1354 
1355     thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
1356   } else {
1357     surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1358     if (!surface)
1359       goto invalid_surface;
1360 
1361     fdata = gst_msdkenc_queue_frame (thiz, frame, info);
1362     if (!fdata)
1363       goto invalid_frame;
1364 
1365     fdata->frame_surface = surface;
1366 
1367     if (frame->pts != GST_CLOCK_TIME_NONE) {
1368       surface->surface->Data.TimeStamp =
1369           gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1370     } else {
1371       surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1372     }
1373   }
1374 
1375   return gst_msdkenc_encode_frame (thiz, surface->surface, frame);
1376 
1377 /* ERRORS */
1378 not_inited:
1379   {
1380     GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1381     return GST_FLOW_NOT_NEGOTIATED;
1382   }
1383 invalid_surface:
1384   {
1385     GST_ERROR_OBJECT (encoder, "Surface pool is full");
1386     return GST_FLOW_ERROR;
1387   }
1388 invalid_frame:
1389   {
1390     GST_WARNING_OBJECT (encoder, "Failed to map frame");
1391     return GST_FLOW_OK;
1392   }
1393 }
1394 
1395 static gboolean
gst_msdkenc_start(GstVideoEncoder * encoder)1396 gst_msdkenc_start (GstVideoEncoder * encoder)
1397 {
1398   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1399 
1400   if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
1401     GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
1402         thiz->context);
1403 
1404     if (gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_ENCODER) {
1405       GstMsdkContext *parent_context, *msdk_context;
1406 
1407       parent_context = thiz->context;
1408       msdk_context = gst_msdk_context_new_with_parent (parent_context);
1409 
1410       if (!msdk_context) {
1411         GST_ERROR_OBJECT (thiz, "Context creation failed");
1412         return FALSE;
1413       }
1414 
1415       thiz->context = msdk_context;
1416       gst_object_unref (parent_context);
1417 
1418       GST_INFO_OBJECT (thiz,
1419           "Creating new context %" GST_PTR_FORMAT " with joined session",
1420           thiz->context);
1421     } else {
1422       gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_ENCODER);
1423     }
1424   } else {
1425     if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
1426             thiz->hardware, GST_MSDK_JOB_ENCODER))
1427       return FALSE;
1428     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1429         thiz->context);
1430   }
1431 
1432   gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
1433 
1434   /* Set the minimum pts to some huge value (1000 hours). This keeps
1435      the dts at the start of the stream from needing to be
1436      negative. */
1437   gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
1438 
1439   return TRUE;
1440 }
1441 
1442 static gboolean
gst_msdkenc_stop(GstVideoEncoder * encoder)1443 gst_msdkenc_stop (GstVideoEncoder * encoder)
1444 {
1445   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1446 
1447   gst_msdkenc_flush_frames (thiz, TRUE);
1448   gst_msdkenc_close_encoder (thiz);
1449   gst_msdkenc_dequeue_all_frames (thiz);
1450 
1451   if (thiz->input_state)
1452     gst_video_codec_state_unref (thiz->input_state);
1453   thiz->input_state = NULL;
1454 
1455   gst_object_replace ((GstObject **) & thiz->context, NULL);
1456 
1457   return TRUE;
1458 }
1459 
1460 static gboolean
gst_msdkenc_flush(GstVideoEncoder * encoder)1461 gst_msdkenc_flush (GstVideoEncoder * encoder)
1462 {
1463   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1464 
1465   gst_msdkenc_flush_frames (thiz, TRUE);
1466   gst_msdkenc_close_encoder (thiz);
1467   gst_msdkenc_dequeue_all_frames (thiz);
1468 
1469   gst_msdkenc_init_encoder (thiz);
1470 
1471   return TRUE;
1472 }
1473 
1474 static GstFlowReturn
gst_msdkenc_finish(GstVideoEncoder * encoder)1475 gst_msdkenc_finish (GstVideoEncoder * encoder)
1476 {
1477   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1478 
1479   gst_msdkenc_flush_frames (thiz, FALSE);
1480 
1481   return GST_FLOW_OK;
1482 }
1483 
1484 
1485 static gboolean
gst_msdkenc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)1486 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1487 {
1488   GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1489   GstVideoInfo info;
1490   GstBufferPool *pool = NULL;
1491   GstAllocator *allocator = NULL;
1492   GstCaps *caps;
1493   guint num_buffers;
1494 
1495   if (!thiz->input_state)
1496     return FALSE;
1497 
1498   gst_query_parse_allocation (query, &caps, NULL);
1499 
1500   if (!caps) {
1501     GST_INFO_OBJECT (encoder, "failed to get caps");
1502     return FALSE;
1503   }
1504 
1505   if (!gst_video_info_from_caps (&info, caps)) {
1506     GST_INFO_OBJECT (encoder, "failed to get video info");
1507     return FALSE;
1508   }
1509 
1510   /* if upstream allocation query supports dmabuf-capsfeatures,
1511    *  we do allocate dmabuf backed memory */
1512   if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
1513     GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
1514     thiz->use_dmabuf = TRUE;
1515   }
1516 
1517   num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1518   pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, TRUE);
1519 
1520   gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info),
1521       num_buffers, 0);
1522   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1523 
1524   if (pool) {
1525     GstStructure *config;
1526     GstAllocationParams params = { 0, 31, 0, 0, };
1527 
1528     config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1529 
1530     if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1531       gst_query_add_allocation_param (query, allocator, &params);
1532     gst_structure_free (config);
1533   }
1534 
1535   gst_object_unref (pool);
1536 
1537   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1538       query);
1539 }
1540 
1541 
1542 static void
gst_msdkenc_finalize(GObject * object)1543 gst_msdkenc_finalize (GObject * object)
1544 {
1545   GstMsdkEnc *thiz = GST_MSDKENC (object);
1546 
1547   if (thiz->input_state)
1548     gst_video_codec_state_unref (thiz->input_state);
1549   thiz->input_state = NULL;
1550 
1551   gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL);
1552   gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
1553 
1554   G_OBJECT_CLASS (parent_class)->finalize (object);
1555 }
1556 
1557 static void
gst_msdkenc_class_init(GstMsdkEncClass * klass)1558 gst_msdkenc_class_init (GstMsdkEncClass * klass)
1559 {
1560   GObjectClass *gobject_class;
1561   GstElementClass *element_class;
1562   GstVideoEncoderClass *gstencoder_class;
1563 
1564   gobject_class = G_OBJECT_CLASS (klass);
1565   element_class = GST_ELEMENT_CLASS (klass);
1566   gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
1567 
1568   gobject_class->finalize = gst_msdkenc_finalize;
1569 
1570   element_class->set_context = gst_msdkenc_set_context;
1571 
1572   gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkenc_set_format);
1573   gstencoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkenc_handle_frame);
1574   gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkenc_start);
1575   gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkenc_stop);
1576   gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkenc_flush);
1577   gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkenc_finish);
1578   gstencoder_class->propose_allocation =
1579       GST_DEBUG_FUNCPTR (gst_msdkenc_propose_allocation);
1580 
1581   gst_element_class_add_static_pad_template (element_class, &sink_factory);
1582 }
1583 
1584 static void
gst_msdkenc_init(GstMsdkEnc * thiz)1585 gst_msdkenc_init (GstMsdkEnc * thiz)
1586 {
1587   thiz->hardware = PROP_HARDWARE_DEFAULT;
1588   thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1589   thiz->target_usage = PROP_TARGET_USAGE_DEFAULT;
1590   thiz->rate_control = PROP_RATE_CONTROL_DEFAULT;
1591   thiz->bitrate = PROP_BITRATE_DEFAULT;
1592   thiz->max_frame_size = PROP_MAX_FRAME_SIZE_DEFAULT;
1593   thiz->max_vbv_bitrate = PROP_MAX_VBV_BITRATE_DEFAULT;
1594   thiz->accuracy = PROP_AVBR_ACCURACY_DEFAULT;
1595   thiz->convergence = PROP_AVBR_ACCURACY_DEFAULT;
1596   thiz->lookahead_depth = PROP_RC_LOOKAHEAD_DEPTH_DEFAULT;
1597   thiz->qpi = PROP_QPI_DEFAULT;
1598   thiz->qpp = PROP_QPP_DEFAULT;
1599   thiz->qpb = PROP_QPB_DEFAULT;
1600   thiz->gop_size = PROP_GOP_SIZE_DEFAULT;
1601   thiz->ref_frames = PROP_REF_FRAMES_DEFAULT;
1602   thiz->i_frames = PROP_I_FRAMES_DEFAULT;
1603   thiz->b_frames = PROP_B_FRAMES_DEFAULT;
1604   thiz->num_slices = PROP_NUM_SLICES_DEFAULT;
1605   thiz->mbbrc = PROP_MBBRC_DEFAULT;
1606   thiz->adaptive_i = PROP_ADAPTIVE_I_DEFAULT;
1607   thiz->adaptive_b = PROP_ADAPTIVE_B_DEFAULT;
1608 }
1609 
1610 /* gst_msdkenc_set_common_property:
1611  *
1612  * This is a helper function to set the common property
1613  * of base encoder from subclass implementation.
1614  */
1615 gboolean
gst_msdkenc_set_common_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1616 gst_msdkenc_set_common_property (GObject * object, guint prop_id,
1617     const GValue * value, GParamSpec * pspec)
1618 {
1619   GstMsdkEnc *thiz = GST_MSDKENC (object);
1620   GstState state;
1621   gboolean ret = TRUE;
1622 
1623   GST_OBJECT_LOCK (thiz);
1624 
1625   state = GST_STATE (thiz);
1626   if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1627       !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) {
1628     ret = FALSE;
1629     goto wrong_state;
1630   }
1631 
1632   switch (prop_id) {
1633     case GST_MSDKENC_PROP_HARDWARE:
1634       thiz->hardware = g_value_get_boolean (value);
1635       break;
1636     case GST_MSDKENC_PROP_ASYNC_DEPTH:
1637       thiz->async_depth = g_value_get_uint (value);
1638       break;
1639     case GST_MSDKENC_PROP_TARGET_USAGE:
1640       thiz->target_usage = g_value_get_uint (value);
1641       break;
1642     case GST_MSDKENC_PROP_RATE_CONTROL:
1643       thiz->rate_control = g_value_get_enum (value);
1644       break;
1645     case GST_MSDKENC_PROP_BITRATE:
1646       thiz->bitrate = g_value_get_uint (value);
1647       thiz->reconfig = TRUE;
1648       break;
1649     case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
1650       thiz->max_frame_size = g_value_get_uint (value);
1651       break;
1652     case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
1653       thiz->max_vbv_bitrate = g_value_get_uint (value);
1654       break;
1655     case GST_MSDKENC_PROP_AVBR_ACCURACY:
1656       thiz->accuracy = g_value_get_uint (value);
1657       break;
1658     case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
1659       thiz->convergence = g_value_get_uint (value);
1660       break;
1661     case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
1662       thiz->lookahead_depth = g_value_get_uint (value);
1663       break;
1664     case GST_MSDKENC_PROP_QPI:
1665       thiz->qpi = g_value_get_uint (value);
1666       break;
1667     case GST_MSDKENC_PROP_QPP:
1668       thiz->qpp = g_value_get_uint (value);
1669       break;
1670     case GST_MSDKENC_PROP_QPB:
1671       thiz->qpb = g_value_get_uint (value);
1672       break;
1673     case GST_MSDKENC_PROP_GOP_SIZE:
1674       thiz->gop_size = g_value_get_uint (value);
1675       break;
1676     case GST_MSDKENC_PROP_REF_FRAMES:
1677       thiz->ref_frames = g_value_get_uint (value);
1678       break;
1679     case GST_MSDKENC_PROP_I_FRAMES:
1680       thiz->i_frames = g_value_get_uint (value);
1681       break;
1682     case GST_MSDKENC_PROP_B_FRAMES:
1683       thiz->b_frames = g_value_get_uint (value);
1684       break;
1685     case GST_MSDKENC_PROP_NUM_SLICES:
1686       thiz->num_slices = g_value_get_uint (value);
1687       break;
1688     case GST_MSDKENC_PROP_MBBRC:
1689       thiz->mbbrc = g_value_get_enum (value);
1690       break;
1691     case GST_MSDKENC_PROP_ADAPTIVE_I:
1692       thiz->adaptive_i = g_value_get_enum (value);
1693       break;
1694     case GST_MSDKENC_PROP_ADAPTIVE_B:
1695       thiz->adaptive_b = g_value_get_enum (value);
1696       break;
1697     default:
1698       ret = FALSE;
1699       break;
1700   }
1701   GST_OBJECT_UNLOCK (thiz);
1702   return ret;
1703 
1704   /* ERROR */
1705 wrong_state:
1706   {
1707     GST_WARNING_OBJECT (thiz, "setting property in wrong state");
1708     GST_OBJECT_UNLOCK (thiz);
1709     return ret;
1710   }
1711 }
1712 
1713 /* gst_msdkenc_get_common_property:
1714  *
1715  * This is a helper function to get the common property
1716  * of base encoder from subclass implementation.
1717  */
1718 gboolean
gst_msdkenc_get_common_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1719 gst_msdkenc_get_common_property (GObject * object, guint prop_id,
1720     GValue * value, GParamSpec * pspec)
1721 {
1722   GstMsdkEnc *thiz = GST_MSDKENC (object);
1723   gboolean ret = TRUE;
1724 
1725   GST_OBJECT_LOCK (thiz);
1726   switch (prop_id) {
1727     case GST_MSDKENC_PROP_HARDWARE:
1728       g_value_set_boolean (value, thiz->hardware);
1729       break;
1730     case GST_MSDKENC_PROP_ASYNC_DEPTH:
1731       g_value_set_uint (value, thiz->async_depth);
1732       break;
1733     case GST_MSDKENC_PROP_TARGET_USAGE:
1734       g_value_set_uint (value, thiz->target_usage);
1735       break;
1736     case GST_MSDKENC_PROP_RATE_CONTROL:
1737       g_value_set_enum (value, thiz->rate_control);
1738       break;
1739     case GST_MSDKENC_PROP_BITRATE:
1740       g_value_set_uint (value, thiz->bitrate);
1741       break;
1742     case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
1743       g_value_set_uint (value, thiz->max_frame_size);
1744       break;
1745     case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
1746       g_value_set_uint (value, thiz->max_vbv_bitrate);
1747       break;
1748     case GST_MSDKENC_PROP_AVBR_ACCURACY:
1749       g_value_set_uint (value, thiz->accuracy);
1750       break;
1751     case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
1752       g_value_set_uint (value, thiz->convergence);
1753       break;
1754     case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
1755       g_value_set_uint (value, thiz->lookahead_depth);
1756       break;
1757     case GST_MSDKENC_PROP_QPI:
1758       g_value_set_uint (value, thiz->qpi);
1759       break;
1760     case GST_MSDKENC_PROP_QPP:
1761       g_value_set_uint (value, thiz->qpp);
1762       break;
1763     case GST_MSDKENC_PROP_QPB:
1764       g_value_set_uint (value, thiz->qpb);
1765       break;
1766     case GST_MSDKENC_PROP_GOP_SIZE:
1767       g_value_set_uint (value, thiz->gop_size);
1768       break;
1769     case GST_MSDKENC_PROP_REF_FRAMES:
1770       g_value_set_uint (value, thiz->ref_frames);
1771       break;
1772     case GST_MSDKENC_PROP_I_FRAMES:
1773       g_value_set_uint (value, thiz->i_frames);
1774       break;
1775     case GST_MSDKENC_PROP_B_FRAMES:
1776       g_value_set_uint (value, thiz->b_frames);
1777       break;
1778     case GST_MSDKENC_PROP_NUM_SLICES:
1779       g_value_set_uint (value, thiz->num_slices);
1780       break;
1781     case GST_MSDKENC_PROP_MBBRC:
1782       g_value_set_enum (value, thiz->mbbrc);
1783       break;
1784     case GST_MSDKENC_PROP_ADAPTIVE_I:
1785       g_value_set_enum (value, thiz->adaptive_i);
1786       break;
1787     case GST_MSDKENC_PROP_ADAPTIVE_B:
1788       g_value_set_enum (value, thiz->adaptive_b);
1789       break;
1790     default:
1791       ret = FALSE;
1792       break;
1793   }
1794   GST_OBJECT_UNLOCK (thiz);
1795   return ret;
1796 }
1797 
1798 /* gst_msdkenc_install_common_properties:
1799  * @thiz: a #GstMsdkEnc
1800  *
1801  * This is a helper function to install common properties
1802  * of base encoder from subclass implementation.
1803  * Encoders like jpeg do't require all the common properties
1804  * and they can avoid installing it into base gobject.
1805  */
1806 void
gst_msdkenc_install_common_properties(GstMsdkEncClass * klass)1807 gst_msdkenc_install_common_properties (GstMsdkEncClass * klass)
1808 {
1809   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1810   GParamSpec *obj_properties[GST_MSDKENC_PROP_MAX] = { NULL, };
1811 
1812   obj_properties[GST_MSDKENC_PROP_HARDWARE] =
1813       g_param_spec_boolean ("hardware", "Hardware", "Enable hardware encoders",
1814       PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1815 
1816   obj_properties[GST_MSDKENC_PROP_ASYNC_DEPTH] =
1817       g_param_spec_uint ("async-depth", "Async Depth",
1818       "Depth of asynchronous pipeline",
1819       1, 20, PROP_ASYNC_DEPTH_DEFAULT,
1820       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1821 
1822   obj_properties[GST_MSDKENC_PROP_TARGET_USAGE] =
1823       g_param_spec_uint ("target-usage", "Target Usage",
1824       "1: Best quality, 4: Balanced, 7: Best speed",
1825       1, 7, PROP_TARGET_USAGE_DEFAULT,
1826       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1827 
1828   obj_properties[GST_MSDKENC_PROP_RATE_CONTROL] =
1829       g_param_spec_enum ("rate-control", "Rate Control",
1830       "Rate control method", gst_msdkenc_rate_control_get_type (),
1831       PROP_RATE_CONTROL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1832 
1833   obj_properties[GST_MSDKENC_PROP_BITRATE] =
1834       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
1835       2000 * 1024, PROP_BITRATE_DEFAULT,
1836       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING);
1837 
1838   obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE] =
1839       g_param_spec_uint ("max-frame-size", "Max Frame Size",
1840       "Maximum possible size (in kb) of any compressed frames (0: auto-calculate)",
1841       0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_DEFAULT,
1842       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1843 
1844   /* Set the same upper bound with bitrate */
1845   obj_properties[GST_MSDKENC_PROP_MAX_VBV_BITRATE] =
1846       g_param_spec_uint ("max-vbv-bitrate", "Max VBV Bitrate",
1847       "Maximum bitrate(kbit/sec) at which data enters Video Buffering Verifier (0: auto-calculate)",
1848       0, 2000 * 1024, PROP_MAX_VBV_BITRATE_DEFAULT,
1849       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1850 
1851   obj_properties[GST_MSDKENC_PROP_AVBR_ACCURACY] =
1852       g_param_spec_uint ("accuracy", "Accuracy", "The AVBR Accuracy in "
1853       "the unit of tenth of percent", 0, G_MAXUINT16,
1854       PROP_AVBR_ACCURACY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1855 
1856   obj_properties[GST_MSDKENC_PROP_AVBR_CONVERGENCE] =
1857       g_param_spec_uint ("convergence", "Convergence",
1858       "The AVBR Convergence in the unit of 100 frames", 0, G_MAXUINT16,
1859       PROP_AVBR_CONVERGENCE_DEFAULT,
1860       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1861 
1862   obj_properties[GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH] =
1863       g_param_spec_uint ("rc-lookahead", "Look-ahead depth",
1864       "Number of frames to look ahead for Rate control", 10, 100,
1865       PROP_RC_LOOKAHEAD_DEPTH_DEFAULT,
1866       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1867 
1868   obj_properties[GST_MSDKENC_PROP_QPI] =
1869       g_param_spec_uint ("qpi", "QPI",
1870       "Constant quantizer for I frames (0 unlimited). Also used as "
1871       "ICQQuality or QVBRQuality for different RateControl methods",
1872       0, 51, PROP_QPI_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1873 
1874   obj_properties[GST_MSDKENC_PROP_QPP] =
1875       g_param_spec_uint ("qpp", "QPP",
1876       "Constant quantizer for P frames (0 unlimited)",
1877       0, 51, PROP_QPP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1878 
1879   obj_properties[GST_MSDKENC_PROP_QPB] =
1880       g_param_spec_uint ("qpb", "QPB",
1881       "Constant quantizer for B frames (0 unlimited)",
1882       0, 51, PROP_QPB_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1883 
1884   obj_properties[GST_MSDKENC_PROP_GOP_SIZE] =
1885       g_param_spec_uint ("gop-size", "GOP Size", "GOP Size", 0,
1886       G_MAXINT, PROP_GOP_SIZE_DEFAULT,
1887       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1888 
1889   obj_properties[GST_MSDKENC_PROP_REF_FRAMES] =
1890       g_param_spec_uint ("ref-frames", "Reference Frames",
1891       "Number of reference frames",
1892       0, G_MAXINT, PROP_REF_FRAMES_DEFAULT,
1893       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1894 
1895   obj_properties[GST_MSDKENC_PROP_I_FRAMES] =
1896       g_param_spec_uint ("i-frames", "I Frames",
1897       "Number of I frames between IDR frames",
1898       0, G_MAXINT, PROP_I_FRAMES_DEFAULT,
1899       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1900 
1901   obj_properties[GST_MSDKENC_PROP_B_FRAMES] =
1902       g_param_spec_uint ("b-frames", "B Frames",
1903       "Number of B frames between I and P frames",
1904       0, G_MAXINT, PROP_B_FRAMES_DEFAULT,
1905       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1906 
1907   obj_properties[GST_MSDKENC_PROP_NUM_SLICES] =
1908       g_param_spec_uint ("num-slices", "Number of Slices",
1909       "Number of slices per frame, Zero tells the encoder to "
1910       "choose any slice partitioning allowed by the codec standard",
1911       0, G_MAXINT, PROP_NUM_SLICES_DEFAULT,
1912       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1913 
1914   obj_properties[GST_MSDKENC_PROP_MBBRC] =
1915       g_param_spec_enum ("mbbrc", "MB level bitrate control",
1916       "Macroblock level bitrate control",
1917       gst_msdkenc_mbbrc_get_type (),
1918       PROP_MBBRC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1919 
1920   obj_properties[GST_MSDKENC_PROP_ADAPTIVE_I] =
1921       g_param_spec_enum ("i-adapt", "Adaptive I-Frame Insertion",
1922       "Adaptive I-Frame Insertion control",
1923       gst_msdkenc_adaptive_i_get_type (),
1924       PROP_ADAPTIVE_I_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1925 
1926   obj_properties[GST_MSDKENC_PROP_ADAPTIVE_B] =
1927       g_param_spec_enum ("b-adapt", "Adaptive B-Frame Insertion",
1928       "Adaptive B-Frame Insertion control",
1929       gst_msdkenc_adaptive_b_get_type (),
1930       PROP_ADAPTIVE_B_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1931 
1932   g_object_class_install_properties (gobject_class,
1933       GST_MSDKENC_PROP_MAX, obj_properties);
1934 }
1935