1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Oblong Industries, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
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.
33 * - Add support for interlaced content
34 * - Add support for MVC AVC
35 * - Wrap more configuration options and maybe move properties to derived
47 #include "gstmsdkenc.h"
48 #include "gstmsdkbufferpool.h"
49 #include "gstmsdkvideomemory.h"
50 #include "gstmsdksystemmemory.h"
51 #include "gstmsdkcontextutil.h"
54 #include "gstmsdkallocator_libva.h"
58 _aligned_alloc (size_t alignment, size_t size)
61 return _aligned_malloc (size, alignment);
64 if (posix_memalign (&out, alignment, size) != 0)
71 #define _aligned_free free
74 static void gst_msdkenc_close_encoder (GstMsdkEnc * thiz);
76 GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug);
77 #define GST_CAT_DEFAULT gst_msdkenc_debug
79 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
82 GST_STATIC_CAPS (GST_MSDK_CAPS_STR
83 ("{ NV12, I420, YV12, YUY2, UYVY, BGRA }", "NV12"))
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
108 #define gst_msdkenc_parent_class parent_class
109 G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER);
113 mfxFrameSurface1 *surface;
118 gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param)
120 if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
121 thiz->extra_params[thiz->num_extra_params] = param;
122 thiz->num_extra_params++;
127 gst_msdkenc_set_context (GstElement * element, GstContext * context)
129 GstMsdkContext *msdk_context = NULL;
130 GstMsdkEnc *thiz = GST_MSDKENC (element);
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);
138 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
142 ensure_bitrate_control (GstMsdkEnc * thiz)
144 mfxInfoMFX *mfx = &thiz->param.mfx;
145 mfxExtCodingOption2 *option2 = &thiz->option2;
146 mfxExtCodingOption3 *option3 = &thiz->option3;
148 GST_DEBUG_OBJECT (thiz, "set target bitrate: %u kbit/sec", thiz->bitrate);
150 mfx->RateControlMethod = thiz->rate_control;
151 /* No effect in CQP variant 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);
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);
165 mfx->TargetKbps = thiz->bitrate;
166 mfx->MaxKbps = thiz->max_vbv_bitrate;
167 mfx->BRCParamMultiplier = 1;
170 switch (mfx->RateControlMethod) {
171 case MFX_RATECONTROL_CQP:
172 mfx->QPI = thiz->qpi;
173 mfx->QPP = thiz->qpp;
174 mfx->QPB = thiz->qpb;
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);
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;
188 case MFX_RATECONTROL_QVBR:
189 option3->QVBRQuality = CLAMP (thiz->qpi, 1, 51);
190 thiz->enable_extopt3 = TRUE;
193 case MFX_RATECONTROL_AVBR:
194 mfx->Accuracy = thiz->accuracy;
195 mfx->Convergence = thiz->convergence;
198 case MFX_RATECONTROL_VBR:
199 option2->MaxFrameSize = thiz->max_frame_size * 1000;
202 case MFX_RATECONTROL_VCM:
203 /*Non HRD compliant mode with no B-frame and interlaced support */
204 thiz->param.mfx.GopRefDist = 0;
207 case MFX_RATECONTROL_CBR:
211 GST_ERROR ("Unsupported RateControl!");
217 gst_msdkenc_ensure_extended_coding_options (GstMsdkEnc * thiz)
219 mfxExtCodingOption2 *option2 = &thiz->option2;
220 mfxExtCodingOption3 *option3 = &thiz->option3;
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);
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);
241 gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
243 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
247 mfxFrameAllocRequest request[2];
249 gboolean need_vpp = TRUE;
250 GstVideoFormat encoder_input_fmt;
252 if (thiz->initialized) {
253 GST_DEBUG_OBJECT (thiz, "Already initialized");
257 if (!thiz->context) {
258 GST_WARNING_OBJECT (thiz, "No MSDK Context");
262 if (!thiz->input_state) {
263 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
266 info = &thiz->input_state->info;
268 GST_OBJECT_LOCK (thiz);
269 session = gst_msdk_context_get_session (thiz->context);
271 thiz->has_vpp = FALSE;
272 if (thiz->use_video_memory)
273 gst_msdk_set_frame_allocator (thiz->context);
275 encoder_input_fmt = GST_VIDEO_INFO_FORMAT (info);
276 need_vpp = klass->need_conversion (thiz, info, &encoder_input_fmt);
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;
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;
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;
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;
298 g_assert_not_reached ();
302 if (thiz->use_video_memory)
303 thiz->vpp_param.IOPattern =
304 MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
306 thiz->vpp_param.IOPattern =
307 MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
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;
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;
323 thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
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;
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;
337 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
338 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
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));
348 } else if (status > MFX_ERR_NONE) {
349 GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
350 msdk_status_to_string (status));
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));
358 } else if (status > MFX_ERR_NONE) {
359 GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
360 msdk_status_to_string (status));
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;
368 if (thiz->use_video_memory)
369 gst_msdk_frame_alloc (thiz->context, &(request[0]),
370 &thiz->vpp_alloc_resp);
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));
382 status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
383 if (status < MFX_ERR_NONE) {
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));
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));
398 thiz->has_vpp = TRUE;
401 thiz->param.AsyncDepth = thiz->async_depth;
402 if (thiz->use_video_memory)
403 thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
405 thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
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 */
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;
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;
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;
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;
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;
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;
460 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
461 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
462 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
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;
469 /* ensure bitrate control parameters */
470 ensure_bitrate_control (thiz);
472 /* allow subclass configure further */
473 if (klass->configure) {
474 if (!klass->configure (thiz))
478 if (thiz->num_extra_params) {
479 thiz->param.NumExtParam = thiz->num_extra_params;
480 thiz->param.ExtParam = thiz->extra_params;
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));
489 } else if (status > MFX_ERR_NONE) {
490 GST_WARNING_OBJECT (thiz, "Video Encode Query returned: %s",
491 msdk_status_to_string (status));
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));
499 } else if (status > MFX_ERR_NONE) {
500 GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
501 msdk_status_to_string (status));
504 request[0].NumFrameSuggested += thiz->num_extra_frames;
507 request[0].NumFrameSuggested += thiz->num_vpp_surfaces + 1 - 4;
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);
515 /* Maximum of VPP output and encoder input, if using 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);
526 /* This is VPP output (if any) and encoder input */
527 thiz->num_surfaces = request[0].NumFrameSuggested;
529 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
530 request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
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));
536 } else if (status > MFX_ERR_NONE) {
537 GST_WARNING_OBJECT (thiz, "Init returned: %s",
538 msdk_status_to_string (status));
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));
546 } else if (status > MFX_ERR_NONE) {
547 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
548 msdk_status_to_string (status));
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 *
557 if (!thiz->tasks[i].output_bitstream.Data) {
558 GST_ERROR_OBJECT (thiz, "Memory allocation failed");
561 thiz->tasks[i].output_bitstream.MaxLength =
562 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
567 thiz->reconfig = FALSE;
568 thiz->initialized = TRUE;
570 GST_OBJECT_UNLOCK (thiz);
574 no_vpp_free_resource:
575 if (thiz->use_video_memory)
576 gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
578 GST_OBJECT_UNLOCK (thiz);
583 gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
588 if (!thiz->context || !thiz->initialized)
591 GST_DEBUG_OBJECT (thiz, "Closing encoder with context %" GST_PTR_FORMAT,
594 gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL);
595 gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
597 if (thiz->use_video_memory)
598 gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
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));
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);
614 g_free (thiz->tasks);
617 /* Close VPP before freeing the surfaces. They are shared between encoder
620 if (thiz->use_video_memory)
621 gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
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));
630 memset (&thiz->param, 0, sizeof (thiz->param));
631 thiz->num_extra_params = 0;
632 thiz->initialized = FALSE;
637 GstVideoCodecFrame *frame;
638 MsdkSurface *frame_surface;
639 MsdkSurface *converted_surface;
643 gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame,
648 fdata = g_slice_new (FrameData);
649 fdata->frame = gst_video_codec_frame_ref (frame);
651 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
657 gst_msdkenc_create_surface (mfxFrameSurface1 * surface, GstBuffer * buf)
659 MsdkSurface *msdk_surface;
660 msdk_surface = g_slice_new0 (MsdkSurface);
661 msdk_surface->surface = surface;
662 msdk_surface->buf = buf;
668 gst_msdkenc_free_surface (MsdkSurface * surface)
671 gst_buffer_unref (surface->buf);
673 g_slice_free (MsdkSurface, surface);
677 gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata)
679 if (fdata->frame_surface)
680 gst_msdkenc_free_surface (fdata->frame_surface);
682 gst_msdkenc_free_surface (fdata->converted_surface);
684 gst_video_codec_frame_unref (fdata->frame);
685 g_slice_free (FrameData, fdata);
689 gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
693 for (l = thiz->pending_frames; l;) {
694 FrameData *fdata = l->data;
699 if (fdata->frame != frame)
702 gst_msdkenc_free_frame_data (thiz, fdata);
704 thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l1);
710 gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz)
714 for (l = thiz->pending_frames; l; l = l->next) {
715 FrameData *fdata = l->data;
717 gst_msdkenc_free_frame_data (thiz, fdata);
719 g_list_free (thiz->pending_frames);
720 thiz->pending_frames = NULL;
724 gst_msdkenc_get_free_task (GstMsdkEnc * thiz)
726 MsdkEncTask *tasks = thiz->tasks;
727 guint size = thiz->num_tasks;
728 guint start = thiz->next_task;
732 for (i = 0; i < size; i++) {
733 guint t = (start + i) % size;
734 if (tasks[t].sync_point == NULL)
742 gst_msdkenc_reset_task (MsdkEncTask * task)
744 task->output_bitstream.DataLength = 0;
745 task->sync_point = NULL;
749 gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task,
752 GstVideoCodecFrame *frame;
754 if (!task->sync_point)
757 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
760 GST_ERROR_OBJECT (thiz, "failed to get a frame");
761 return GST_FLOW_ERROR;
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
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");
772 if (!discard && task->output_bitstream.DataLength) {
773 GstBuffer *out_buf = NULL;
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;
781 gst_util_uint64_scale (task->output_bitstream.TimeStamp, GST_SECOND,
784 gst_util_uint64_scale (task->output_bitstream.DecodeTimeStamp,
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);
792 /* Mark task as available */
793 gst_msdkenc_reset_task (task);
796 gst_video_codec_frame_unref (frame);
797 gst_msdkenc_dequeue_frame (thiz, frame);
799 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
803 gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
804 GstVideoCodecFrame * input_frame)
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;
815 session = gst_msdk_context_get_session (thiz->context);
817 task = gst_msdkenc_get_free_task (thiz);
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;
825 thiz->enc_cntrl.FrameType = MFX_FRAMETYPE_UNKNOWN;
828 MFXVideoENCODE_EncodeFrameAsync (session, &thiz->enc_cntrl, surface,
829 &task->output_bitstream, &task->sync_point);
830 if (status != MFX_WRN_DEVICE_BUSY)
832 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
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;
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);
850 /* Ensure that next task is available */
851 task = thiz->tasks + thiz->next_task;
852 return gst_msdkenc_finish_frame (thiz, task, FALSE);
856 gst_msdkenc_maximum_delayed_frames (GstMsdkEnc * thiz)
858 return thiz->num_tasks;
862 gst_msdkenc_set_latency (GstMsdkEnc * thiz)
864 GstVideoInfo *info = &thiz->input_state->info;
865 gint max_delayed_frames;
866 GstClockTime latency;
868 max_delayed_frames = gst_msdkenc_maximum_delayed_frames (thiz);
871 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
872 max_delayed_frames, info->fps_n);
874 /* FIXME: Assume 25fps. This is better than reporting no latency at
875 * all and then later failing in live pipelines
877 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
878 max_delayed_frames, 25);
881 GST_INFO_OBJECT (thiz,
882 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
883 GST_TIME_ARGS (latency), max_delayed_frames);
885 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (thiz), latency, latency);
889 gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard)
899 GST_DEBUG_OBJECT (thiz, "flush frames");
901 session = gst_msdk_context_get_session (thiz->context);
904 task = thiz->tasks + thiz->next_task;
905 gst_msdkenc_finish_frame (thiz, task, FALSE);
907 status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL,
908 &task->output_bitstream, &task->sync_point);
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)));
916 if (task->sync_point) {
917 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
918 } else if (status == MFX_ERR_MORE_DATA) {
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;
931 gst_msdkenc_set_src_caps (GstMsdkEnc * thiz)
933 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
934 GstCaps *outcaps = NULL;
935 GstVideoCodecState *state;
938 if (klass->set_src_caps)
939 outcaps = klass->set_src_caps (thiz);
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);
948 gst_video_codec_state_unref (state);
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);
961 static GstBufferPool *
962 gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps,
963 guint num_buffers, gboolean set_align)
965 GstBufferPool *pool = NULL;
966 GstStructure *config;
967 GstAllocator *allocator = NULL;
969 GstVideoAlignment align;
970 GstAllocationParams params = { 0, 31, 0, 0, };
971 mfxFrameAllocResponse *alloc_resp = NULL;
974 alloc_resp = set_align ? &thiz->vpp_alloc_resp : &thiz->alloc_resp;
976 alloc_resp = &thiz->alloc_resp;
978 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
982 if (!gst_video_info_from_caps (&info, caps)) {
983 GST_INFO_OBJECT (thiz, "failed to get video info");
987 gst_msdk_set_video_alignment (&info, 0, 0, &align);
988 gst_video_info_align (&info, &align);
990 if (thiz->use_dmabuf)
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);
996 allocator = gst_msdk_system_allocator_new (&info);
999 goto error_no_allocator;
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);
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);
1015 gst_buffer_pool_config_set_video_alignment (config, &align);
1016 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
1017 gst_object_unref (allocator);
1019 if (!gst_buffer_pool_set_config (pool, config))
1020 goto error_pool_config;
1023 thiz->aligned_info = info;
1029 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1034 GST_INFO_OBJECT (thiz, "failed to create allocator");
1035 gst_object_unref (pool);
1040 GST_INFO_OBJECT (thiz, "failed to set config");
1041 gst_object_unref (pool);
1042 gst_object_unref (allocator);
1047 /* Fixme: Common routine used by all msdk elements, should be
1048 * moved to a common util file */
1050 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
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))
1059 if (gst_caps_features_contains (features, feature))
1066 sinkpad_can_dmabuf (GstMsdkEnc * thiz)
1068 gboolean ret = FALSE;
1069 GstCaps *caps, *allowed_caps;
1072 sinkpad = GST_VIDEO_ENCODER_SINK_PAD (thiz);
1073 caps = gst_pad_get_pad_template_caps (sinkpad);
1075 allowed_caps = gst_pad_peer_query_caps (sinkpad, caps);
1078 if (gst_caps_is_any (allowed_caps) || gst_caps_is_empty (allowed_caps)
1079 || allowed_caps == caps)
1082 if (_gst_caps_has_feature (allowed_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
1087 gst_caps_unref (caps);
1089 gst_caps_unref (allowed_caps);
1094 gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
1096 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1097 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1100 if (thiz->input_state)
1101 gst_video_codec_state_unref (thiz->input_state);
1102 thiz->input_state = gst_video_codec_state_ref (state);
1105 /* TODO: Currently d3d allocator is not implemented.
1106 * So encoder uses system memory by default on Windows.
1109 thiz->use_video_memory = TRUE;
1111 thiz->use_video_memory = FALSE;
1114 GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory",
1115 thiz->use_video_memory ? "video" : "system");
1117 if (klass->set_format) {
1118 if (!klass->set_format (thiz))
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
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;
1133 if (!gst_msdkenc_init_encoder (thiz))
1136 if (!gst_msdkenc_set_src_caps (thiz)) {
1137 gst_msdkenc_close_encoder (thiz);
1141 if (!thiz->msdk_pool) {
1142 guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1144 gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps,
1148 gst_msdkenc_set_latency (thiz);
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;
1156 GstBufferPool *pool = NULL;
1158 gst_video_info_init (&out_info);
1160 gst_msdk_get_video_format_from_mfx_fourcc (thiz->vpp_param.vpp.
1162 gst_video_info_set_format (&out_info, out_fmt, info->width, info->height);
1163 caps = gst_video_info_to_caps (&out_info);
1165 /* If there's an existing pool try to reuse it when is compatible */
1166 if (thiz->msdk_converted_pool) {
1167 GstStructure *config;
1169 gboolean is_pool_compatible = FALSE;
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);
1177 /* If caps are the same then we are done */
1178 if (is_pool_compatible) {
1179 gst_caps_unref (caps);
1182 /* Release current pool because we are going to create a new one */
1183 gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
1186 /* Otherwise create a new pool */
1188 gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE);
1190 thiz->msdk_converted_pool = pool;
1191 gst_caps_unref (caps);
1198 static MsdkSurface *
1199 gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool,
1200 GstBufferPoolAcquireParams * params)
1202 GstBuffer *new_buffer;
1203 mfxFrameSurface1 *new_surface;
1204 MsdkSurface *msdk_surface;
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");
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");
1217 if (gst_msdk_is_msdk_buffer (new_buffer))
1218 new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
1220 GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
1224 msdk_surface = gst_msdkenc_create_surface (new_surface, new_buffer);
1226 return msdk_surface;
1231 import_dmabuf_to_msdk_surface (GstMsdkEnc * thiz, GstBuffer * buf,
1232 MsdkSurface * msdk_surface)
1234 GstMemory *mem = NULL;
1236 GstVideoMeta *vmeta;
1237 GstMsdkMemoryID *msdk_mid = NULL;
1238 mfxFrameSurface1 *mfx_surface = NULL;
1240 mem = gst_buffer_peek_memory (buf, 0);
1241 fd = gst_dmabuf_memory_get_fd (mem);
1245 vinfo = thiz->input_state->info;
1246 /* Update offset/stride/size if there is VideoMeta attached to
1248 vmeta = gst_buffer_get_video_meta (buf);
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");
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];
1262 GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
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.
1272 * See this: https://github.com/intel/media-driver/issues/169
1274 if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1277 mfx_surface = msdk_surface->surface;
1278 msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1280 /* release the internal memory storage of associated mfxSurface */
1281 gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);
1283 /* export dmabuf to vasurface */
1284 if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
1292 static MsdkSurface *
1293 gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
1294 GstVideoCodecFrame * frame)
1296 GstVideoFrame src_frame, out_frame;
1297 MsdkSurface *msdk_surface;
1299 GstMemory *mem = NULL;
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;
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.
1311 if (!(msdk_surface =
1312 gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL)))
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;
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");
1329 if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, inbuf,
1331 GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
1335 if (!gst_video_frame_map (&out_frame, &thiz->aligned_info, msdk_surface->buf,
1337 GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
1338 gst_video_frame_unmap (&src_frame);
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);
1349 gst_video_frame_unmap (&out_frame);
1350 gst_video_frame_unmap (&src_frame);
1352 gst_buffer_replace (&frame->input_buffer, msdk_surface->buf);
1353 gst_buffer_unref (msdk_surface->buf);
1354 msdk_surface->buf = NULL;
1356 return msdk_surface;
1360 if (msdk_surface->buf)
1361 gst_buffer_unref (msdk_surface->buf);
1362 g_slice_free (MsdkSurface, msdk_surface);
1367 static GstFlowReturn
1368 gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1370 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1371 GstVideoInfo *info = &thiz->input_state->info;
1373 MsdkSurface *surface;
1375 if (thiz->reconfig) {
1376 mfxInfoMFX *mfx = NULL;
1378 GST_INFO_OBJECT (encoder, "Adjust encoder bitrate before current frame");
1379 gst_msdkenc_flush_frames (thiz, FALSE);
1380 gst_msdkenc_close_encoder (thiz);
1382 // This will reinitialized the encoder but keep same input format.
1383 gst_msdkenc_set_format (encoder, NULL);
1385 mfx = &thiz->param.mfx;
1386 GST_INFO_OBJECT (encoder, "New target bitrate: %u", mfx->TargetKbps);
1389 if (G_UNLIKELY (thiz->context == NULL))
1392 if (thiz->has_vpp) {
1393 MsdkSurface *vpp_surface;
1394 GstVideoFrame vframe;
1396 mfxSyncPoint vpp_sync_point = NULL;
1399 vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1401 goto invalid_surface;
1403 gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_converted_pool,
1406 goto invalid_surface;
1408 if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
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);
1417 vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1418 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1421 session = gst_msdk_context_get_session (thiz->context);
1424 MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface,
1425 surface->surface, NULL, &vpp_sync_point);
1426 if (status != MFX_WRN_DEVICE_BUSY)
1428 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1432 gst_video_frame_unmap (&vframe);
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;
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;
1446 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
1448 surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1450 goto invalid_surface;
1452 fdata = gst_msdkenc_queue_frame (thiz, frame, info);
1456 fdata->frame_surface = surface;
1458 if (frame->pts != GST_CLOCK_TIME_NONE) {
1459 surface->surface->Data.TimeStamp =
1460 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1462 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1466 return gst_msdkenc_encode_frame (thiz, surface->surface, frame);
1471 GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1472 return GST_FLOW_NOT_NEGOTIATED;
1476 GST_ERROR_OBJECT (encoder, "Surface pool is full");
1477 return GST_FLOW_ERROR;
1481 GST_WARNING_OBJECT (encoder, "Failed to map frame");
1487 gst_msdkenc_start (GstVideoEncoder * encoder)
1489 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1491 if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
1492 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
1495 /* Check GST_MSDK_JOB_VPP and GST_MSDK_JOB_ENCODER together to avoid sharing context
1496 * between VPP and ENCODER
1498 * gst-launch-1.0 videotestsrc ! video/x-raw,format=I420 ! msdkh264enc ! \
1499 * msdkh264dec ! msdkvpp ! video/x-raw,format=YUY2 ! fakesink
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;
1505 parent_context = thiz->context;
1506 msdk_context = gst_msdk_context_new_with_parent (parent_context);
1508 if (!msdk_context) {
1509 GST_ERROR_OBJECT (thiz, "Context creation failed");
1513 thiz->context = msdk_context;
1514 gst_object_unref (parent_context);
1516 GST_INFO_OBJECT (thiz,
1517 "Creating new context %" GST_PTR_FORMAT " with joined session",
1520 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_ENCODER);
1523 if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
1524 thiz->hardware, GST_MSDK_JOB_ENCODER))
1526 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1530 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
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
1535 gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
1541 gst_msdkenc_stop (GstVideoEncoder * encoder)
1543 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1545 gst_msdkenc_flush_frames (thiz, TRUE);
1546 gst_msdkenc_close_encoder (thiz);
1547 gst_msdkenc_dequeue_all_frames (thiz);
1549 if (thiz->input_state)
1550 gst_video_codec_state_unref (thiz->input_state);
1551 thiz->input_state = NULL;
1553 gst_object_replace ((GstObject **) & thiz->context, NULL);
1559 gst_msdkenc_flush (GstVideoEncoder * encoder)
1561 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1563 GST_DEBUG_OBJECT (encoder, "flush and close encoder");
1565 gst_msdkenc_flush_frames (thiz, TRUE);
1566 gst_msdkenc_close_encoder (thiz);
1567 gst_msdkenc_dequeue_all_frames (thiz);
1569 gst_msdkenc_init_encoder (thiz);
1574 static GstFlowReturn
1575 gst_msdkenc_finish (GstVideoEncoder * encoder)
1577 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1579 gst_msdkenc_flush_frames (thiz, FALSE);
1586 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1588 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1590 GstBufferPool *pool = NULL;
1591 GstAllocator *allocator = NULL;
1595 if (!thiz->input_state)
1598 gst_query_parse_allocation (query, &caps, NULL);
1601 GST_INFO_OBJECT (encoder, "failed to get caps");
1605 if (!gst_video_info_from_caps (&info, caps)) {
1606 GST_INFO_OBJECT (encoder, "failed to get video info");
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;
1617 num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1618 pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, TRUE);
1620 gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info),
1622 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1625 GstStructure *config;
1626 GstAllocationParams params = { 0, 31, 0, 0, };
1628 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1630 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1631 gst_query_add_allocation_param (query, allocator, ¶ms);
1632 gst_structure_free (config);
1635 gst_object_unref (pool);
1637 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1643 gst_msdkenc_finalize (GObject * object)
1645 GstMsdkEnc *thiz = GST_MSDKENC (object);
1647 if (thiz->input_state)
1648 gst_video_codec_state_unref (thiz->input_state);
1649 thiz->input_state = NULL;
1651 gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL);
1652 gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
1654 G_OBJECT_CLASS (parent_class)->finalize (object);
1658 gst_msdkenc_need_conversion (GstMsdkEnc * encoder, GstVideoInfo * info,
1659 GstVideoFormat * out_format)
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:
1671 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10)
1672 *out_format = GST_VIDEO_FORMAT_P010_10LE;
1674 *out_format = GST_VIDEO_FORMAT_NV12;
1680 gst_msdkenc_class_init (GstMsdkEncClass * klass)
1682 GObjectClass *gobject_class;
1683 GstElementClass *element_class;
1684 GstVideoEncoderClass *gstencoder_class;
1686 gobject_class = G_OBJECT_CLASS (klass);
1687 element_class = GST_ELEMENT_CLASS (klass);
1688 gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
1690 klass->need_conversion = gst_msdkenc_need_conversion;
1692 gobject_class->finalize = gst_msdkenc_finalize;
1694 element_class->set_context = gst_msdkenc_set_context;
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);
1705 gst_element_class_add_static_pad_template (element_class, &sink_factory);
1709 gst_msdkenc_init (GstMsdkEnc * thiz)
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;
1734 /* gst_msdkenc_set_common_property:
1736 * This is a helper function to set the common property
1737 * of base encoder from subclass implementation.
1740 gst_msdkenc_set_common_property (GObject * object, guint prop_id,
1741 const GValue * value, GParamSpec * pspec)
1743 GstMsdkEnc *thiz = GST_MSDKENC (object);
1745 gboolean ret = TRUE;
1747 GST_OBJECT_LOCK (thiz);
1749 state = GST_STATE (thiz);
1750 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1751 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) {
1757 case GST_MSDKENC_PROP_HARDWARE:
1758 thiz->hardware = g_value_get_boolean (value);
1760 case GST_MSDKENC_PROP_ASYNC_DEPTH:
1761 thiz->async_depth = g_value_get_uint (value);
1763 case GST_MSDKENC_PROP_TARGET_USAGE:
1764 thiz->target_usage = g_value_get_uint (value);
1766 case GST_MSDKENC_PROP_RATE_CONTROL:
1767 thiz->rate_control = g_value_get_enum (value);
1769 case GST_MSDKENC_PROP_BITRATE:
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);
1780 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
1781 thiz->max_frame_size = g_value_get_uint (value);
1783 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
1784 thiz->max_vbv_bitrate = g_value_get_uint (value);
1786 case GST_MSDKENC_PROP_AVBR_ACCURACY:
1787 thiz->accuracy = g_value_get_uint (value);
1789 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
1790 thiz->convergence = g_value_get_uint (value);
1792 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
1793 thiz->lookahead_depth = g_value_get_uint (value);
1795 case GST_MSDKENC_PROP_QPI:
1796 thiz->qpi = g_value_get_uint (value);
1798 case GST_MSDKENC_PROP_QPP:
1799 thiz->qpp = g_value_get_uint (value);
1801 case GST_MSDKENC_PROP_QPB:
1802 thiz->qpb = g_value_get_uint (value);
1804 case GST_MSDKENC_PROP_GOP_SIZE:
1805 thiz->gop_size = g_value_get_uint (value);
1807 case GST_MSDKENC_PROP_REF_FRAMES:
1808 thiz->ref_frames = g_value_get_uint (value);
1810 case GST_MSDKENC_PROP_I_FRAMES:
1811 thiz->i_frames = g_value_get_uint (value);
1813 case GST_MSDKENC_PROP_B_FRAMES:
1814 thiz->b_frames = g_value_get_uint (value);
1816 case GST_MSDKENC_PROP_NUM_SLICES:
1817 thiz->num_slices = g_value_get_uint (value);
1819 case GST_MSDKENC_PROP_MBBRC:
1820 thiz->mbbrc = g_value_get_enum (value);
1822 case GST_MSDKENC_PROP_ADAPTIVE_I:
1823 thiz->adaptive_i = g_value_get_enum (value);
1825 case GST_MSDKENC_PROP_ADAPTIVE_B:
1826 thiz->adaptive_b = g_value_get_enum (value);
1832 GST_OBJECT_UNLOCK (thiz);
1838 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
1839 GST_OBJECT_UNLOCK (thiz);
1844 /* gst_msdkenc_get_common_property:
1846 * This is a helper function to get the common property
1847 * of base encoder from subclass implementation.
1850 gst_msdkenc_get_common_property (GObject * object, guint prop_id,
1851 GValue * value, GParamSpec * pspec)
1853 GstMsdkEnc *thiz = GST_MSDKENC (object);
1854 gboolean ret = TRUE;
1856 GST_OBJECT_LOCK (thiz);
1858 case GST_MSDKENC_PROP_HARDWARE:
1859 g_value_set_boolean (value, thiz->hardware);
1861 case GST_MSDKENC_PROP_ASYNC_DEPTH:
1862 g_value_set_uint (value, thiz->async_depth);
1864 case GST_MSDKENC_PROP_TARGET_USAGE:
1865 g_value_set_uint (value, thiz->target_usage);
1867 case GST_MSDKENC_PROP_RATE_CONTROL:
1868 g_value_set_enum (value, thiz->rate_control);
1870 case GST_MSDKENC_PROP_BITRATE:
1871 g_value_set_uint (value, thiz->bitrate);
1873 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
1874 g_value_set_uint (value, thiz->max_frame_size);
1876 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
1877 g_value_set_uint (value, thiz->max_vbv_bitrate);
1879 case GST_MSDKENC_PROP_AVBR_ACCURACY:
1880 g_value_set_uint (value, thiz->accuracy);
1882 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
1883 g_value_set_uint (value, thiz->convergence);
1885 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
1886 g_value_set_uint (value, thiz->lookahead_depth);
1888 case GST_MSDKENC_PROP_QPI:
1889 g_value_set_uint (value, thiz->qpi);
1891 case GST_MSDKENC_PROP_QPP:
1892 g_value_set_uint (value, thiz->qpp);
1894 case GST_MSDKENC_PROP_QPB:
1895 g_value_set_uint (value, thiz->qpb);
1897 case GST_MSDKENC_PROP_GOP_SIZE:
1898 g_value_set_uint (value, thiz->gop_size);
1900 case GST_MSDKENC_PROP_REF_FRAMES:
1901 g_value_set_uint (value, thiz->ref_frames);
1903 case GST_MSDKENC_PROP_I_FRAMES:
1904 g_value_set_uint (value, thiz->i_frames);
1906 case GST_MSDKENC_PROP_B_FRAMES:
1907 g_value_set_uint (value, thiz->b_frames);
1909 case GST_MSDKENC_PROP_NUM_SLICES:
1910 g_value_set_uint (value, thiz->num_slices);
1912 case GST_MSDKENC_PROP_MBBRC:
1913 g_value_set_enum (value, thiz->mbbrc);
1915 case GST_MSDKENC_PROP_ADAPTIVE_I:
1916 g_value_set_enum (value, thiz->adaptive_i);
1918 case GST_MSDKENC_PROP_ADAPTIVE_B:
1919 g_value_set_enum (value, thiz->adaptive_b);
1925 GST_OBJECT_UNLOCK (thiz);
1929 /* gst_msdkenc_install_common_properties:
1930 * @thiz: a #GstMsdkEnc
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.
1938 gst_msdkenc_install_common_properties (GstMsdkEncClass * klass)
1940 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1941 GParamSpec *obj_properties[GST_MSDKENC_PROP_MAX] = { NULL, };
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2063 g_object_class_install_properties (gobject_class,
2064 GST_MSDKENC_PROP_MAX, obj_properties);