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"
55 #include "gstmsdkallocator_libva.h"
56 #include "gstmsdk_va.h"
60 _aligned_alloc (size_t alignment, size_t size)
63 return _aligned_malloc (size, alignment);
66 if (posix_memalign (&out, alignment, size) != 0)
73 #define _aligned_free free
76 static void gst_msdkenc_close_encoder (GstMsdkEnc * thiz);
78 GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug);
79 #define GST_CAT_DEFAULT gst_msdkenc_debug
81 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
84 GST_STATIC_CAPS (GST_MSDK_CAPS_STR
85 ("{ NV12, I420, YV12, YUY2, UYVY, BGRA }", "NV12") "; "
86 GST_MSDK_CAPS_MAKE_WITH_VA_FEATURE ("NV12"))
89 #define PROP_HARDWARE_DEFAULT TRUE
90 #define PROP_ASYNC_DEPTH_DEFAULT 4
91 #define PROP_TARGET_USAGE_DEFAULT (MFX_TARGETUSAGE_BALANCED)
92 #define PROP_RATE_CONTROL_DEFAULT (MFX_RATECONTROL_CBR)
93 #define PROP_BITRATE_DEFAULT (2 * 1024)
94 #define PROP_QPI_DEFAULT 0
95 #define PROP_QPP_DEFAULT 0
96 #define PROP_QPB_DEFAULT 0
97 #define PROP_GOP_SIZE_DEFAULT 256
98 #define PROP_REF_FRAMES_DEFAULT 1
99 #define PROP_I_FRAMES_DEFAULT 0
100 #define PROP_B_FRAMES_DEFAULT 0
101 #define PROP_NUM_SLICES_DEFAULT 0
102 #define PROP_AVBR_ACCURACY_DEFAULT 0
103 #define PROP_AVBR_CONVERGENCE_DEFAULT 0
104 #define PROP_RC_LOOKAHEAD_DEPTH_DEFAULT 10
105 #define PROP_MAX_VBV_BITRATE_DEFAULT 0
106 #define PROP_MAX_FRAME_SIZE_DEFAULT 0
107 #define PROP_MBBRC_DEFAULT MFX_CODINGOPTION_OFF
108 #define PROP_ADAPTIVE_I_DEFAULT MFX_CODINGOPTION_OFF
109 #define PROP_ADAPTIVE_B_DEFAULT MFX_CODINGOPTION_OFF
111 /* External coding properties */
112 #define EC_PROPS_STRUCT_NAME "props"
113 #define EC_PROPS_EXTBRC "extbrc"
115 #define gst_msdkenc_parent_class parent_class
116 G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER);
120 mfxFrameSurface1 *surface;
122 GstBuffer *buf_external;
123 VASurfaceID cache_surface;
127 gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param)
129 if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
130 thiz->extra_params[thiz->num_extra_params] = param;
131 thiz->num_extra_params++;
136 gst_msdkenc_set_context (GstElement * element, GstContext * context)
138 GstMsdkContext *msdk_context = NULL;
139 GstMsdkEnc *thiz = GST_MSDKENC (element);
141 if (gst_msdk_context_get_context (context, &msdk_context)) {
142 gst_object_replace ((GstObject **) & thiz->context,
143 (GstObject *) msdk_context);
144 gst_object_unref (msdk_context);
145 } else if (gst_msdk_context_from_external_display (context,
146 thiz->hardware, 0 /* GST_MSDK_JOB_ENCODER will be set later */ ,
148 gst_object_replace ((GstObject **) & thiz->context,
149 (GstObject *) msdk_context);
150 gst_object_unref (msdk_context);
153 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
157 ensure_bitrate_control (GstMsdkEnc * thiz)
159 mfxInfoMFX *mfx = &thiz->param.mfx;
160 mfxExtCodingOption2 *option2 = &thiz->option2;
161 mfxExtCodingOption3 *option3 = &thiz->option3;
163 GST_DEBUG_OBJECT (thiz, "set target bitrate: %u kbit/sec", thiz->bitrate);
165 mfx->RateControlMethod = thiz->rate_control;
166 /* No effect in CQP variant algorithms */
167 if ((mfx->RateControlMethod != MFX_RATECONTROL_CQP) &&
168 (thiz->bitrate > G_MAXUINT16 || thiz->max_vbv_bitrate > G_MAXUINT16)) {
169 mfxU32 max_val = MAX (thiz->max_vbv_bitrate, thiz->bitrate);
171 mfx->BRCParamMultiplier = (mfxU16) ((max_val + 0x10000) / 0x10000);
172 mfx->TargetKbps = (mfxU16) (thiz->bitrate / mfx->BRCParamMultiplier);
173 mfx->MaxKbps = (mfxU16) (thiz->max_vbv_bitrate / mfx->BRCParamMultiplier);
174 mfx->BufferSizeInKB =
175 (mfxU16) (mfx->BufferSizeInKB / mfx->BRCParamMultiplier);
176 /* Currently InitialDelayInKB is not used in this plugin */
177 mfx->InitialDelayInKB =
178 (mfxU16) (mfx->InitialDelayInKB / mfx->BRCParamMultiplier);
180 mfx->TargetKbps = thiz->bitrate;
181 mfx->MaxKbps = thiz->max_vbv_bitrate;
182 mfx->BRCParamMultiplier = 1;
185 switch (mfx->RateControlMethod) {
186 case MFX_RATECONTROL_CQP:
187 mfx->QPI = thiz->qpi;
188 mfx->QPP = thiz->qpp;
189 mfx->QPB = thiz->qpb;
192 case MFX_RATECONTROL_LA_ICQ:
193 option2->LookAheadDepth = thiz->lookahead_depth;
194 case MFX_RATECONTROL_ICQ:
195 mfx->ICQQuality = CLAMP (thiz->qpi, 1, 51);
198 case MFX_RATECONTROL_LA: /* VBR with LA. Only supported in H264?? */
199 case MFX_RATECONTROL_LA_HRD: /* VBR with LA, HRD compliant */
200 option2->LookAheadDepth = thiz->lookahead_depth;
203 case MFX_RATECONTROL_QVBR:
204 option3->QVBRQuality = CLAMP (thiz->qpi, 1, 51);
205 thiz->enable_extopt3 = TRUE;
208 case MFX_RATECONTROL_AVBR:
209 mfx->Accuracy = thiz->accuracy;
210 mfx->Convergence = thiz->convergence;
213 case MFX_RATECONTROL_VBR:
214 option2->MaxFrameSize = thiz->max_frame_size * 1000;
217 case MFX_RATECONTROL_VCM:
218 /*Non HRD compliant mode with no B-frame and interlaced support */
219 thiz->param.mfx.GopRefDist = 0;
222 case MFX_RATECONTROL_CBR:
226 GST_ERROR ("Unsupported RateControl!");
232 coding_option_get_value (const gchar * key, const gchar * nickname)
234 if (!g_strcmp0 (nickname, "on")) {
235 return MFX_CODINGOPTION_ON;
236 } else if (!g_strcmp0 (nickname, "off")) {
237 return MFX_CODINGOPTION_OFF;
238 } else if (!g_strcmp0 (nickname, "auto")) {
239 return MFX_CODINGOPTION_UNKNOWN;
242 GST_ERROR ("\"%s\" illegal option \"%s\", set to \"off\"", key, nickname);
244 return MFX_CODINGOPTION_OFF;
248 structure_transform (const GstStructure * src, GstStructure * dst)
251 GValue dst_value = G_VALUE_INIT;
254 g_return_val_if_fail (src != NULL, FALSE);
255 g_return_val_if_fail (dst != NULL, FALSE);
257 len = gst_structure_n_fields (src);
259 for (guint i = 0; i < len; i++) {
260 const gchar *key = gst_structure_nth_field_name (src, i);
261 const GValue *src_value = gst_structure_get_value (src, key);
263 if (!gst_structure_has_field (dst, key)) {
264 GST_ERROR ("structure \"%s\" does not support \"%s\"",
265 gst_structure_get_name (dst), key);
270 g_value_init (&dst_value, gst_structure_get_field_type (dst, key));
272 if (g_value_transform (src_value, &dst_value)) {
273 gst_structure_set_value (dst, key, &dst_value);
275 GST_ERROR ("\"%s\" transform %s to %s failed", key,
276 G_VALUE_TYPE_NAME (src_value), G_VALUE_TYPE_NAME (&dst_value));
280 g_value_unset (&dst_value);
286 /* Supported types: gchar*, gboolean, gint, guint, gfloat, gdouble */
288 structure_get_value (const GstStructure * s, const gchar * key, gpointer value)
290 const GValue *gvalue = gst_structure_get_value (s, key);
292 GST_ERROR ("structure \"%s\" does not support \"%s\"",
293 gst_structure_get_name (s), key);
297 switch (G_VALUE_TYPE (gvalue)) {
299 const gchar **val = (const gchar **) value;
300 *val = g_value_get_string (gvalue);
303 case G_TYPE_BOOLEAN:{
304 gboolean *val = (gboolean *) value;
305 *val = g_value_get_boolean (gvalue);
309 gint *val = (gint *) value;
310 *val = g_value_get_int (gvalue);
314 guint *val = (guint *) value;
315 *val = g_value_get_uint (gvalue);
319 gfloat *val = (gfloat *) value;
320 *val = g_value_get_float (gvalue);
324 gdouble *val = (gdouble *) value;
325 *val = g_value_get_double (gvalue);
329 GST_ERROR ("\"%s\" unsupported type %s", key, G_VALUE_TYPE_NAME (gvalue));
337 ext_coding_props_get_value (GstMsdkEnc * thiz,
338 const gchar * key, gpointer value)
341 if (!(ret = structure_get_value (thiz->ext_coding_props, key, value))) {
342 GST_ERROR_OBJECT (thiz, "structure \"%s\" failed to get value for \"%s\"",
343 gst_structure_get_name (thiz->ext_coding_props), key);
350 gst_msdkenc_ensure_extended_coding_options (GstMsdkEnc * thiz)
352 mfxExtCodingOption2 *option2 = &thiz->option2;
353 mfxExtCodingOption3 *option3 = &thiz->option3;
356 ext_coding_props_get_value (thiz, EC_PROPS_EXTBRC, &extbrc);
358 /* Fill ExtendedCodingOption2, set non-zero defaults too */
359 option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
360 option2->Header.BufferSz = sizeof (thiz->option2);
361 option2->MBBRC = thiz->mbbrc;
362 option2->ExtBRC = coding_option_get_value (EC_PROPS_EXTBRC, extbrc);
363 option2->AdaptiveI = thiz->adaptive_i;
364 option2->AdaptiveB = thiz->adaptive_b;
365 option2->BitrateLimit = MFX_CODINGOPTION_OFF;
366 option2->EnableMAD = MFX_CODINGOPTION_OFF;
367 option2->UseRawRef = MFX_CODINGOPTION_OFF;
368 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option2);
370 if (thiz->enable_extopt3) {
371 option3->Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
372 option3->Header.BufferSz = sizeof (thiz->option3);
373 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option3);
377 /* Return TRUE if ROI is changed and update ROI parameters in encoder_roi */
379 gst_msdkenc_get_roi_params (GstMsdkEnc * thiz,
380 GstVideoCodecFrame * frame, mfxExtEncoderROI * encoder_roi)
383 guint num_roi, i, num_valid_roi = 0;
384 gushort roi_mode = G_MAXUINT16;
385 gpointer state = NULL;
386 mfxExtEncoderROI *curr_roi = encoder_roi;
387 mfxExtEncoderROI *prev_roi = encoder_roi + 1;
389 if (!frame || !frame->input_buffer)
392 memset (curr_roi, 0, sizeof (mfxExtEncoderROI));
393 input = frame->input_buffer;
396 gst_buffer_get_n_meta (input, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
401 curr_roi->Header.BufferId = MFX_EXTBUFF_ENCODER_ROI;
402 curr_roi->Header.BufferSz = sizeof (mfxExtEncoderROI);
404 for (i = 0; i < num_roi && num_valid_roi < 256; i++) {
405 GstVideoRegionOfInterestMeta *roi;
408 roi = (GstVideoRegionOfInterestMeta *)
409 gst_buffer_iterate_meta_filtered (input, &state,
410 GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
415 /* ignore roi if overflow */
416 if ((roi->x > G_MAXINT16) || (roi->y > G_MAXINT16)
417 || (roi->w > G_MAXUINT16) || (roi->h > G_MAXUINT16)) {
418 GST_DEBUG_OBJECT (thiz, "Ignoring ROI... ROI overflow");
422 GST_LOG ("Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
423 g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
426 curr_roi->ROI[num_valid_roi].Left = roi->x;
427 curr_roi->ROI[num_valid_roi].Top = roi->y;
428 curr_roi->ROI[num_valid_roi].Right = roi->x + roi->w;
429 curr_roi->ROI[num_valid_roi].Bottom = roi->y + roi->h;
431 s = gst_video_region_of_interest_meta_get_param (roi, "roi/msdk");
436 if (roi_mode == G_MAXUINT16) {
437 if (gst_structure_get_int (s, "delta-qp", &value)) {
438 #if (MFX_VERSION >= 1022)
439 roi_mode = MFX_ROI_MODE_QP_DELTA;
440 curr_roi->ROI[num_valid_roi].DeltaQP = CLAMP (value, -51, 51);
441 GST_LOG ("Use delta-qp %d", value);
444 ("Ignore delta QP because the MFX doesn't support delta QP mode");
446 } else if (gst_structure_get_int (s, "priority", &value)) {
447 roi_mode = MFX_ROI_MODE_PRIORITY;
448 curr_roi->ROI[num_valid_roi].Priority = CLAMP (value, -3, 3);
449 GST_LOG ("Use priority %d", value);
452 #if (MFX_VERSION >= 1022)
453 } else if (roi_mode == MFX_ROI_MODE_QP_DELTA &&
454 gst_structure_get_int (s, "delta-qp", &value)) {
455 curr_roi->ROI[num_valid_roi].DeltaQP = CLAMP (value, -51, 51);
457 } else if (roi_mode == MFX_ROI_MODE_PRIORITY &&
458 gst_structure_get_int (s, "priority", &value)) {
459 curr_roi->ROI[num_valid_roi].Priority = CLAMP (value, -3, 3);
467 #if (MFX_VERSION >= 1022)
468 curr_roi->ROIMode = roi_mode;
471 curr_roi->NumROI = num_valid_roi;
474 if (curr_roi->NumROI == 0 && prev_roi->NumROI == 0)
477 if (curr_roi->NumROI != prev_roi->NumROI ||
478 memcmp (curr_roi, prev_roi, sizeof (mfxExtEncoderROI)) != 0) {
479 *prev_roi = *curr_roi;
487 gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
489 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
493 mfxFrameAllocRequest request[2];
495 gboolean need_vpp = TRUE;
496 GstVideoFormat encoder_input_fmt;
497 mfxExtVideoSignalInfo ext_vsi;
499 if (thiz->initialized) {
500 GST_DEBUG_OBJECT (thiz, "Already initialized");
504 if (!thiz->context) {
505 GST_WARNING_OBJECT (thiz, "No MSDK Context");
509 if (!thiz->input_state) {
510 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
513 info = &thiz->input_state->info;
515 GST_OBJECT_LOCK (thiz);
516 session = gst_msdk_context_get_session (thiz->context);
517 thiz->codename = msdk_get_platform_codename (session);
519 thiz->has_vpp = FALSE;
520 if (thiz->use_video_memory)
521 gst_msdk_set_frame_allocator (thiz->context);
523 encoder_input_fmt = GST_VIDEO_INFO_FORMAT (info);
524 need_vpp = klass->need_conversion (thiz, info, &encoder_input_fmt);
527 switch (GST_VIDEO_INFO_FORMAT (info)) {
528 case GST_VIDEO_FORMAT_YV12:
529 case GST_VIDEO_FORMAT_I420:
530 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YV12;
531 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
533 case GST_VIDEO_FORMAT_YUY2:
534 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YUY2;
535 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
537 case GST_VIDEO_FORMAT_UYVY:
538 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_UYVY;
539 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
541 case GST_VIDEO_FORMAT_BGRA:
542 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_RGB4;
543 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
546 g_assert_not_reached ();
550 if (thiz->use_video_memory)
551 thiz->vpp_param.IOPattern =
552 MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
554 thiz->vpp_param.IOPattern =
555 MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
557 thiz->vpp_param.vpp.In.Width = GST_ROUND_UP_16 (info->width);
558 thiz->vpp_param.vpp.In.Height = GST_ROUND_UP_32 (info->height);
559 thiz->vpp_param.vpp.In.CropW = info->width;
560 thiz->vpp_param.vpp.In.CropH = info->height;
561 thiz->vpp_param.vpp.In.FrameRateExtN = info->fps_n;
562 thiz->vpp_param.vpp.In.FrameRateExtD = info->fps_d;
563 thiz->vpp_param.vpp.In.AspectRatioW = info->par_n;
564 thiz->vpp_param.vpp.In.AspectRatioH = info->par_d;
565 thiz->vpp_param.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
567 /* work-around to avoid zero fps in msdk structure */
568 if (0 == thiz->vpp_param.vpp.In.FrameRateExtN)
569 thiz->vpp_param.vpp.In.FrameRateExtN = 30;
571 thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
573 switch (encoder_input_fmt) {
574 case GST_VIDEO_FORMAT_P010_10LE:
575 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_P010;
576 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
579 case GST_VIDEO_FORMAT_YUY2:
580 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_YUY2;
581 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
585 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
586 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
590 /* validate parameters and allow MFX to make adjustments */
591 status = MFXVideoVPP_Query (session, &thiz->vpp_param, &thiz->vpp_param);
592 if (status < MFX_ERR_NONE) {
593 GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
594 msdk_status_to_string (status));
596 } else if (status > MFX_ERR_NONE) {
597 GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
598 msdk_status_to_string (status));
601 status = MFXVideoVPP_QueryIOSurf (session, &thiz->vpp_param, request);
602 if (status < MFX_ERR_NONE) {
603 GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
604 msdk_status_to_string (status));
606 } else if (status > MFX_ERR_NONE) {
607 GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
608 msdk_status_to_string (status));
611 if (thiz->use_video_memory)
612 request[0].NumFrameSuggested +=
613 gst_msdk_context_get_shared_async_depth (thiz->context);
614 thiz->num_vpp_surfaces = request[0].NumFrameSuggested;
616 if (thiz->use_video_memory)
617 gst_msdk_frame_alloc (thiz->context, &(request[0]),
618 &thiz->vpp_alloc_resp);
620 status = MFXVideoVPP_Init (session, &thiz->vpp_param);
621 if (status < MFX_ERR_NONE) {
622 GST_ERROR_OBJECT (thiz, "Init failed (%s)",
623 msdk_status_to_string (status));
624 goto no_vpp_free_resource;
625 } else if (status > MFX_ERR_NONE) {
626 GST_WARNING_OBJECT (thiz, "Init returned: %s",
627 msdk_status_to_string (status));
630 status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
631 if (status < MFX_ERR_NONE) {
633 GST_ERROR_OBJECT (thiz, "Get VPP Parameters failed (%s)",
634 msdk_status_to_string (status));
635 status1 = MFXVideoVPP_Close (session);
636 if (status1 != MFX_ERR_NONE && status1 != MFX_ERR_NOT_INITIALIZED)
637 GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
638 msdk_status_to_string (status1));
640 goto no_vpp_free_resource;
641 } else if (status > MFX_ERR_NONE) {
642 GST_WARNING_OBJECT (thiz, "Get VPP Parameters returned: %s",
643 msdk_status_to_string (status));
646 thiz->has_vpp = TRUE;
649 thiz->param.AsyncDepth = thiz->async_depth;
650 if (thiz->use_video_memory)
651 thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
653 thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
655 thiz->param.mfx.TargetUsage = thiz->target_usage;
656 thiz->param.mfx.GopPicSize = thiz->gop_size;
657 thiz->param.mfx.GopRefDist = thiz->b_frames + 1;
658 thiz->param.mfx.IdrInterval = thiz->i_frames;
659 thiz->param.mfx.NumSlice = thiz->num_slices;
660 thiz->param.mfx.NumRefFrame = thiz->ref_frames;
661 thiz->param.mfx.EncodedOrder = 0; /* Take input frames in display order */
663 thiz->param.mfx.FrameInfo.Width = GST_ROUND_UP_16 (info->width);
664 thiz->param.mfx.FrameInfo.Height = GST_ROUND_UP_32 (info->height);
665 thiz->param.mfx.FrameInfo.CropW = info->width;
666 thiz->param.mfx.FrameInfo.CropH = info->height;
667 thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
668 thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
669 thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
670 thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
671 thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
672 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
674 switch (encoder_input_fmt) {
675 case GST_VIDEO_FORMAT_P010_10LE:
676 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P010;
677 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
678 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
679 thiz->param.mfx.FrameInfo.Shift = 1;
681 case GST_VIDEO_FORMAT_VUYA:
682 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_AYUV;
683 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
684 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
685 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
687 #if (MFX_VERSION >= 1027)
688 case GST_VIDEO_FORMAT_Y410:
689 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_Y410;
690 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
691 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
692 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
694 case GST_VIDEO_FORMAT_Y210:
695 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_Y210;
696 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
697 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
698 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
699 thiz->param.mfx.FrameInfo.Shift = 1;
702 case GST_VIDEO_FORMAT_BGRA:
703 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_RGB4;
704 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
705 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
706 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
708 case GST_VIDEO_FORMAT_BGR10A2_LE:
709 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_A2RGB10;
710 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
711 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
712 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
714 case GST_VIDEO_FORMAT_YUY2:
715 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_YUY2;
716 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
717 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
718 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
720 #if (MFX_VERSION >= 1031)
721 case GST_VIDEO_FORMAT_P012_LE:
722 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P016;
723 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
724 thiz->param.mfx.FrameInfo.BitDepthLuma = 12;
725 thiz->param.mfx.FrameInfo.BitDepthChroma = 12;
726 thiz->param.mfx.FrameInfo.Shift = 1;
730 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
731 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
732 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
735 /* work-around to avoid zero fps in msdk structure */
736 if (0 == thiz->param.mfx.FrameInfo.FrameRateExtN)
737 thiz->param.mfx.FrameInfo.FrameRateExtN = 30;
739 /* ensure bitrate control parameters */
740 ensure_bitrate_control (thiz);
742 /* allow subclass configure further */
743 if (klass->configure) {
744 if (!klass->configure (thiz))
748 /* If color properties are available from upstream, set it and pass to MediaSDK here.
749 * MJPEG and VP9 are excluded as MediaSDK does not support to handle video param
750 * extbuff with buffer id equals to MFX_EXTBUFF_VIDEO_SIGNAL_INFO.
752 if (thiz->param.mfx.CodecId != MFX_CODEC_JPEG &&
753 thiz->param.mfx.CodecId != MFX_CODEC_VP9 &&
754 (info->colorimetry.primaries || info->colorimetry.transfer
755 || info->colorimetry.matrix)) {
756 memset (&ext_vsi, 0, sizeof (ext_vsi));
757 ext_vsi.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
758 ext_vsi.Header.BufferSz = sizeof (ext_vsi);
759 ext_vsi.ColourDescriptionPresent = 1;
760 ext_vsi.ColourPrimaries =
761 gst_video_color_primaries_to_iso (info->colorimetry.primaries);
762 ext_vsi.TransferCharacteristics =
763 gst_video_transfer_function_to_iso (info->colorimetry.transfer);
764 ext_vsi.MatrixCoefficients =
765 gst_video_color_matrix_to_iso (info->colorimetry.matrix);
766 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) & ext_vsi);
769 if (thiz->num_extra_params) {
770 thiz->param.NumExtParam = thiz->num_extra_params;
771 thiz->param.ExtParam = thiz->extra_params;
774 /* validate parameters and allow MFX to make adjustments */
775 status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param);
776 if (status < MFX_ERR_NONE) {
777 GST_ERROR_OBJECT (thiz, "Video Encode Query failed (%s)",
778 msdk_status_to_string (status));
780 } else if (status > MFX_ERR_NONE) {
781 GST_WARNING_OBJECT (thiz, "Video Encode Query returned: %s",
782 msdk_status_to_string (status));
785 status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, request);
786 if (status < MFX_ERR_NONE) {
787 GST_ERROR_OBJECT (thiz, "Encode Query IO surfaces failed (%s)",
788 msdk_status_to_string (status));
790 } else if (status > MFX_ERR_NONE) {
791 GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
792 msdk_status_to_string (status));
795 request[0].NumFrameSuggested += thiz->num_extra_frames;
798 request[0].NumFrameSuggested += thiz->num_vpp_surfaces + 1 - 4;
800 if (thiz->use_video_memory) {
801 if (thiz->use_dmabuf && !thiz->has_vpp)
802 request[0].Type |= MFX_MEMTYPE_EXPORT_FRAME;
803 gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->alloc_resp);
806 /* Maximum of VPP output and encoder input, if using VPP */
808 request[0].NumFrameSuggested =
809 MAX (request[0].NumFrameSuggested, request[1].NumFrameSuggested);
810 if (request[0].NumFrameSuggested < thiz->param.AsyncDepth) {
811 GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
812 request[0].NumFrameMin, request[0].NumFrameSuggested,
813 thiz->param.AsyncDepth);
817 /* This is VPP output (if any) and encoder input */
818 thiz->num_surfaces = request[0].NumFrameSuggested;
820 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
821 request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
823 status = MFXVideoENCODE_Init (session, &thiz->param);
824 if (status < MFX_ERR_NONE) {
825 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
827 } else if (status > MFX_ERR_NONE) {
828 GST_WARNING_OBJECT (thiz, "Init returned: %s",
829 msdk_status_to_string (status));
832 status = MFXVideoENCODE_GetVideoParam (session, &thiz->param);
833 if (status < MFX_ERR_NONE) {
834 GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
835 msdk_status_to_string (status));
837 } else if (status > MFX_ERR_NONE) {
838 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
839 msdk_status_to_string (status));
842 thiz->num_tasks = thiz->param.AsyncDepth;
843 thiz->tasks = g_new0 (MsdkEncTask, thiz->num_tasks);
844 for (i = 0; i < thiz->num_tasks; i++) {
845 thiz->tasks[i].output_bitstream.Data = _aligned_alloc (32,
846 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
848 if (!thiz->tasks[i].output_bitstream.Data) {
849 GST_ERROR_OBJECT (thiz, "Memory allocation failed");
852 thiz->tasks[i].output_bitstream.MaxLength =
853 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
858 thiz->reconfig = FALSE;
859 thiz->initialized = TRUE;
861 GST_OBJECT_UNLOCK (thiz);
865 no_vpp_free_resource:
866 if (thiz->use_video_memory)
867 gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
869 GST_OBJECT_UNLOCK (thiz);
874 gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
879 if (!thiz->context || !thiz->initialized)
882 GST_DEBUG_OBJECT (thiz, "Closing encoder with context %" GST_PTR_FORMAT,
885 gst_clear_object (&thiz->msdk_pool);
886 gst_clear_object (&thiz->msdk_converted_pool);
888 if (thiz->use_video_memory)
889 gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
891 status = MFXVideoENCODE_Close (gst_msdk_context_get_session (thiz->context));
892 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
893 GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
894 msdk_status_to_string (status));
898 for (i = 0; i < thiz->num_tasks; i++) {
899 MsdkEncTask *task = &thiz->tasks[i];
900 if (task->output_bitstream.Data) {
901 _aligned_free (task->output_bitstream.Data);
905 g_free (thiz->tasks);
908 /* Close VPP before freeing the surfaces. They are shared between encoder
911 if (thiz->use_video_memory)
912 gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
914 status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
915 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
916 GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
917 msdk_status_to_string (status));
921 memset (&thiz->param, 0, sizeof (thiz->param));
922 thiz->num_extra_params = 0;
923 thiz->initialized = FALSE;
928 GstVideoCodecFrame *frame;
929 MsdkSurface *frame_surface;
930 MsdkSurface *converted_surface;
934 gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame,
939 fdata = g_slice_new (FrameData);
940 fdata->frame = gst_video_codec_frame_ref (frame);
942 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
948 gst_msdkenc_create_surface (mfxFrameSurface1 * surface, GstBuffer * buf)
950 MsdkSurface *msdk_surface;
951 msdk_surface = g_slice_new0 (MsdkSurface);
952 msdk_surface->surface = surface;
953 msdk_surface->buf = buf;
959 gst_msdkenc_free_surface (MsdkSurface * surface)
961 if (surface->buf_external) {
962 GstMsdkMemoryID *msdk_mid = NULL;
963 mfxFrameSurface1 *mfx_surface = NULL;
965 mfx_surface = surface->surface;
966 msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
967 *msdk_mid->surface = surface->cache_surface;
969 gst_buffer_unref (surface->buf_external);
973 gst_buffer_unref (surface->buf);
975 g_slice_free (MsdkSurface, surface);
979 gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata)
981 if (fdata->frame_surface)
982 gst_msdkenc_free_surface (fdata->frame_surface);
984 gst_msdkenc_free_surface (fdata->converted_surface);
986 gst_video_codec_frame_unref (fdata->frame);
987 g_slice_free (FrameData, fdata);
991 gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
995 for (l = thiz->pending_frames; l;) {
996 FrameData *fdata = l->data;
1001 if (fdata->frame != frame)
1004 gst_msdkenc_free_frame_data (thiz, fdata);
1006 thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l1);
1012 gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz)
1016 for (l = thiz->pending_frames; l; l = l->next) {
1017 FrameData *fdata = l->data;
1019 gst_msdkenc_free_frame_data (thiz, fdata);
1021 g_list_free (thiz->pending_frames);
1022 thiz->pending_frames = NULL;
1025 static MsdkEncTask *
1026 gst_msdkenc_get_free_task (GstMsdkEnc * thiz)
1028 MsdkEncTask *tasks = thiz->tasks;
1029 guint size = thiz->num_tasks;
1030 guint start = thiz->next_task;
1034 for (i = 0; i < size; i++) {
1035 guint t = (start + i) % size;
1036 if (tasks[t].sync_point == NULL)
1044 gst_msdkenc_reset_task (MsdkEncTask * task)
1046 task->output_bitstream.DataLength = 0;
1047 task->sync_point = NULL;
1050 static GstVideoCodecFrame *
1051 gst_msdkenc_find_best_frame (GstMsdkEnc * thiz, GList * frames,
1052 mfxBitstream * bitstream)
1055 GstVideoCodecFrame *ret = NULL;
1057 GstClockTimeDiff best_diff = GST_CLOCK_STIME_NONE;
1062 if (bitstream->TimeStamp == MFX_TIMESTAMP_UNKNOWN) {
1063 pts = GST_CLOCK_TIME_NONE;
1065 pts = gst_util_uint64_scale (bitstream->TimeStamp, GST_SECOND, 90000);
1068 for (iter = frames; iter; iter = g_list_next (iter)) {
1069 GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
1071 /* if we don't know the time stamp, find the first frame which
1072 * has unknown timestamp */
1073 if (!GST_CLOCK_TIME_IS_VALID (pts)) {
1074 if (!GST_CLOCK_TIME_IS_VALID (frame->pts)) {
1079 GstClockTimeDiff abs_diff = ABS (GST_CLOCK_DIFF (frame->pts, pts));
1080 if (abs_diff == 0) {
1085 if (!GST_CLOCK_STIME_IS_VALID (best_diff) || abs_diff < best_diff) {
1087 best_diff = abs_diff;
1093 gst_video_codec_frame_ref (ret);
1098 static GstFlowReturn
1099 gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task,
1102 GstVideoCodecFrame *frame;
1105 if (!task->sync_point)
1108 list = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (thiz));
1111 GST_ERROR_OBJECT (thiz, "failed to get list of frame");
1112 return GST_FLOW_ERROR;
1115 /* Wait for encoding operation to complete, the magic number 300000 below
1116 * is used in MSDK samples
1117 * #define MSDK_ENC_WAIT_INTERVAL 300000
1119 if (MFXVideoCORE_SyncOperation (gst_msdk_context_get_session (thiz->context),
1120 task->sync_point, 300000) != MFX_ERR_NONE)
1121 GST_WARNING_OBJECT (thiz, "failed to do sync operation");
1123 if (!discard && task->output_bitstream.DataLength) {
1124 GstBuffer *out_buf = NULL;
1126 task->output_bitstream.Data + task->output_bitstream.DataOffset;
1127 gsize size = task->output_bitstream.DataLength;
1129 frame = gst_msdkenc_find_best_frame (thiz, list, &task->output_bitstream);
1131 /* just pick the oldest one */
1132 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
1135 out_buf = gst_buffer_new_allocate (NULL, size, NULL);
1136 gst_buffer_fill (out_buf, 0, data, size);
1137 frame->output_buffer = out_buf;
1139 gst_util_uint64_scale (task->output_bitstream.TimeStamp, GST_SECOND,
1142 gst_util_uint64_scale (task->output_bitstream.DecodeTimeStamp,
1145 if ((task->output_bitstream.FrameType & MFX_FRAMETYPE_IDR) != 0 ||
1146 (task->output_bitstream.FrameType & MFX_FRAMETYPE_xIDR) != 0) {
1147 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1150 /* Mark task as available */
1151 gst_msdkenc_reset_task (task);
1153 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
1156 g_list_free_full (list, (GDestroyNotify) gst_video_codec_frame_unref);
1158 gst_video_codec_frame_unref (frame);
1159 gst_msdkenc_dequeue_frame (thiz, frame);
1161 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1164 static GstFlowReturn
1165 gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
1166 GstVideoCodecFrame * input_frame)
1172 if (G_UNLIKELY (thiz->context == NULL)) {
1173 gst_msdkenc_dequeue_frame (thiz, input_frame);
1174 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
1175 return GST_FLOW_NOT_NEGOTIATED;
1177 session = gst_msdk_context_get_session (thiz->context);
1179 task = gst_msdkenc_get_free_task (thiz);
1182 /* Force key-frame if needed */
1183 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame))
1184 thiz->enc_cntrl.FrameType =
1185 MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF;
1187 thiz->enc_cntrl.FrameType = MFX_FRAMETYPE_UNKNOWN;
1190 MFXVideoENCODE_EncodeFrameAsync (session, &thiz->enc_cntrl, surface,
1191 &task->output_bitstream, &task->sync_point);
1192 if (status != MFX_WRN_DEVICE_BUSY)
1194 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1198 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1199 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
1200 ("MSDK encode error (%s)", msdk_status_to_string (status)));
1201 gst_msdkenc_dequeue_frame (thiz, input_frame);
1202 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
1203 return GST_FLOW_ERROR;
1206 if (task->sync_point) {
1207 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
1208 } else if (status == MFX_ERR_MORE_DATA) {
1209 gst_msdkenc_dequeue_frame (thiz, input_frame);
1212 /* Ensure that next task is available */
1213 task = thiz->tasks + thiz->next_task;
1214 return gst_msdkenc_finish_frame (thiz, task, FALSE);
1218 gst_msdkenc_maximum_delayed_frames (GstMsdkEnc * thiz)
1220 return thiz->num_tasks;
1224 gst_msdkenc_set_latency (GstMsdkEnc * thiz)
1226 GstVideoInfo *info = &thiz->input_state->info;
1227 gint max_delayed_frames;
1228 GstClockTime latency;
1230 max_delayed_frames = gst_msdkenc_maximum_delayed_frames (thiz);
1233 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
1234 max_delayed_frames, info->fps_n);
1236 /* FIXME: Assume 25fps. This is better than reporting no latency at
1237 * all and then later failing in live pipelines
1239 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
1240 max_delayed_frames, 25);
1243 GST_INFO_OBJECT (thiz,
1244 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
1245 GST_TIME_ARGS (latency), max_delayed_frames);
1247 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (thiz), latency, latency);
1251 gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard)
1261 GST_DEBUG_OBJECT (thiz, "flush frames");
1263 session = gst_msdk_context_get_session (thiz->context);
1266 task = thiz->tasks + thiz->next_task;
1267 gst_msdkenc_finish_frame (thiz, task, FALSE);
1269 status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL,
1270 &task->output_bitstream, &task->sync_point);
1272 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1273 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
1274 ("MSDK encode error (%s)", msdk_status_to_string (status)));
1278 if (task->sync_point) {
1279 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
1280 } else if (status == MFX_ERR_MORE_DATA) {
1285 t = thiz->next_task;
1286 for (i = 0; i < thiz->num_tasks; i++) {
1287 gst_msdkenc_finish_frame (thiz, &thiz->tasks[t], discard);
1288 t = (t + 1) % thiz->num_tasks;
1293 gst_msdkenc_set_src_caps (GstMsdkEnc * thiz)
1295 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1296 GstCaps *outcaps = NULL;
1297 GstVideoCodecState *state;
1300 if (klass->set_src_caps)
1301 outcaps = klass->set_src_caps (thiz);
1306 state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (thiz),
1307 outcaps, thiz->input_state);
1308 GST_DEBUG_OBJECT (thiz, "output caps: %" GST_PTR_FORMAT, state->caps);
1310 gst_video_codec_state_unref (state);
1312 tags = gst_tag_list_new_empty ();
1313 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "msdkenc",
1314 GST_TAG_MAXIMUM_BITRATE, thiz->bitrate * 1024,
1315 GST_TAG_NOMINAL_BITRATE, thiz->bitrate * 1024, NULL);
1316 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (thiz), tags,
1317 GST_TAG_MERGE_REPLACE);
1318 gst_tag_list_unref (tags);
1323 static GstBufferPool *
1324 gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps,
1325 guint num_buffers, gboolean set_align)
1327 GstBufferPool *pool = NULL;
1328 GstStructure *config;
1329 GstAllocator *allocator = NULL;
1331 GstVideoAlignment align;
1332 GstAllocationParams params = { 0, 31, 0, 0, };
1333 mfxFrameAllocResponse *alloc_resp = NULL;
1336 alloc_resp = set_align ? &thiz->vpp_alloc_resp : &thiz->alloc_resp;
1338 alloc_resp = &thiz->alloc_resp;
1340 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
1344 if (!gst_video_info_from_caps (&info, caps)) {
1345 GST_INFO_OBJECT (thiz, "failed to get video info");
1349 gst_msdk_set_video_alignment (&info, 0, 0, &align);
1350 gst_video_info_align (&info, &align);
1352 if (thiz->use_dmabuf)
1354 gst_msdk_dmabuf_allocator_new (thiz->context, &info, alloc_resp);
1355 else if (thiz->use_video_memory)
1356 allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
1358 allocator = gst_msdk_system_allocator_new (&info);
1361 goto error_no_allocator;
1363 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1364 gst_buffer_pool_config_set_params (config, caps, info.size, num_buffers, 0);
1365 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1366 gst_buffer_pool_config_add_option (config,
1367 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1369 if (thiz->use_video_memory) {
1370 gst_buffer_pool_config_add_option (config,
1371 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1372 if (thiz->use_dmabuf)
1373 gst_buffer_pool_config_add_option (config,
1374 GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1377 gst_buffer_pool_config_set_video_alignment (config, &align);
1378 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
1379 gst_object_unref (allocator);
1381 if (!gst_buffer_pool_set_config (pool, config))
1382 goto error_pool_config;
1385 thiz->aligned_info = info;
1391 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1396 GST_INFO_OBJECT (thiz, "failed to create allocator");
1397 gst_object_unref (pool);
1402 GST_INFO_OBJECT (thiz, "failed to set config");
1403 gst_object_unref (pool);
1404 gst_object_unref (allocator);
1409 /* Fixme: Common routine used by all msdk elements, should be
1410 * moved to a common util file */
1412 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
1416 for (i = 0; i < gst_caps_get_size (caps); i++) {
1417 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
1418 /* Skip ANY features, we need an exact match for correct evaluation */
1419 if (gst_caps_features_is_any (features))
1421 if (gst_caps_features_contains (features, feature))
1428 sinkpad_can_dmabuf (GstMsdkEnc * thiz)
1430 gboolean ret = FALSE;
1431 GstCaps *caps, *allowed_caps;
1434 sinkpad = GST_VIDEO_ENCODER_SINK_PAD (thiz);
1435 caps = gst_pad_get_pad_template_caps (sinkpad);
1437 allowed_caps = gst_pad_peer_query_caps (sinkpad, caps);
1440 if (gst_caps_is_any (allowed_caps) || gst_caps_is_empty (allowed_caps)
1441 || allowed_caps == caps)
1444 if (_gst_caps_has_feature (allowed_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
1449 gst_caps_unref (caps);
1451 gst_caps_unref (allowed_caps);
1456 sinkpad_is_va (GstMsdkEnc * thiz)
1458 GstCapsFeatures *const features =
1459 gst_caps_get_features (thiz->input_state->caps, 0);
1460 if (gst_caps_features_contains (features, "memory:VAMemory"))
1467 gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
1469 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1470 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1473 if (thiz->input_state) {
1474 if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
1475 GST_INFO_OBJECT (thiz, "Re-init the encoder as info changed");
1476 gst_msdkenc_flush_frames (thiz, FALSE);
1477 gst_msdkenc_close_encoder (thiz);
1479 gst_video_codec_state_unref (thiz->input_state);
1481 thiz->input_state = gst_video_codec_state_ref (state);
1484 /* TODO: Currently d3d allocator is not implemented.
1485 * So encoder uses system memory by default on Windows.
1488 thiz->use_video_memory = TRUE;
1489 if (sinkpad_is_va (thiz))
1490 thiz->use_va = TRUE;
1492 thiz->use_video_memory = FALSE;
1495 GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory",
1496 thiz->use_video_memory ? "video" : "system");
1498 if (klass->set_format) {
1499 if (!klass->set_format (thiz))
1503 /* If upstream supports DMABufCapsfeatures, then we request for the dmabuf
1504 * based pipeline usage. Ideally we should have dmabuf support even with
1505 * raw-caps negotiation, but we don't have dmabuf-import support in msdk
1507 /* If VA is set, we do not fallback to DMA. */
1508 if (!thiz->use_va && sinkpad_can_dmabuf (thiz)) {
1509 thiz->input_state->caps = gst_caps_make_writable (thiz->input_state->caps);
1510 gst_caps_set_features (thiz->input_state->caps, 0,
1511 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1512 thiz->use_dmabuf = TRUE;
1515 if (!gst_msdkenc_init_encoder (thiz))
1518 if (!gst_msdkenc_set_src_caps (thiz)) {
1519 gst_msdkenc_close_encoder (thiz);
1523 if (!thiz->msdk_pool) {
1524 guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1526 gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps,
1530 gst_msdkenc_set_latency (thiz);
1532 /* Create another bufferpool if VPP requires */
1533 if (thiz->has_vpp) {
1534 GstVideoInfo *info = &thiz->input_state->info;
1535 GstVideoInfo out_info;
1536 GstVideoFormat out_fmt;
1538 GstBufferPool *pool = NULL;
1540 gst_video_info_init (&out_info);
1542 gst_msdk_get_video_format_from_mfx_fourcc (thiz->vpp_param.vpp.
1544 gst_video_info_set_format (&out_info, out_fmt, info->width, info->height);
1545 caps = gst_video_info_to_caps (&out_info);
1547 /* If there's an existing pool try to reuse it when is compatible */
1548 if (thiz->msdk_converted_pool) {
1549 GstStructure *config;
1551 gboolean is_pool_compatible = FALSE;
1553 config = gst_buffer_pool_get_config (thiz->msdk_converted_pool);
1554 gst_buffer_pool_config_get_params (config, &pool_caps, NULL, NULL, NULL);
1555 if (caps && pool_caps)
1556 is_pool_compatible = gst_caps_is_equal (caps, pool_caps);
1557 gst_structure_free (config);
1559 /* If caps are the same then we are done */
1560 if (is_pool_compatible) {
1561 gst_caps_unref (caps);
1564 /* Release current pool because we are going to create a new one */
1565 gst_clear_object (&thiz->msdk_converted_pool);
1568 /* Otherwise create a new pool */
1570 gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE);
1572 thiz->msdk_converted_pool = pool;
1573 gst_caps_unref (caps);
1580 static MsdkSurface *
1581 gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool,
1582 GstBufferPoolAcquireParams * params)
1584 GstBuffer *new_buffer;
1585 mfxFrameSurface1 *new_surface;
1586 MsdkSurface *msdk_surface;
1588 if (!gst_buffer_pool_is_active (pool) &&
1589 !gst_buffer_pool_set_active (pool, TRUE)) {
1590 GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
1594 if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
1595 GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
1599 if (gst_msdk_is_msdk_buffer (new_buffer))
1600 new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
1602 GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
1606 msdk_surface = gst_msdkenc_create_surface (new_surface, new_buffer);
1608 return msdk_surface;
1613 import_dmabuf_to_msdk_surface (GstMsdkEnc * thiz, GstBuffer * buf,
1614 MsdkSurface * msdk_surface)
1616 GstMemory *mem = NULL;
1618 GstVideoMeta *vmeta;
1619 GstMsdkMemoryID *msdk_mid = NULL;
1620 mfxFrameSurface1 *mfx_surface = NULL;
1622 mem = gst_buffer_peek_memory (buf, 0);
1623 fd = gst_dmabuf_memory_get_fd (mem);
1627 vinfo = thiz->input_state->info;
1628 /* Update offset/stride/size if there is VideoMeta attached to
1630 vmeta = gst_buffer_get_video_meta (buf);
1632 if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
1633 GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
1634 GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
1635 GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
1636 GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
1637 "the negotiated width/height/format");
1640 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
1641 GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
1642 GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
1644 GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
1647 /* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions.
1648 * Current media-driver and GMMLib will fail due to strict memory size restrictions.
1649 * Ideally, media-driver should accept what ever memory coming from other drivers
1650 * in case of dmabuf-import and this is how the intel-vaapi-driver works.
1651 * For now, in order to avoid any crash we check the buffer size and fallback
1652 * to copy frame method.
1654 * See this: https://github.com/intel/media-driver/issues/169
1656 if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1659 mfx_surface = msdk_surface->surface;
1660 msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1662 /* release the internal memory storage of associated mfxSurface */
1663 gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);
1665 /* export dmabuf to vasurface */
1666 if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
1674 import_va_surface_to_msdk (GstMsdkEnc * thiz, GstBuffer * buf,
1675 MsdkSurface * msdk_surface)
1678 GstVideoMeta *vmeta;
1679 GstMsdkMemoryID *msdk_mid = NULL;
1680 mfxFrameSurface1 *mfx_surface = NULL;
1681 VASurfaceID surface;
1684 surface = gst_msdk_va_peek_buffer_surface (buf);
1685 if (surface == VA_INVALID_SURFACE)
1688 vinfo = thiz->input_state->info;
1689 /* Update offset/stride/size if there is VideoMeta attached to
1691 vmeta = gst_buffer_get_video_meta (buf);
1693 if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
1694 GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
1695 GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
1696 GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
1697 GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
1698 "the negotiated width/height/format");
1701 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
1702 GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
1703 GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
1705 GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
1708 if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1711 msdk_surface->buf_external = gst_buffer_ref (buf);
1713 mfx_surface = msdk_surface->surface;
1714 msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1716 msdk_surface->cache_surface = *msdk_mid->surface;
1717 *msdk_mid->surface = surface;
1722 static MsdkSurface *
1723 gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
1724 GstVideoCodecFrame * frame)
1726 GstVideoFrame src_frame, out_frame;
1727 MsdkSurface *msdk_surface;
1730 GstMemory *mem = NULL;
1733 inbuf = frame->input_buffer;
1734 if (gst_msdk_is_msdk_buffer (inbuf)) {
1735 msdk_surface = g_slice_new0 (MsdkSurface);
1736 msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
1737 return msdk_surface;
1740 /* If upstream hasn't accpeted the proposed msdk bufferpool,
1741 * just copy frame (if not dmabuf backed )to msdk buffer and take a surface from it.
1743 if (!(msdk_surface =
1744 gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL)))
1748 /************** VA import *****************/
1750 if (import_va_surface_to_msdk (thiz, inbuf, msdk_surface)) {
1751 return msdk_surface;
1755 /************ dmabuf-import ************* */
1756 /* if upstream provided a dmabuf backed memory, but not an msdk
1757 * buffer, we could try to export the dmabuf to underlined vasurface */
1758 mem = gst_buffer_peek_memory (inbuf, 0);
1759 if (gst_is_dmabuf_memory (mem)) {
1760 if (import_dmabuf_to_msdk_surface (thiz, inbuf, msdk_surface))
1761 return msdk_surface;
1763 GST_INFO_OBJECT (thiz, "Upstream dmabuf-backed memory is not imported"
1764 "to the msdk surface, fall back to the copy input frame method");
1768 if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, inbuf,
1770 GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
1774 if (!gst_video_frame_map (&out_frame, &thiz->aligned_info, msdk_surface->buf,
1776 GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
1777 gst_video_frame_unmap (&src_frame);
1781 if (!gst_video_frame_copy (&out_frame, &src_frame)) {
1782 GST_ERROR_OBJECT (thiz, "failed to copy frame");
1783 gst_video_frame_unmap (&out_frame);
1784 gst_video_frame_unmap (&src_frame);
1788 gst_video_frame_unmap (&out_frame);
1789 gst_video_frame_unmap (&src_frame);
1791 gst_buffer_replace (&frame->input_buffer, msdk_surface->buf);
1792 gst_buffer_unref (msdk_surface->buf);
1793 msdk_surface->buf = NULL;
1795 return msdk_surface;
1799 if (msdk_surface->buf)
1800 gst_buffer_unref (msdk_surface->buf);
1801 g_slice_free (MsdkSurface, msdk_surface);
1806 static GstFlowReturn
1807 gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1809 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1810 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1811 GstVideoInfo *info = &thiz->input_state->info;
1813 MsdkSurface *surface;
1815 if (thiz->reconfig || klass->need_reconfig (thiz, frame)) {
1816 gst_msdkenc_flush_frames (thiz, FALSE);
1817 gst_msdkenc_close_encoder (thiz);
1819 klass->set_extra_params (thiz, frame);
1821 // This will reinitialized the encoder but keep same input format.
1822 gst_msdkenc_set_format (encoder, NULL);
1825 if (G_UNLIKELY (thiz->context == NULL))
1828 if (thiz->has_vpp) {
1829 MsdkSurface *vpp_surface;
1830 GstVideoFrame vframe;
1832 mfxSyncPoint vpp_sync_point = NULL;
1835 vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1837 goto invalid_surface;
1839 gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_converted_pool,
1842 goto invalid_surface;
1844 if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
1847 if (frame->pts != GST_CLOCK_TIME_NONE) {
1848 vpp_surface->surface->Data.TimeStamp =
1849 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1850 surface->surface->Data.TimeStamp =
1851 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1853 vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1854 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1857 session = gst_msdk_context_get_session (thiz->context);
1860 MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface,
1861 surface->surface, NULL, &vpp_sync_point);
1862 if (status != MFX_WRN_DEVICE_BUSY)
1864 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1868 gst_video_frame_unmap (&vframe);
1870 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1871 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Converting frame failed."),
1872 ("MSDK VPP error (%s)", msdk_status_to_string (status)));
1873 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1874 return GST_FLOW_ERROR;
1877 fdata = g_slice_new0 (FrameData);
1878 fdata->frame = gst_video_codec_frame_ref (frame);
1879 fdata->frame_surface = vpp_surface;
1880 fdata->converted_surface = surface;
1882 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
1884 surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1886 goto invalid_surface;
1888 fdata = gst_msdkenc_queue_frame (thiz, frame, info);
1892 fdata->frame_surface = surface;
1894 if (frame->pts != GST_CLOCK_TIME_NONE) {
1895 surface->surface->Data.TimeStamp =
1896 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1898 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1902 return gst_msdkenc_encode_frame (thiz, surface->surface, frame);
1907 GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1908 return GST_FLOW_NOT_NEGOTIATED;
1912 GST_ERROR_OBJECT (encoder, "Surface pool is full");
1913 return GST_FLOW_ERROR;
1917 GST_WARNING_OBJECT (encoder, "Failed to map frame");
1923 gst_msdkenc_context_prepare (GstMsdkEnc * thiz)
1925 /* Try to find an existing context from the pipeline. This may (indirectly)
1926 * invoke gst_msdkenc_set_context, which will set thiz->context. */
1927 if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
1930 if (thiz->context == thiz->old_context) {
1931 GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
1932 ", reusing as-is", thiz->context);
1936 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
1939 /* Check GST_MSDK_JOB_VPP and GST_MSDK_JOB_ENCODER together to avoid sharing context
1940 * between VPP and ENCODER
1942 * gst-launch-1.0 videotestsrc ! video/x-raw,format=I420 ! msdkh264enc ! \
1943 * msdkh264dec ! msdkvpp ! video/x-raw,format=YUY2 ! fakesink
1945 if (!(gst_msdk_context_get_job_type (thiz->context) & (GST_MSDK_JOB_VPP |
1946 GST_MSDK_JOB_ENCODER))) {
1947 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_ENCODER);
1951 /* Found an existing context that's already being used as an encoder, clone
1952 * the MFX session inside it to create a new one */
1954 GstMsdkContext *parent_context, *msdk_context;
1956 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
1957 "joined session", thiz->context);
1958 parent_context = thiz->context;
1959 msdk_context = gst_msdk_context_new_with_parent (parent_context);
1961 if (!msdk_context) {
1962 GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
1963 "as %" GST_PTR_FORMAT, parent_context);
1967 thiz->context = msdk_context;
1968 gst_object_unref (parent_context);
1975 gst_msdkenc_start (GstVideoEncoder * encoder)
1977 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1979 if (!gst_msdkenc_context_prepare (thiz)) {
1980 if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
1981 thiz->hardware, GST_MSDK_JOB_ENCODER, &thiz->context))
1983 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1987 /* Save the current context in a separate field so that we know whether it
1988 * has changed between calls to _start() */
1989 gst_object_replace ((GstObject **) & thiz->old_context,
1990 (GstObject *) thiz->context);
1992 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
1994 /* Set the minimum pts to some huge value (1000 hours). This keeps
1995 the dts at the start of the stream from needing to be
1997 gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
2003 gst_msdkenc_stop (GstVideoEncoder * encoder)
2005 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2007 gst_msdkenc_flush_frames (thiz, TRUE);
2008 gst_msdkenc_close_encoder (thiz);
2009 gst_msdkenc_dequeue_all_frames (thiz);
2011 if (thiz->input_state)
2012 gst_video_codec_state_unref (thiz->input_state);
2013 thiz->input_state = NULL;
2015 gst_clear_object (&thiz->context);
2021 gst_msdkenc_flush (GstVideoEncoder * encoder)
2023 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2025 GST_DEBUG_OBJECT (encoder, "flush and close encoder");
2027 gst_msdkenc_flush_frames (thiz, TRUE);
2028 gst_msdkenc_close_encoder (thiz);
2029 gst_msdkenc_dequeue_all_frames (thiz);
2031 gst_msdkenc_init_encoder (thiz);
2036 static GstFlowReturn
2037 gst_msdkenc_finish (GstVideoEncoder * encoder)
2039 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2041 gst_msdkenc_flush_frames (thiz, FALSE);
2048 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
2050 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2052 GstBufferPool *pool = NULL;
2053 GstAllocator *allocator = NULL;
2057 if (!thiz->input_state)
2060 gst_query_parse_allocation (query, &caps, NULL);
2063 GST_INFO_OBJECT (encoder, "failed to get caps");
2067 if (!gst_video_info_from_caps (&info, caps)) {
2068 GST_INFO_OBJECT (encoder, "failed to get video info");
2072 /* if upstream allocation query supports dmabuf-capsfeatures,
2073 * we do allocate dmabuf backed memory */
2074 if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
2075 GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
2076 thiz->use_dmabuf = TRUE;
2079 num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
2080 pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, TRUE);
2082 gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info),
2084 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2087 GstStructure *config;
2088 GstAllocationParams params = { 0, 31, 0, 0, };
2090 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
2092 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
2093 gst_query_add_allocation_param (query, allocator, ¶ms);
2094 gst_structure_free (config);
2097 gst_object_unref (pool);
2099 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
2104 gst_msdkenc_query (GstVideoEncoder * encoder, GstQuery * query,
2105 GstPadDirection dir)
2107 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2108 gboolean ret = FALSE;
2110 switch (GST_QUERY_TYPE (query)) {
2111 case GST_QUERY_CONTEXT:{
2112 GstMsdkContext *msdk_context = NULL;
2114 gst_object_replace ((GstObject **) & msdk_context,
2115 (GstObject *) thiz->context);
2116 ret = gst_msdk_handle_context_query (GST_ELEMENT_CAST (encoder),
2117 query, msdk_context);
2118 gst_clear_object (&msdk_context);
2122 if (dir == GST_PAD_SRC) {
2124 GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
2127 GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
2136 gst_msdkenc_src_query (GstVideoEncoder * encoder, GstQuery * query)
2138 return gst_msdkenc_query (encoder, query, GST_PAD_SRC);
2142 gst_msdkenc_sink_query (GstVideoEncoder * encoder, GstQuery * query)
2144 return gst_msdkenc_query (encoder, query, GST_PAD_SINK);
2148 gst_msdkenc_dispose (GObject * object)
2150 GstMsdkEnc *thiz = GST_MSDKENC (object);
2152 if (thiz->input_state)
2153 gst_video_codec_state_unref (thiz->input_state);
2154 thiz->input_state = NULL;
2156 gst_clear_object (&thiz->msdk_pool);
2157 gst_clear_object (&thiz->msdk_converted_pool);
2158 gst_clear_object (&thiz->old_context);
2160 gst_clear_structure (&thiz->ext_coding_props);
2162 G_OBJECT_CLASS (parent_class)->dispose (object);
2166 gst_msdkenc_need_conversion (GstMsdkEnc * encoder, GstVideoInfo * info,
2167 GstVideoFormat * out_format)
2169 switch (GST_VIDEO_INFO_FORMAT (info)) {
2170 case GST_VIDEO_FORMAT_NV12:
2171 case GST_VIDEO_FORMAT_P010_10LE:
2172 case GST_VIDEO_FORMAT_VUYA:
2173 #if (MFX_VERSION >= 1027)
2174 case GST_VIDEO_FORMAT_Y410:
2175 case GST_VIDEO_FORMAT_Y210:
2180 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10)
2181 *out_format = GST_VIDEO_FORMAT_P010_10LE;
2183 *out_format = GST_VIDEO_FORMAT_NV12;
2189 gst_msdkenc_need_reconfig (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
2195 gst_msdkenc_set_extra_params (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
2201 gst_msdkenc_class_init (GstMsdkEncClass * klass)
2203 GObjectClass *gobject_class;
2204 GstElementClass *element_class;
2205 GstVideoEncoderClass *gstencoder_class;
2207 gobject_class = G_OBJECT_CLASS (klass);
2208 element_class = GST_ELEMENT_CLASS (klass);
2209 gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
2211 klass->need_conversion = gst_msdkenc_need_conversion;
2212 klass->need_reconfig = gst_msdkenc_need_reconfig;
2213 klass->set_extra_params = gst_msdkenc_set_extra_params;
2217 gobject_class->dispose = gst_msdkenc_dispose;
2219 element_class->set_context = gst_msdkenc_set_context;
2221 gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkenc_set_format);
2222 gstencoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkenc_handle_frame);
2223 gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkenc_start);
2224 gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkenc_stop);
2225 gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkenc_flush);
2226 gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkenc_finish);
2227 gstencoder_class->propose_allocation =
2228 GST_DEBUG_FUNCPTR (gst_msdkenc_propose_allocation);
2229 gstencoder_class->src_query = GST_DEBUG_FUNCPTR (gst_msdkenc_src_query);
2230 gstencoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_msdkenc_sink_query);
2232 gst_element_class_add_static_pad_template (element_class, &sink_factory);
2236 gst_msdkenc_init (GstMsdkEnc * thiz)
2238 thiz->hardware = PROP_HARDWARE_DEFAULT;
2239 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
2240 thiz->target_usage = PROP_TARGET_USAGE_DEFAULT;
2241 thiz->rate_control = PROP_RATE_CONTROL_DEFAULT;
2242 thiz->bitrate = PROP_BITRATE_DEFAULT;
2243 thiz->max_frame_size = PROP_MAX_FRAME_SIZE_DEFAULT;
2244 thiz->max_vbv_bitrate = PROP_MAX_VBV_BITRATE_DEFAULT;
2245 thiz->accuracy = PROP_AVBR_ACCURACY_DEFAULT;
2246 thiz->convergence = PROP_AVBR_ACCURACY_DEFAULT;
2247 thiz->lookahead_depth = PROP_RC_LOOKAHEAD_DEPTH_DEFAULT;
2248 thiz->qpi = PROP_QPI_DEFAULT;
2249 thiz->qpp = PROP_QPP_DEFAULT;
2250 thiz->qpb = PROP_QPB_DEFAULT;
2251 thiz->gop_size = PROP_GOP_SIZE_DEFAULT;
2252 thiz->ref_frames = PROP_REF_FRAMES_DEFAULT;
2253 thiz->i_frames = PROP_I_FRAMES_DEFAULT;
2254 thiz->b_frames = PROP_B_FRAMES_DEFAULT;
2255 thiz->num_slices = PROP_NUM_SLICES_DEFAULT;
2256 thiz->mbbrc = PROP_MBBRC_DEFAULT;
2257 thiz->adaptive_i = PROP_ADAPTIVE_I_DEFAULT;
2258 thiz->adaptive_b = PROP_ADAPTIVE_B_DEFAULT;
2260 thiz->ext_coding_props = gst_structure_new (EC_PROPS_STRUCT_NAME,
2261 EC_PROPS_EXTBRC, G_TYPE_STRING, "off", NULL);
2264 /* gst_msdkenc_set_common_property:
2266 * This is a helper function to set the common property
2267 * of base encoder from subclass implementation.
2270 gst_msdkenc_set_common_property (GObject * object, guint prop_id,
2271 const GValue * value, GParamSpec * pspec)
2273 GstMsdkEnc *thiz = GST_MSDKENC (object);
2275 gboolean ret = TRUE;
2277 GST_OBJECT_LOCK (thiz);
2279 state = GST_STATE (thiz);
2280 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
2281 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) {
2287 case GST_MSDKENC_PROP_HARDWARE:
2288 thiz->hardware = g_value_get_boolean (value);
2290 case GST_MSDKENC_PROP_ASYNC_DEPTH:
2291 thiz->async_depth = g_value_get_uint (value);
2293 case GST_MSDKENC_PROP_TARGET_USAGE:
2294 thiz->target_usage = g_value_get_uint (value);
2296 case GST_MSDKENC_PROP_RATE_CONTROL:
2297 thiz->rate_control = g_value_get_enum (value);
2299 case GST_MSDKENC_PROP_BITRATE:
2301 guint bitrate = g_value_get_uint (value);
2302 /* Ensure that bitrate changed before triggering a reconfig */
2303 if (bitrate != thiz->bitrate) {
2304 thiz->bitrate = bitrate;
2305 thiz->reconfig = TRUE;
2306 GST_DEBUG_OBJECT (thiz, "changed bitrate to %u", bitrate);
2310 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
2311 thiz->max_frame_size = g_value_get_uint (value);
2313 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
2314 thiz->max_vbv_bitrate = g_value_get_uint (value);
2316 case GST_MSDKENC_PROP_AVBR_ACCURACY:
2317 thiz->accuracy = g_value_get_uint (value);
2319 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
2320 thiz->convergence = g_value_get_uint (value);
2322 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
2323 thiz->lookahead_depth = g_value_get_uint (value);
2325 case GST_MSDKENC_PROP_QPI:
2326 thiz->qpi = g_value_get_uint (value);
2328 case GST_MSDKENC_PROP_QPP:
2329 thiz->qpp = g_value_get_uint (value);
2331 case GST_MSDKENC_PROP_QPB:
2332 thiz->qpb = g_value_get_uint (value);
2334 case GST_MSDKENC_PROP_GOP_SIZE:
2335 thiz->gop_size = g_value_get_uint (value);
2337 case GST_MSDKENC_PROP_REF_FRAMES:
2338 thiz->ref_frames = g_value_get_uint (value);
2340 case GST_MSDKENC_PROP_I_FRAMES:
2341 thiz->i_frames = g_value_get_uint (value);
2343 case GST_MSDKENC_PROP_B_FRAMES:
2344 thiz->b_frames = g_value_get_uint (value);
2346 case GST_MSDKENC_PROP_NUM_SLICES:
2347 thiz->num_slices = g_value_get_uint (value);
2349 case GST_MSDKENC_PROP_MBBRC:
2350 thiz->mbbrc = g_value_get_enum (value);
2352 case GST_MSDKENC_PROP_ADAPTIVE_I:
2353 thiz->adaptive_i = g_value_get_enum (value);
2355 case GST_MSDKENC_PROP_ADAPTIVE_B:
2356 thiz->adaptive_b = g_value_get_enum (value);
2358 case GST_MSDKENC_PROP_EXT_CODING_PROPS:
2360 const GstStructure *s = gst_value_get_structure (value);
2361 const gchar *name = gst_structure_get_name (s);
2362 gst_structure_set_name (thiz->ext_coding_props, name);
2363 if (!structure_transform (s, thiz->ext_coding_props)) {
2364 GST_ERROR_OBJECT (thiz, "failed to transform structure");
2372 GST_OBJECT_UNLOCK (thiz);
2378 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
2379 GST_OBJECT_UNLOCK (thiz);
2384 /* gst_msdkenc_get_common_property:
2386 * This is a helper function to get the common property
2387 * of base encoder from subclass implementation.
2390 gst_msdkenc_get_common_property (GObject * object, guint prop_id,
2391 GValue * value, GParamSpec * pspec)
2393 GstMsdkEnc *thiz = GST_MSDKENC (object);
2394 gboolean ret = TRUE;
2396 GST_OBJECT_LOCK (thiz);
2398 case GST_MSDKENC_PROP_HARDWARE:
2399 g_value_set_boolean (value, thiz->hardware);
2401 case GST_MSDKENC_PROP_ASYNC_DEPTH:
2402 g_value_set_uint (value, thiz->async_depth);
2404 case GST_MSDKENC_PROP_TARGET_USAGE:
2405 g_value_set_uint (value, thiz->target_usage);
2407 case GST_MSDKENC_PROP_RATE_CONTROL:
2408 g_value_set_enum (value, thiz->rate_control);
2410 case GST_MSDKENC_PROP_BITRATE:
2411 g_value_set_uint (value, thiz->bitrate);
2413 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
2414 g_value_set_uint (value, thiz->max_frame_size);
2416 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
2417 g_value_set_uint (value, thiz->max_vbv_bitrate);
2419 case GST_MSDKENC_PROP_AVBR_ACCURACY:
2420 g_value_set_uint (value, thiz->accuracy);
2422 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
2423 g_value_set_uint (value, thiz->convergence);
2425 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
2426 g_value_set_uint (value, thiz->lookahead_depth);
2428 case GST_MSDKENC_PROP_QPI:
2429 g_value_set_uint (value, thiz->qpi);
2431 case GST_MSDKENC_PROP_QPP:
2432 g_value_set_uint (value, thiz->qpp);
2434 case GST_MSDKENC_PROP_QPB:
2435 g_value_set_uint (value, thiz->qpb);
2437 case GST_MSDKENC_PROP_GOP_SIZE:
2438 g_value_set_uint (value, thiz->gop_size);
2440 case GST_MSDKENC_PROP_REF_FRAMES:
2441 g_value_set_uint (value, thiz->ref_frames);
2443 case GST_MSDKENC_PROP_I_FRAMES:
2444 g_value_set_uint (value, thiz->i_frames);
2446 case GST_MSDKENC_PROP_B_FRAMES:
2447 g_value_set_uint (value, thiz->b_frames);
2449 case GST_MSDKENC_PROP_NUM_SLICES:
2450 g_value_set_uint (value, thiz->num_slices);
2452 case GST_MSDKENC_PROP_MBBRC:
2453 g_value_set_enum (value, thiz->mbbrc);
2455 case GST_MSDKENC_PROP_ADAPTIVE_I:
2456 g_value_set_enum (value, thiz->adaptive_i);
2458 case GST_MSDKENC_PROP_ADAPTIVE_B:
2459 g_value_set_enum (value, thiz->adaptive_b);
2461 case GST_MSDKENC_PROP_EXT_CODING_PROPS:
2462 gst_value_set_structure (value, thiz->ext_coding_props);
2468 GST_OBJECT_UNLOCK (thiz);
2472 /* gst_msdkenc_install_common_properties:
2473 * @thiz: a #GstMsdkEnc
2475 * This is a helper function to install common properties
2476 * of base encoder from subclass implementation.
2477 * Encoders like jpeg do't require all the common properties
2478 * and they can avoid installing it into base gobject.
2481 gst_msdkenc_install_common_properties (GstMsdkEncClass * klass)
2483 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2484 GParamSpec *obj_properties[GST_MSDKENC_PROP_MAX] = { NULL, };
2485 guint qp_range_max = klass->qp_max;
2486 guint qp_range_min = klass->qp_min;
2488 obj_properties[GST_MSDKENC_PROP_HARDWARE] =
2489 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware encoders",
2490 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2492 obj_properties[GST_MSDKENC_PROP_ASYNC_DEPTH] =
2493 g_param_spec_uint ("async-depth", "Async Depth",
2494 "Depth of asynchronous pipeline",
2495 1, 20, PROP_ASYNC_DEPTH_DEFAULT,
2496 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2498 obj_properties[GST_MSDKENC_PROP_TARGET_USAGE] =
2499 g_param_spec_uint ("target-usage", "Target Usage",
2500 "1: Best quality, 4: Balanced, 7: Best speed",
2501 1, 7, PROP_TARGET_USAGE_DEFAULT,
2502 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2504 obj_properties[GST_MSDKENC_PROP_RATE_CONTROL] =
2505 g_param_spec_enum ("rate-control", "Rate Control",
2506 "Rate control method", gst_msdkenc_rate_control_get_type (),
2507 PROP_RATE_CONTROL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2509 obj_properties[GST_MSDKENC_PROP_BITRATE] =
2510 g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
2511 2000 * 1024, PROP_BITRATE_DEFAULT,
2512 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING);
2514 obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE] =
2515 g_param_spec_uint ("max-frame-size", "Max Frame Size",
2516 "Maximum possible size (in kbyte) of any compressed frames (0: auto-calculate)",
2517 0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_DEFAULT,
2518 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2520 /* Set the same upper bound with bitrate */
2521 obj_properties[GST_MSDKENC_PROP_MAX_VBV_BITRATE] =
2522 g_param_spec_uint ("max-vbv-bitrate", "Max VBV Bitrate",
2523 "Maximum bitrate(kbit/sec) at which data enters Video Buffering Verifier (0: auto-calculate)",
2524 0, 2000 * 1024, PROP_MAX_VBV_BITRATE_DEFAULT,
2525 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2527 obj_properties[GST_MSDKENC_PROP_AVBR_ACCURACY] =
2528 g_param_spec_uint ("accuracy", "Accuracy", "The AVBR Accuracy in "
2529 "the unit of tenth of percent", 0, G_MAXUINT16,
2530 PROP_AVBR_ACCURACY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2532 obj_properties[GST_MSDKENC_PROP_AVBR_CONVERGENCE] =
2533 g_param_spec_uint ("convergence", "Convergence",
2534 "The AVBR Convergence in the unit of 100 frames", 0, G_MAXUINT16,
2535 PROP_AVBR_CONVERGENCE_DEFAULT,
2536 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2538 obj_properties[GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH] =
2539 g_param_spec_uint ("rc-lookahead", "Look-ahead depth",
2540 "Number of frames to look ahead for Rate control", 10, 100,
2541 PROP_RC_LOOKAHEAD_DEPTH_DEFAULT,
2542 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2544 obj_properties[GST_MSDKENC_PROP_QPI] =
2545 g_param_spec_uint ("qpi", "QPI",
2546 "Constant quantizer for I frames (0 unlimited). Also used as "
2547 "ICQQuality or QVBRQuality for different RateControl methods",
2548 qp_range_min, qp_range_max, PROP_QPI_DEFAULT,
2549 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2551 obj_properties[GST_MSDKENC_PROP_QPP] =
2552 g_param_spec_uint ("qpp", "QPP",
2553 "Constant quantizer for P frames (0 unlimited)",
2554 qp_range_min, qp_range_max, PROP_QPP_DEFAULT,
2555 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2557 obj_properties[GST_MSDKENC_PROP_QPB] =
2558 g_param_spec_uint ("qpb", "QPB",
2559 "Constant quantizer for B frames (0 unlimited)",
2560 qp_range_min, qp_range_max, PROP_QPB_DEFAULT,
2561 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2563 obj_properties[GST_MSDKENC_PROP_GOP_SIZE] =
2564 g_param_spec_uint ("gop-size", "GOP Size", "GOP Size", 0,
2565 G_MAXINT, PROP_GOP_SIZE_DEFAULT,
2566 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2568 obj_properties[GST_MSDKENC_PROP_REF_FRAMES] =
2569 g_param_spec_uint ("ref-frames", "Reference Frames",
2570 "Number of reference frames",
2571 0, G_MAXINT, PROP_REF_FRAMES_DEFAULT,
2572 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2574 obj_properties[GST_MSDKENC_PROP_I_FRAMES] =
2575 g_param_spec_uint ("i-frames", "I Frames",
2576 "Number of I frames between IDR frames",
2577 0, G_MAXINT, PROP_I_FRAMES_DEFAULT,
2578 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2580 obj_properties[GST_MSDKENC_PROP_B_FRAMES] =
2581 g_param_spec_uint ("b-frames", "B Frames",
2582 "Number of B frames between I and P frames",
2583 0, G_MAXINT, PROP_B_FRAMES_DEFAULT,
2584 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2586 obj_properties[GST_MSDKENC_PROP_NUM_SLICES] =
2587 g_param_spec_uint ("num-slices", "Number of Slices",
2588 "Number of slices per frame, Zero tells the encoder to "
2589 "choose any slice partitioning allowed by the codec standard",
2590 0, G_MAXINT, PROP_NUM_SLICES_DEFAULT,
2591 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2593 obj_properties[GST_MSDKENC_PROP_MBBRC] =
2594 g_param_spec_enum ("mbbrc", "MB level bitrate control",
2595 "Macroblock level bitrate control",
2596 gst_msdkenc_mbbrc_get_type (),
2597 PROP_MBBRC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2599 obj_properties[GST_MSDKENC_PROP_ADAPTIVE_I] =
2600 g_param_spec_enum ("i-adapt", "Adaptive I-Frame Insertion",
2601 "Adaptive I-Frame Insertion control",
2602 gst_msdkenc_adaptive_i_get_type (),
2603 PROP_ADAPTIVE_I_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2605 obj_properties[GST_MSDKENC_PROP_ADAPTIVE_B] =
2606 g_param_spec_enum ("b-adapt", "Adaptive B-Frame Insertion",
2607 "Adaptive B-Frame Insertion control",
2608 gst_msdkenc_adaptive_b_get_type (),
2609 PROP_ADAPTIVE_B_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2612 * GstMsdkEnc:ext-coding-props
2614 * The properties for the external coding.
2616 * Supported properties:
2618 * extbrc : External bitrate control
2619 * String. Range: { auto, on, off } Default: off
2624 * ext-coding-props="props,extbrc=on"
2630 obj_properties[GST_MSDKENC_PROP_EXT_CODING_PROPS] =
2631 g_param_spec_boxed ("ext-coding-props", "External coding properties",
2632 "The properties for the external coding, refer to the hotdoc for the "
2633 "supported properties",
2634 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2636 g_object_class_install_properties (gobject_class,
2637 GST_MSDKENC_PROP_MAX, obj_properties);