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