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