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 <gst/va/gstvaallocator.h>
58 #include <gst/d3d11/gstd3d11.h>
62 _aligned_alloc (size_t alignment, size_t size)
65 return _aligned_malloc (size, alignment);
68 if (posix_memalign (&out, alignment, size) != 0)
75 #define _aligned_free free
78 static void gst_msdkenc_close_encoder (GstMsdkEnc * thiz);
80 GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug);
81 #define GST_CAT_DEFAULT gst_msdkenc_debug
84 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
87 GST_STATIC_CAPS (GST_MSDK_CAPS_STR
88 ("{ NV12, I420, YV12, YUY2, UYVY, BGRA }", "NV12") "; "
89 GST_MSDK_CAPS_MAKE_WITH_D3D11_FEATURE ("NV12"))
92 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
95 GST_STATIC_CAPS (GST_MSDK_CAPS_STR
96 ("{ NV12, I420, YV12, YUY2, UYVY, BGRA }", "NV12") "; "
97 GST_MSDK_CAPS_MAKE_WITH_VA_FEATURE ("NV12"))
101 #define PROP_HARDWARE_DEFAULT TRUE
102 #define PROP_ASYNC_DEPTH_DEFAULT 4
103 #define PROP_TARGET_USAGE_DEFAULT (MFX_TARGETUSAGE_BALANCED)
104 #define PROP_RATE_CONTROL_DEFAULT (MFX_RATECONTROL_CBR)
105 #define PROP_BITRATE_DEFAULT (2 * 1024)
106 #define PROP_QPI_DEFAULT 0
107 #define PROP_QPP_DEFAULT 0
108 #define PROP_QPB_DEFAULT 0
109 #define PROP_GOP_SIZE_DEFAULT 256
110 #define PROP_REF_FRAMES_DEFAULT 0
111 #define PROP_I_FRAMES_DEFAULT 0
112 #define PROP_B_FRAMES_DEFAULT 0
113 #define PROP_NUM_SLICES_DEFAULT 0
114 #define PROP_AVBR_ACCURACY_DEFAULT 0
115 #define PROP_AVBR_CONVERGENCE_DEFAULT 0
116 #define PROP_RC_LOOKAHEAD_DEPTH_DEFAULT 10
117 #define PROP_MAX_VBV_BITRATE_DEFAULT 0
118 #define PROP_MAX_FRAME_SIZE_DEFAULT 0
119 #define PROP_MAX_FRAME_SIZE_I_DEFAULT 0
120 #define PROP_MAX_FRAME_SIZE_P_DEFAULT 0
121 #define PROP_MBBRC_DEFAULT MFX_CODINGOPTION_OFF
122 #define PROP_LOWDELAY_BRC_DEFAULT MFX_CODINGOPTION_OFF
123 #define PROP_ADAPTIVE_I_DEFAULT MFX_CODINGOPTION_OFF
124 #define PROP_ADAPTIVE_B_DEFAULT MFX_CODINGOPTION_OFF
126 /* External coding properties */
127 #define EC_PROPS_STRUCT_NAME "props"
128 #define EC_PROPS_EXTBRC "extbrc"
130 #define gst_msdkenc_parent_class parent_class
131 G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER);
134 gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param)
136 if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
137 thiz->extra_params[thiz->num_extra_params] = param;
138 thiz->num_extra_params++;
143 gst_msdkenc_set_context (GstElement * element, GstContext * context)
145 GstMsdkContext *msdk_context = NULL;
146 GstMsdkEnc *thiz = GST_MSDKENC (element);
148 if (gst_msdk_context_get_context (context, &msdk_context)) {
149 gst_object_replace ((GstObject **) & thiz->context,
150 (GstObject *) msdk_context);
151 gst_object_unref (msdk_context);
154 if (gst_msdk_context_from_external_va_display (context,
155 thiz->hardware, 0 /* GST_MSDK_JOB_ENCODER will be set later */ ,
157 gst_object_replace ((GstObject **) & thiz->context,
158 (GstObject *) msdk_context);
159 gst_object_unref (msdk_context);
162 if (gst_msdk_context_from_external_d3d11_device (context,
163 thiz->hardware, 0 /* GST_MSDK_JOB_ENCODER will be set later */ ,
165 gst_object_replace ((GstObject **) & thiz->context,
166 (GstObject *) msdk_context);
167 gst_object_unref (msdk_context);
171 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
175 ensure_bitrate_control (GstMsdkEnc * thiz)
177 mfxInfoMFX *mfx = &thiz->param.mfx;
178 mfxExtCodingOption2 *option2 = &thiz->option2;
179 mfxExtCodingOption3 *option3 = &thiz->option3;
181 GST_DEBUG_OBJECT (thiz, "set target bitrate: %u kbit/sec", thiz->bitrate);
183 mfx->RateControlMethod = thiz->rate_control;
184 /* No effect in CQP variant algorithms */
185 if ((mfx->RateControlMethod != MFX_RATECONTROL_CQP) &&
186 (thiz->bitrate > G_MAXUINT16 || thiz->max_vbv_bitrate > G_MAXUINT16)) {
187 mfxU32 max_val = MAX (thiz->max_vbv_bitrate, thiz->bitrate);
189 mfx->BRCParamMultiplier = (mfxU16) ((max_val + 0x10000) / 0x10000);
190 mfx->TargetKbps = (mfxU16) (thiz->bitrate / mfx->BRCParamMultiplier);
191 mfx->MaxKbps = (mfxU16) (thiz->max_vbv_bitrate / mfx->BRCParamMultiplier);
192 mfx->BufferSizeInKB =
193 (mfxU16) (mfx->BufferSizeInKB / mfx->BRCParamMultiplier);
194 /* Currently InitialDelayInKB is not used in this plugin */
195 mfx->InitialDelayInKB =
196 (mfxU16) (mfx->InitialDelayInKB / mfx->BRCParamMultiplier);
198 mfx->TargetKbps = thiz->bitrate;
199 mfx->MaxKbps = thiz->max_vbv_bitrate;
200 mfx->BRCParamMultiplier = 1;
203 switch (mfx->RateControlMethod) {
204 case MFX_RATECONTROL_CQP:
205 mfx->QPI = thiz->qpi;
206 mfx->QPP = thiz->qpp;
207 mfx->QPB = thiz->qpb;
210 case MFX_RATECONTROL_LA_ICQ:
211 option2->LookAheadDepth = thiz->lookahead_depth;
212 case MFX_RATECONTROL_ICQ:
213 mfx->ICQQuality = CLAMP (thiz->qpi, 1, 51);
216 case MFX_RATECONTROL_LA: /* VBR with LA. Only supported in H264?? */
217 case MFX_RATECONTROL_LA_HRD: /* VBR with LA, HRD compliant */
218 option2->LookAheadDepth = thiz->lookahead_depth;
221 case MFX_RATECONTROL_QVBR:
222 option3->QVBRQuality = CLAMP (thiz->qpi, 1, 51);
223 thiz->enable_extopt3 = TRUE;
226 case MFX_RATECONTROL_AVBR:
227 mfx->Accuracy = thiz->accuracy;
228 mfx->Convergence = thiz->convergence;
231 case MFX_RATECONTROL_VBR:
232 thiz->enable_extopt3 = TRUE;
233 option2->MaxFrameSize = thiz->max_frame_size * 1000;
234 if (thiz->max_frame_size_i > 0)
235 option3->MaxFrameSizeI = thiz->max_frame_size_i * 1000;
236 if (thiz->max_frame_size_p > 0)
237 option3->MaxFrameSizeP = thiz->max_frame_size_p * 1000;
238 if (thiz->lowdelay_brc != MFX_CODINGOPTION_UNKNOWN) {
239 option3->LowDelayBRC = thiz->lowdelay_brc;
243 case MFX_RATECONTROL_VCM:
244 /*Non HRD compliant mode with no B-frame and interlaced support */
245 thiz->param.mfx.GopRefDist = 0;
248 case MFX_RATECONTROL_CBR:
252 GST_ERROR ("Unsupported RateControl!");
258 coding_option_get_value (const gchar * key, const gchar * nickname)
260 if (!g_strcmp0 (nickname, "on")) {
261 return MFX_CODINGOPTION_ON;
262 } else if (!g_strcmp0 (nickname, "off")) {
263 return MFX_CODINGOPTION_OFF;
264 } else if (!g_strcmp0 (nickname, "auto")) {
265 return MFX_CODINGOPTION_UNKNOWN;
268 GST_ERROR ("\"%s\" illegal option \"%s\", set to \"off\"", key, nickname);
270 return MFX_CODINGOPTION_OFF;
274 structure_transform (const GstStructure * src, GstStructure * dst)
277 GValue dst_value = G_VALUE_INIT;
280 g_return_val_if_fail (src != NULL, FALSE);
281 g_return_val_if_fail (dst != NULL, FALSE);
283 len = gst_structure_n_fields (src);
285 for (guint i = 0; i < len; i++) {
286 const gchar *key = gst_structure_nth_field_name (src, i);
287 const GValue *src_value = gst_structure_get_value (src, key);
289 if (!gst_structure_has_field (dst, key)) {
290 GST_ERROR ("structure \"%s\" does not support \"%s\"",
291 gst_structure_get_name (dst), key);
296 g_value_init (&dst_value, gst_structure_get_field_type (dst, key));
298 if (g_value_transform (src_value, &dst_value)) {
299 gst_structure_set_value (dst, key, &dst_value);
301 GST_ERROR ("\"%s\" transform %s to %s failed", key,
302 G_VALUE_TYPE_NAME (src_value), G_VALUE_TYPE_NAME (&dst_value));
306 g_value_unset (&dst_value);
312 /* Supported types: gchar*, gboolean, gint, guint, gfloat, gdouble */
314 structure_get_value (const GstStructure * s, const gchar * key, gpointer value)
316 const GValue *gvalue = gst_structure_get_value (s, key);
318 GST_ERROR ("structure \"%s\" does not support \"%s\"",
319 gst_structure_get_name (s), key);
323 switch (G_VALUE_TYPE (gvalue)) {
325 const gchar **val = (const gchar **) value;
326 *val = g_value_get_string (gvalue);
329 case G_TYPE_BOOLEAN:{
330 gboolean *val = (gboolean *) value;
331 *val = g_value_get_boolean (gvalue);
335 gint *val = (gint *) value;
336 *val = g_value_get_int (gvalue);
340 guint *val = (guint *) value;
341 *val = g_value_get_uint (gvalue);
345 gfloat *val = (gfloat *) value;
346 *val = g_value_get_float (gvalue);
350 gdouble *val = (gdouble *) value;
351 *val = g_value_get_double (gvalue);
355 GST_ERROR ("\"%s\" unsupported type %s", key, G_VALUE_TYPE_NAME (gvalue));
363 ext_coding_props_get_value (GstMsdkEnc * thiz,
364 const gchar * key, gpointer value)
367 if (!(ret = structure_get_value (thiz->ext_coding_props, key, value))) {
368 GST_ERROR_OBJECT (thiz, "structure \"%s\" failed to get value for \"%s\"",
369 gst_structure_get_name (thiz->ext_coding_props), key);
376 gst_msdkenc_ensure_extended_coding_options (GstMsdkEnc * thiz)
378 mfxExtCodingOption2 *option2 = &thiz->option2;
379 mfxExtCodingOption3 *option3 = &thiz->option3;
382 ext_coding_props_get_value (thiz, EC_PROPS_EXTBRC, &extbrc);
384 /* Fill ExtendedCodingOption2, set non-zero defaults too */
385 option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
386 option2->Header.BufferSz = sizeof (thiz->option2);
387 option2->MBBRC = thiz->mbbrc;
388 option2->ExtBRC = coding_option_get_value (EC_PROPS_EXTBRC, extbrc);
389 option2->AdaptiveI = thiz->adaptive_i;
390 option2->AdaptiveB = thiz->adaptive_b;
391 option2->BitrateLimit = MFX_CODINGOPTION_OFF;
392 option2->EnableMAD = MFX_CODINGOPTION_OFF;
393 option2->UseRawRef = MFX_CODINGOPTION_OFF;
394 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option2);
396 if (thiz->enable_extopt3) {
397 option3->Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
398 option3->Header.BufferSz = sizeof (thiz->option3);
399 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option3);
403 /* Return TRUE if ROI is changed and update ROI parameters in encoder_roi */
405 gst_msdkenc_get_roi_params (GstMsdkEnc * thiz,
406 GstVideoCodecFrame * frame, mfxExtEncoderROI * encoder_roi)
409 guint num_roi, i, num_valid_roi = 0;
410 gushort roi_mode = G_MAXUINT16;
411 gpointer state = NULL;
412 mfxExtEncoderROI *curr_roi = encoder_roi;
413 mfxExtEncoderROI *prev_roi = encoder_roi + 1;
415 if (!frame || !frame->input_buffer)
418 memset (curr_roi, 0, sizeof (mfxExtEncoderROI));
419 input = frame->input_buffer;
422 gst_buffer_get_n_meta (input, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
427 curr_roi->Header.BufferId = MFX_EXTBUFF_ENCODER_ROI;
428 curr_roi->Header.BufferSz = sizeof (mfxExtEncoderROI);
430 for (i = 0; i < num_roi && num_valid_roi < 256; i++) {
431 GstVideoRegionOfInterestMeta *roi;
434 roi = (GstVideoRegionOfInterestMeta *)
435 gst_buffer_iterate_meta_filtered (input, &state,
436 GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
441 /* ignore roi if overflow */
442 if ((roi->x > G_MAXINT16) || (roi->y > G_MAXINT16)
443 || (roi->w > G_MAXUINT16) || (roi->h > G_MAXUINT16)) {
444 GST_DEBUG_OBJECT (thiz, "Ignoring ROI... ROI overflow");
448 GST_LOG ("Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
449 g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
452 curr_roi->ROI[num_valid_roi].Left = roi->x;
453 curr_roi->ROI[num_valid_roi].Top = roi->y;
454 curr_roi->ROI[num_valid_roi].Right = roi->x + roi->w;
455 curr_roi->ROI[num_valid_roi].Bottom = roi->y + roi->h;
457 s = gst_video_region_of_interest_meta_get_param (roi, "roi/msdk");
462 if (roi_mode == G_MAXUINT16) {
463 if (gst_structure_get_int (s, "delta-qp", &value)) {
464 #if (MFX_VERSION >= 1022)
465 roi_mode = MFX_ROI_MODE_QP_DELTA;
466 curr_roi->ROI[num_valid_roi].DeltaQP = CLAMP (value, -51, 51);
467 GST_LOG ("Use delta-qp %d", value);
470 ("Ignore delta QP because the MFX doesn't support delta QP mode");
472 } else if (gst_structure_get_int (s, "priority", &value)) {
473 roi_mode = MFX_ROI_MODE_PRIORITY;
474 curr_roi->ROI[num_valid_roi].Priority = CLAMP (value, -3, 3);
475 GST_LOG ("Use priority %d", value);
478 #if (MFX_VERSION >= 1022)
479 } else if (roi_mode == MFX_ROI_MODE_QP_DELTA &&
480 gst_structure_get_int (s, "delta-qp", &value)) {
481 curr_roi->ROI[num_valid_roi].DeltaQP = CLAMP (value, -51, 51);
483 } else if (roi_mode == MFX_ROI_MODE_PRIORITY &&
484 gst_structure_get_int (s, "priority", &value)) {
485 curr_roi->ROI[num_valid_roi].Priority = CLAMP (value, -3, 3);
493 #if (MFX_VERSION >= 1022)
494 curr_roi->ROIMode = roi_mode;
497 curr_roi->NumROI = num_valid_roi;
500 if (curr_roi->NumROI == 0 && prev_roi->NumROI == 0)
503 if (curr_roi->NumROI != prev_roi->NumROI ||
504 memcmp (curr_roi, prev_roi, sizeof (mfxExtEncoderROI)) != 0) {
505 *prev_roi = *curr_roi;
513 gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
515 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
519 mfxFrameAllocRequest request[2];
521 gboolean need_vpp = TRUE;
522 GstVideoFormat encoder_input_fmt;
523 mfxExtVideoSignalInfo ext_vsi;
525 if (thiz->initialized) {
526 GST_DEBUG_OBJECT (thiz, "Already initialized");
530 if (!thiz->context) {
531 GST_WARNING_OBJECT (thiz, "No MSDK Context");
535 if (!thiz->input_state) {
536 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
539 info = &thiz->input_state->info;
541 GST_OBJECT_LOCK (thiz);
542 session = gst_msdk_context_get_session (thiz->context);
543 thiz->codename = msdk_get_platform_codename (session);
545 thiz->has_vpp = FALSE;
546 if (thiz->use_video_memory)
547 gst_msdk_set_frame_allocator (thiz->context);
549 encoder_input_fmt = GST_VIDEO_INFO_FORMAT (info);
550 need_vpp = klass->need_conversion (thiz, info, &encoder_input_fmt);
553 switch (GST_VIDEO_INFO_FORMAT (info)) {
554 case GST_VIDEO_FORMAT_YV12:
555 case GST_VIDEO_FORMAT_I420:
556 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YV12;
557 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
559 case GST_VIDEO_FORMAT_YUY2:
560 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YUY2;
561 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
563 case GST_VIDEO_FORMAT_UYVY:
564 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_UYVY;
565 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
567 case GST_VIDEO_FORMAT_BGRA:
568 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_RGB4;
569 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
572 g_assert_not_reached ();
576 if (thiz->use_video_memory)
577 thiz->vpp_param.IOPattern =
578 MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
580 thiz->vpp_param.IOPattern =
581 MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
583 thiz->vpp_param.vpp.In.Width = GST_ROUND_UP_16 (info->width);
584 thiz->vpp_param.vpp.In.Height = GST_ROUND_UP_32 (info->height);
585 thiz->vpp_param.vpp.In.CropW = info->width;
586 thiz->vpp_param.vpp.In.CropH = info->height;
587 thiz->vpp_param.vpp.In.FrameRateExtN = info->fps_n;
588 thiz->vpp_param.vpp.In.FrameRateExtD = info->fps_d;
589 thiz->vpp_param.vpp.In.AspectRatioW = info->par_n;
590 thiz->vpp_param.vpp.In.AspectRatioH = info->par_d;
591 thiz->vpp_param.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
593 /* work-around to avoid zero fps in msdk structure */
594 if (0 == thiz->vpp_param.vpp.In.FrameRateExtN)
595 thiz->vpp_param.vpp.In.FrameRateExtN = 30;
597 thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
599 switch (encoder_input_fmt) {
600 case GST_VIDEO_FORMAT_P010_10LE:
601 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_P010;
602 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
605 case GST_VIDEO_FORMAT_YUY2:
606 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_YUY2;
607 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
611 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
612 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
616 /* validate parameters and allow MFX to make adjustments */
617 status = MFXVideoVPP_Query (session, &thiz->vpp_param, &thiz->vpp_param);
618 if (status < MFX_ERR_NONE) {
619 GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
620 msdk_status_to_string (status));
622 } else if (status > MFX_ERR_NONE) {
623 GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
624 msdk_status_to_string (status));
627 status = MFXVideoVPP_QueryIOSurf (session, &thiz->vpp_param, request);
628 if (status < MFX_ERR_NONE) {
629 GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
630 msdk_status_to_string (status));
632 } else if (status > MFX_ERR_NONE) {
633 GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
634 msdk_status_to_string (status));
637 if (thiz->use_video_memory)
638 request[0].NumFrameSuggested +=
639 gst_msdk_context_get_shared_async_depth (thiz->context);
640 thiz->num_vpp_surfaces = request[0].NumFrameSuggested;
642 status = MFXVideoVPP_Init (session, &thiz->vpp_param);
643 if (status < MFX_ERR_NONE) {
644 GST_ERROR_OBJECT (thiz, "Init failed (%s)",
645 msdk_status_to_string (status));
646 } else if (status > MFX_ERR_NONE) {
647 GST_WARNING_OBJECT (thiz, "Init returned: %s",
648 msdk_status_to_string (status));
651 status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
652 if (status < MFX_ERR_NONE) {
654 GST_ERROR_OBJECT (thiz, "Get VPP Parameters failed (%s)",
655 msdk_status_to_string (status));
656 status1 = MFXVideoVPP_Close (session);
657 if (status1 != MFX_ERR_NONE && status1 != MFX_ERR_NOT_INITIALIZED)
658 GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
659 msdk_status_to_string (status1));
660 } else if (status > MFX_ERR_NONE) {
661 GST_WARNING_OBJECT (thiz, "Get VPP Parameters returned: %s",
662 msdk_status_to_string (status));
665 thiz->has_vpp = TRUE;
668 thiz->param.AsyncDepth = thiz->async_depth;
669 if (thiz->use_video_memory)
670 thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
672 thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
674 thiz->param.mfx.TargetUsage = thiz->target_usage;
675 thiz->param.mfx.GopPicSize = thiz->gop_size;
676 thiz->param.mfx.GopRefDist = thiz->b_frames + 1;
677 thiz->param.mfx.IdrInterval = thiz->i_frames;
678 thiz->param.mfx.NumSlice = thiz->num_slices;
679 thiz->param.mfx.NumRefFrame = thiz->ref_frames;
680 thiz->param.mfx.EncodedOrder = 0; /* Take input frames in display order */
682 thiz->param.mfx.FrameInfo.Width = GST_ROUND_UP_16 (info->width);
683 thiz->param.mfx.FrameInfo.Height = GST_ROUND_UP_32 (info->height);
684 thiz->param.mfx.FrameInfo.CropW = info->width;
685 thiz->param.mfx.FrameInfo.CropH = info->height;
686 thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
687 thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
688 thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
689 thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
690 thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
691 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
693 switch (encoder_input_fmt) {
694 case GST_VIDEO_FORMAT_P010_10LE:
695 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P010;
696 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
697 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
698 thiz->param.mfx.FrameInfo.Shift = 1;
700 case GST_VIDEO_FORMAT_VUYA:
701 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_AYUV;
702 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
703 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
704 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
706 #if (MFX_VERSION >= 1027)
707 case GST_VIDEO_FORMAT_Y410:
708 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_Y410;
709 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
710 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
711 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
713 case GST_VIDEO_FORMAT_Y210:
714 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_Y210;
715 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
716 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
717 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
718 thiz->param.mfx.FrameInfo.Shift = 1;
721 case GST_VIDEO_FORMAT_BGRA:
722 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_RGB4;
723 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
724 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
725 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
727 case GST_VIDEO_FORMAT_BGR10A2_LE:
728 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_A2RGB10;
729 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
730 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
731 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
733 case GST_VIDEO_FORMAT_YUY2:
734 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_YUY2;
735 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
736 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
737 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
739 #if (MFX_VERSION >= 1031)
740 case GST_VIDEO_FORMAT_P012_LE:
741 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P016;
742 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
743 thiz->param.mfx.FrameInfo.BitDepthLuma = 12;
744 thiz->param.mfx.FrameInfo.BitDepthChroma = 12;
745 thiz->param.mfx.FrameInfo.Shift = 1;
749 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
750 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
751 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
754 /* work-around to avoid zero fps in msdk structure */
755 if (0 == thiz->param.mfx.FrameInfo.FrameRateExtN)
756 thiz->param.mfx.FrameInfo.FrameRateExtN = 30;
758 /* ensure bitrate control parameters */
759 ensure_bitrate_control (thiz);
761 /* allow subclass configure further */
762 if (klass->configure) {
763 if (!klass->configure (thiz))
767 /* If color properties are available from upstream, set it and pass to MediaSDK here.
768 * MJPEG and VP9 are excluded as MediaSDK does not support to handle video param
769 * extbuff with buffer id equals to MFX_EXTBUFF_VIDEO_SIGNAL_INFO.
771 if (thiz->param.mfx.CodecId != MFX_CODEC_JPEG &&
772 thiz->param.mfx.CodecId != MFX_CODEC_VP9 &&
773 (info->colorimetry.primaries || info->colorimetry.transfer
774 || info->colorimetry.matrix)) {
775 memset (&ext_vsi, 0, sizeof (ext_vsi));
776 ext_vsi.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
777 ext_vsi.Header.BufferSz = sizeof (ext_vsi);
778 ext_vsi.ColourDescriptionPresent = 1;
779 ext_vsi.ColourPrimaries =
780 gst_video_color_primaries_to_iso (info->colorimetry.primaries);
781 ext_vsi.TransferCharacteristics =
782 gst_video_transfer_function_to_iso (info->colorimetry.transfer);
783 ext_vsi.MatrixCoefficients =
784 gst_video_color_matrix_to_iso (info->colorimetry.matrix);
785 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) & ext_vsi);
788 if (thiz->num_extra_params) {
789 thiz->param.NumExtParam = thiz->num_extra_params;
790 thiz->param.ExtParam = thiz->extra_params;
793 /* validate parameters and allow MFX to make adjustments */
794 status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param);
795 if (status < MFX_ERR_NONE) {
796 GST_ERROR_OBJECT (thiz, "Video Encode Query failed (%s)",
797 msdk_status_to_string (status));
799 } else if (status > MFX_ERR_NONE) {
800 GST_WARNING_OBJECT (thiz, "Video Encode Query returned: %s",
801 msdk_status_to_string (status));
804 status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, request);
805 if (status < MFX_ERR_NONE) {
806 GST_ERROR_OBJECT (thiz, "Encode Query IO surfaces failed (%s)",
807 msdk_status_to_string (status));
809 } else if (status > MFX_ERR_NONE) {
810 GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
811 msdk_status_to_string (status));
814 request[0].NumFrameSuggested += thiz->num_extra_frames;
817 request[0].NumFrameSuggested += thiz->num_vpp_surfaces + 1 - 4;
819 /* Maximum of VPP output and encoder input, if using VPP */
821 request[0].NumFrameSuggested =
822 MAX (request[0].NumFrameSuggested, request[1].NumFrameSuggested);
823 if (request[0].NumFrameSuggested < thiz->param.AsyncDepth) {
824 GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
825 request[0].NumFrameMin, request[0].NumFrameSuggested,
826 thiz->param.AsyncDepth);
830 /* This is VPP output (if any) and encoder input */
831 thiz->num_surfaces = request[0].NumFrameSuggested;
833 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
834 request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
836 status = MFXVideoENCODE_Init (session, &thiz->param);
837 if (status < MFX_ERR_NONE) {
838 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
840 } else if (status > MFX_ERR_NONE) {
841 GST_WARNING_OBJECT (thiz, "Init returned: %s",
842 msdk_status_to_string (status));
845 status = MFXVideoENCODE_GetVideoParam (session, &thiz->param);
846 if (status < MFX_ERR_NONE) {
847 GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
848 msdk_status_to_string (status));
850 } else if (status > MFX_ERR_NONE) {
851 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
852 msdk_status_to_string (status));
855 thiz->num_tasks = thiz->param.AsyncDepth;
856 thiz->tasks = g_new0 (MsdkEncTask, thiz->num_tasks);
857 for (i = 0; i < thiz->num_tasks; i++) {
858 thiz->tasks[i].output_bitstream.Data = _aligned_alloc (32,
859 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
861 if (!thiz->tasks[i].output_bitstream.Data) {
862 GST_ERROR_OBJECT (thiz, "Memory allocation failed");
865 thiz->tasks[i].output_bitstream.MaxLength =
866 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
871 thiz->reconfig = FALSE;
872 thiz->initialized = TRUE;
874 GST_OBJECT_UNLOCK (thiz);
879 GST_OBJECT_UNLOCK (thiz);
884 gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
889 if (!thiz->context || !thiz->initialized)
892 GST_DEBUG_OBJECT (thiz, "Closing encoder with context %" GST_PTR_FORMAT,
895 gst_clear_object (&thiz->msdk_pool);
896 gst_clear_object (&thiz->msdk_converted_pool);
898 status = MFXVideoENCODE_Close (gst_msdk_context_get_session (thiz->context));
899 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
900 GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
901 msdk_status_to_string (status));
905 for (i = 0; i < thiz->num_tasks; i++) {
906 MsdkEncTask *task = &thiz->tasks[i];
907 if (task->output_bitstream.Data) {
908 _aligned_free (task->output_bitstream.Data);
912 g_free (thiz->tasks);
915 /* Close VPP before freeing the surfaces. They are shared between encoder
918 status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
919 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
920 GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
921 msdk_status_to_string (status));
925 memset (&thiz->param, 0, sizeof (thiz->param));
926 thiz->num_extra_params = 0;
927 thiz->initialized = FALSE;
932 GstVideoCodecFrame *frame;
933 GstMsdkSurface *frame_surface;
934 GstMsdkSurface *converted_surface;
938 gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame,
943 fdata = g_slice_new (FrameData);
944 fdata->frame = gst_video_codec_frame_ref (frame);
946 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
952 gst_msdkenc_free_surface (GstMsdkSurface * surface)
955 gst_buffer_unref (surface->buf);
957 g_slice_free (GstMsdkSurface, surface);
961 gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata)
963 if (fdata->frame_surface)
964 gst_msdkenc_free_surface (fdata->frame_surface);
966 gst_msdkenc_free_surface (fdata->converted_surface);
968 gst_video_codec_frame_unref (fdata->frame);
969 g_slice_free (FrameData, fdata);
973 gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
977 for (l = thiz->pending_frames; l;) {
978 FrameData *fdata = l->data;
983 if (fdata->frame != frame)
986 gst_msdkenc_free_frame_data (thiz, fdata);
988 thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l1);
994 gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz)
998 for (l = thiz->pending_frames; l; l = l->next) {
999 FrameData *fdata = l->data;
1001 gst_msdkenc_free_frame_data (thiz, fdata);
1003 g_list_free (thiz->pending_frames);
1004 thiz->pending_frames = NULL;
1007 static MsdkEncTask *
1008 gst_msdkenc_get_free_task (GstMsdkEnc * thiz)
1010 MsdkEncTask *tasks = thiz->tasks;
1011 guint size = thiz->num_tasks;
1012 guint start = thiz->next_task;
1016 for (i = 0; i < size; i++) {
1017 guint t = (start + i) % size;
1018 if (tasks[t].sync_point == NULL)
1026 gst_msdkenc_reset_task (MsdkEncTask * task)
1028 task->output_bitstream.DataLength = 0;
1029 task->sync_point = NULL;
1032 static GstVideoCodecFrame *
1033 gst_msdkenc_find_best_frame (GstMsdkEnc * thiz, GList * frames,
1034 mfxBitstream * bitstream)
1037 GstVideoCodecFrame *ret = NULL;
1039 GstClockTimeDiff best_diff = GST_CLOCK_STIME_NONE;
1044 if (bitstream->TimeStamp == MFX_TIMESTAMP_UNKNOWN) {
1045 pts = GST_CLOCK_TIME_NONE;
1047 pts = gst_util_uint64_scale (bitstream->TimeStamp, GST_SECOND, 90000);
1050 for (iter = frames; iter; iter = g_list_next (iter)) {
1051 GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
1053 /* if we don't know the time stamp, find the first frame which
1054 * has unknown timestamp */
1055 if (!GST_CLOCK_TIME_IS_VALID (pts)) {
1056 if (!GST_CLOCK_TIME_IS_VALID (frame->pts)) {
1061 GstClockTimeDiff abs_diff = ABS (GST_CLOCK_DIFF (frame->pts, pts));
1062 if (abs_diff == 0) {
1067 if (!GST_CLOCK_STIME_IS_VALID (best_diff) || abs_diff < best_diff) {
1069 best_diff = abs_diff;
1075 gst_video_codec_frame_ref (ret);
1080 static GstFlowReturn
1081 gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task,
1084 GstVideoCodecFrame *frame;
1087 if (!task->sync_point)
1090 list = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (thiz));
1093 GST_ERROR_OBJECT (thiz, "failed to get list of frame");
1094 return GST_FLOW_ERROR;
1097 /* Wait for encoding operation to complete, the magic number 300000 below
1098 * is used in MSDK samples
1099 * #define MSDK_ENC_WAIT_INTERVAL 300000
1101 if (MFXVideoCORE_SyncOperation (gst_msdk_context_get_session (thiz->context),
1102 task->sync_point, 300000) != MFX_ERR_NONE)
1103 GST_WARNING_OBJECT (thiz, "failed to do sync operation");
1105 if (!discard && task->output_bitstream.DataLength) {
1106 GstBuffer *out_buf = NULL;
1108 task->output_bitstream.Data + task->output_bitstream.DataOffset;
1109 gsize size = task->output_bitstream.DataLength;
1111 frame = gst_msdkenc_find_best_frame (thiz, list, &task->output_bitstream);
1113 /* just pick the oldest one */
1114 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
1117 out_buf = gst_buffer_new_allocate (NULL, size, NULL);
1118 gst_buffer_fill (out_buf, 0, data, size);
1119 frame->output_buffer = out_buf;
1121 gst_util_uint64_scale (task->output_bitstream.TimeStamp, GST_SECOND,
1124 gst_util_uint64_scale (task->output_bitstream.DecodeTimeStamp,
1126 if ((task->output_bitstream.FrameType & MFX_FRAMETYPE_IDR) != 0 ||
1127 (task->output_bitstream.FrameType & MFX_FRAMETYPE_xIDR) != 0) {
1128 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1131 /* Mark task as available */
1132 gst_msdkenc_reset_task (task);
1134 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
1137 g_list_free_full (list, (GDestroyNotify) gst_video_codec_frame_unref);
1139 gst_video_codec_frame_unref (frame);
1140 gst_msdkenc_dequeue_frame (thiz, frame);
1142 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1145 static GstFlowReturn
1146 gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
1147 GstVideoCodecFrame * input_frame)
1153 if (G_UNLIKELY (thiz->context == NULL)) {
1154 gst_msdkenc_dequeue_frame (thiz, input_frame);
1155 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
1156 return GST_FLOW_NOT_NEGOTIATED;
1158 session = gst_msdk_context_get_session (thiz->context);
1160 task = gst_msdkenc_get_free_task (thiz);
1163 /* Force key-frame if needed */
1164 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame))
1165 thiz->enc_cntrl.FrameType =
1166 MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF;
1168 thiz->enc_cntrl.FrameType = MFX_FRAMETYPE_UNKNOWN;
1171 MFXVideoENCODE_EncodeFrameAsync (session, &thiz->enc_cntrl, surface,
1172 &task->output_bitstream, &task->sync_point);
1174 if (status != MFX_WRN_DEVICE_BUSY)
1176 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1180 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1181 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
1182 ("MSDK encode error (%s)", msdk_status_to_string (status)));
1183 gst_msdkenc_dequeue_frame (thiz, input_frame);
1184 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
1185 return GST_FLOW_ERROR;
1188 if (task->sync_point) {
1189 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
1190 } else if (status == MFX_ERR_MORE_DATA) {
1191 gst_msdkenc_dequeue_frame (thiz, input_frame);
1194 /* Ensure that next task is available */
1195 task = thiz->tasks + thiz->next_task;
1196 return gst_msdkenc_finish_frame (thiz, task, FALSE);
1200 gst_msdkenc_maximum_delayed_frames (GstMsdkEnc * thiz)
1202 return thiz->num_tasks;
1206 gst_msdkenc_set_latency (GstMsdkEnc * thiz)
1208 GstVideoInfo *info = &thiz->input_state->info;
1209 gint max_delayed_frames;
1210 GstClockTime latency;
1212 max_delayed_frames = gst_msdkenc_maximum_delayed_frames (thiz);
1215 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
1216 max_delayed_frames, info->fps_n);
1218 /* FIXME: Assume 25fps. This is better than reporting no latency at
1219 * all and then later failing in live pipelines
1221 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
1222 max_delayed_frames, 25);
1225 GST_INFO_OBJECT (thiz,
1226 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
1227 GST_TIME_ARGS (latency), max_delayed_frames);
1229 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (thiz), latency, latency);
1233 gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard)
1243 GST_DEBUG_OBJECT (thiz, "flush frames");
1245 session = gst_msdk_context_get_session (thiz->context);
1248 task = thiz->tasks + thiz->next_task;
1249 gst_msdkenc_finish_frame (thiz, task, FALSE);
1251 status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL,
1252 &task->output_bitstream, &task->sync_point);
1254 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1255 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
1256 ("MSDK encode error (%s)", msdk_status_to_string (status)));
1260 if (task->sync_point) {
1261 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
1262 } else if (status == MFX_ERR_MORE_DATA) {
1267 t = thiz->next_task;
1268 for (i = 0; i < thiz->num_tasks; i++) {
1269 gst_msdkenc_finish_frame (thiz, &thiz->tasks[t], discard);
1270 t = (t + 1) % thiz->num_tasks;
1275 gst_msdkenc_set_src_caps (GstMsdkEnc * thiz)
1277 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1278 GstCaps *outcaps = NULL;
1279 GstVideoCodecState *state;
1282 if (klass->set_src_caps)
1283 outcaps = klass->set_src_caps (thiz);
1288 state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (thiz),
1289 outcaps, thiz->input_state);
1290 GST_DEBUG_OBJECT (thiz, "output caps: %" GST_PTR_FORMAT, state->caps);
1292 gst_video_codec_state_unref (state);
1294 tags = gst_tag_list_new_empty ();
1295 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "msdkenc",
1296 GST_TAG_MAXIMUM_BITRATE, thiz->bitrate * 1024,
1297 GST_TAG_NOMINAL_BITRATE, thiz->bitrate * 1024, NULL);
1298 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (thiz), tags,
1299 GST_TAG_MERGE_REPLACE);
1300 gst_tag_list_unref (tags);
1306 static GstBufferPool *
1307 gst_msdk_create_va_pool (GstMsdkEnc * thiz, GstCaps * caps, guint num_buffers)
1309 GstBufferPool *pool = NULL;
1310 GstAllocator *allocator;
1311 GArray *formats = NULL;
1312 GstAllocationParams alloc_params = { 0, 31, 0, 0 };
1313 GstVaDisplay *display = NULL;
1314 GstVideoInfo info = thiz->input_state->info;
1316 display = (GstVaDisplay *) gst_msdk_context_get_va_display (thiz->context);
1318 if (thiz->use_dmabuf) {
1319 allocator = gst_va_dmabuf_allocator_new (display);
1321 formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
1322 g_array_append_val (formats, GST_VIDEO_INFO_FORMAT (&info));
1323 allocator = gst_va_allocator_new (display, formats);
1327 GST_ERROR_OBJECT (thiz, "failed to create allocator");
1329 g_array_unref (formats);
1334 gst_va_pool_new_with_config (caps, GST_VIDEO_INFO_SIZE (&info),
1335 num_buffers, 0, VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC, GST_VA_FEATURE_AUTO,
1336 allocator, &alloc_params);
1338 gst_object_unref (allocator);
1340 GST_LOG_OBJECT (thiz, "Creating va pool");
1344 static GstBufferPool *
1345 gst_msdk_create_d3d11_pool (GstMsdkEnc * thiz, guint num_buffers)
1347 GstBufferPool *pool = NULL;
1348 GstD3D11Device *device;
1349 GstStructure *config;
1350 GstD3D11AllocationParams *params;
1351 GstD3D11Format device_format;
1352 guint bind_flags = 0;
1353 GstCaps *aligned_caps = NULL;
1354 GstVideoInfo *info = &thiz->input_state->info;
1355 GstVideoInfo aligned_info;
1357 gint aligned_height;
1359 device = gst_msdk_context_get_d3d11_device (thiz->context);
1361 aligned_width = GST_ROUND_UP_16 (info->width);
1362 if (GST_VIDEO_INFO_IS_INTERLACED (info)) {
1363 aligned_height = GST_ROUND_UP_32 (info->height);
1365 aligned_height = GST_ROUND_UP_16 (info->height);
1368 gst_video_info_set_interlaced_format (&aligned_info,
1369 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1370 aligned_width, aligned_height);
1372 gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (&aligned_info),
1374 if ((device_format.format_support[0] & D3D11_FORMAT_SUPPORT_RENDER_TARGET) ==
1375 D3D11_FORMAT_SUPPORT_RENDER_TARGET) {
1376 bind_flags = D3D11_BIND_RENDER_TARGET;
1379 aligned_caps = gst_video_info_to_caps (&aligned_info);
1381 pool = gst_d3d11_buffer_pool_new (device);
1382 config = gst_buffer_pool_get_config (pool);
1383 params = gst_d3d11_allocation_params_new (device, &aligned_info,
1384 GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags,
1385 D3D11_RESOURCE_MISC_SHARED);
1387 gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
1388 gst_d3d11_allocation_params_free (params);
1389 gst_buffer_pool_config_set_params (config, aligned_caps,
1390 GST_VIDEO_INFO_SIZE (&aligned_info), num_buffers, 0);
1391 gst_buffer_pool_set_config (pool, config);
1393 gst_caps_unref (aligned_caps);
1394 GST_LOG_OBJECT (thiz, "Creating d3d11 pool");
1400 static GstBufferPool *
1401 gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps,
1402 guint num_buffers, gboolean set_align)
1404 GstBufferPool *pool = NULL;
1405 GstStructure *config;
1407 GstVideoAlignment align;
1409 if (!gst_video_info_from_caps (&info, caps)) {
1410 GST_INFO_OBJECT (thiz, "failed to get video info");
1414 gst_msdk_set_video_alignment (&info, 0, 0, &align);
1415 gst_video_info_align (&info, &align);
1417 pool = gst_msdk_create_va_pool (thiz, caps, num_buffers);
1419 pool = gst_msdk_create_d3d11_pool (thiz, num_buffers);
1421 if (!thiz->use_video_memory)
1422 pool = gst_video_buffer_pool_new ();
1426 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1427 gst_buffer_pool_config_set_params (config, caps,
1428 GST_VIDEO_INFO_SIZE (&info), num_buffers, 0);
1429 gst_buffer_pool_config_set_video_alignment (config, &align);
1431 if (thiz->use_video_memory) {
1432 gst_buffer_pool_config_add_option (config,
1433 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1434 if (thiz->use_dmabuf)
1435 gst_buffer_pool_config_add_option (config,
1436 GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1438 if (!gst_buffer_pool_set_config (pool, config))
1439 goto error_pool_config;
1442 thiz->aligned_info = info;
1448 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1453 GST_INFO_OBJECT (thiz, "failed to set config");
1454 gst_object_unref (pool);
1459 /* Fixme: Common routine used by all msdk elements, should be
1460 * moved to a common util file */
1462 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
1466 for (i = 0; i < gst_caps_get_size (caps); i++) {
1467 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
1468 /* Skip ANY features, we need an exact match for correct evaluation */
1469 if (gst_caps_features_is_any (features))
1471 if (gst_caps_features_contains (features, feature))
1478 sinkpad_can_dmabuf (GstMsdkEnc * thiz)
1480 gboolean ret = FALSE;
1481 GstCaps *caps, *allowed_caps;
1484 sinkpad = GST_VIDEO_ENCODER_SINK_PAD (thiz);
1485 caps = gst_pad_get_pad_template_caps (sinkpad);
1487 allowed_caps = gst_pad_peer_query_caps (sinkpad, caps);
1490 if (gst_caps_is_any (allowed_caps) || gst_caps_is_empty (allowed_caps)
1491 || allowed_caps == caps)
1494 if (_gst_caps_has_feature (allowed_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
1499 gst_caps_unref (caps);
1501 gst_caps_unref (allowed_caps);
1507 sinkpad_is_va (GstMsdkEnc * thiz)
1509 GstCapsFeatures *features =
1510 gst_caps_get_features (thiz->input_state->caps, 0);
1511 if (gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_VA))
1518 sinkpad_is_d3d11 (GstMsdkEnc * thiz)
1520 GstCapsFeatures *features =
1521 gst_caps_get_features (thiz->input_state->caps, 0);
1522 if (gst_caps_features_contains (features,
1523 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY))
1531 gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
1533 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1534 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1537 if (thiz->input_state) {
1538 if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
1539 GST_INFO_OBJECT (thiz, "Re-init the encoder as info changed");
1540 gst_msdkenc_flush_frames (thiz, FALSE);
1541 gst_msdkenc_close_encoder (thiz);
1543 gst_video_codec_state_unref (thiz->input_state);
1545 thiz->input_state = gst_video_codec_state_ref (state);
1548 thiz->use_video_memory = TRUE;
1549 if (sinkpad_is_va (thiz))
1550 thiz->use_va = TRUE;
1552 thiz->use_video_memory = TRUE;
1553 if (sinkpad_is_d3d11 (thiz))
1554 thiz->use_d3d11 = TRUE;
1557 GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory",
1558 thiz->use_video_memory ? "video" : "system");
1560 if (klass->set_format) {
1561 if (!klass->set_format (thiz))
1565 /* If upstream supports DMABufCapsfeatures, then we request for the dmabuf
1566 * based pipeline usage. Ideally we should have dmabuf support even with
1567 * raw-caps negotiation, but we don't have dmabuf-import support in msdk
1569 /* If VA is set, we do not fallback to DMA. */
1570 if (!thiz->use_va && sinkpad_can_dmabuf (thiz)) {
1571 thiz->input_state->caps = gst_caps_make_writable (thiz->input_state->caps);
1572 gst_caps_set_features (thiz->input_state->caps, 0,
1573 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1574 thiz->use_dmabuf = TRUE;
1577 if (!gst_msdkenc_init_encoder (thiz))
1580 if (!gst_msdkenc_set_src_caps (thiz)) {
1581 gst_msdkenc_close_encoder (thiz);
1585 if (!thiz->msdk_pool) {
1586 guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1588 gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps,
1592 gst_msdkenc_set_latency (thiz);
1594 /* Create another bufferpool if VPP requires */
1595 if (thiz->has_vpp) {
1596 GstVideoInfo *info = &thiz->input_state->info;
1597 GstVideoInfo out_info;
1598 GstVideoFormat out_fmt;
1600 GstBufferPool *pool = NULL;
1602 gst_video_info_init (&out_info);
1604 gst_msdk_get_video_format_from_mfx_fourcc (thiz->vpp_param.vpp.
1606 gst_video_info_set_format (&out_info, out_fmt, info->width, info->height);
1607 caps = gst_video_info_to_caps (&out_info);
1609 /* If there's an existing pool try to reuse it when is compatible */
1610 if (thiz->msdk_converted_pool) {
1611 GstStructure *config;
1613 gboolean is_pool_compatible = FALSE;
1615 config = gst_buffer_pool_get_config (thiz->msdk_converted_pool);
1616 gst_buffer_pool_config_get_params (config, &pool_caps, NULL, NULL, NULL);
1617 if (caps && pool_caps)
1618 is_pool_compatible = gst_caps_is_equal (caps, pool_caps);
1619 gst_structure_free (config);
1621 /* If caps are the same then we are done */
1622 if (is_pool_compatible) {
1623 gst_caps_unref (caps);
1626 /* Release current pool because we are going to create a new one */
1627 gst_clear_object (&thiz->msdk_converted_pool);
1630 /* Otherwise create a new pool */
1632 gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE);
1634 thiz->msdk_converted_pool = pool;
1635 gst_caps_unref (caps);
1642 /* This function will be removed later */
1643 static GstMsdkSurface *
1644 gst_msdkenc_get_surface_from_pool_old (GstMsdkEnc * thiz, GstBufferPool * pool,
1645 GstBufferPoolAcquireParams * params)
1647 GstBuffer *new_buffer;
1648 GstMsdkSurface *msdk_surface = NULL;
1650 if (!gst_buffer_pool_is_active (pool) &&
1651 !gst_buffer_pool_set_active (pool, TRUE)) {
1652 GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
1656 if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
1657 GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
1661 msdk_surface = gst_msdk_import_to_msdk_surface (new_buffer, thiz->context,
1662 &thiz->aligned_info, 0);
1665 gst_msdk_import_sys_mem_to_msdk_surface (new_buffer, thiz->aligned_info);
1669 msdk_surface->buf = new_buffer;
1671 return msdk_surface;
1674 static GstMsdkSurface *
1675 gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz,
1676 GstVideoCodecFrame * frame, GstBuffer * buf)
1678 GstBuffer *upload_buf;
1679 GstMsdkSurface *msdk_surface = NULL;
1680 GstVideoFrame src_frame, dst_frame;
1682 if (!gst_buffer_pool_is_active (thiz->msdk_pool) &&
1683 !gst_buffer_pool_set_active (thiz->msdk_pool, TRUE)) {
1684 GST_ERROR_OBJECT (thiz->msdk_pool, "failed to activate buffer pool");
1688 if (gst_buffer_pool_acquire_buffer (thiz->msdk_pool, &upload_buf,
1689 NULL) != GST_FLOW_OK) {
1690 GST_ERROR_OBJECT (thiz->msdk_pool, "failed to acquire a buffer from pool");
1694 if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, buf,
1696 GST_WARNING ("Failed to map src frame");
1697 gst_buffer_unref (upload_buf);
1701 if (!gst_video_frame_map (&dst_frame, &thiz->aligned_info, upload_buf,
1703 GST_WARNING ("Failed to map dst frame");
1704 gst_video_frame_unmap (&src_frame);
1705 gst_buffer_unref (upload_buf);
1709 for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&src_frame); i++) {
1710 guint src_width_in_bytes, src_height;
1711 guint dst_width_in_bytes, dst_height;
1712 guint width_in_bytes, height;
1713 guint src_stride, dst_stride;
1714 guint8 *src_data, *dst_data;
1716 src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
1717 GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
1718 src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
1719 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&src_frame, i);
1721 dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
1722 GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
1723 dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
1724 dst_stride = GST_VIDEO_FRAME_COMP_STRIDE (&dst_frame, i);
1726 width_in_bytes = MIN (src_width_in_bytes, dst_width_in_bytes);
1727 height = MIN (src_height, dst_height);
1729 src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
1730 dst_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
1732 for (guint j = 0; j < height; j++) {
1733 memcpy (dst_data, src_data, width_in_bytes);
1734 dst_data += dst_stride;
1735 src_data += src_stride;
1739 gst_video_frame_unmap (&dst_frame);
1740 gst_video_frame_unmap (&src_frame);
1742 if (thiz->use_video_memory) {
1743 msdk_surface = gst_msdk_import_to_msdk_surface (upload_buf, thiz->context,
1744 &thiz->aligned_info, GST_MAP_READ);
1747 gst_msdk_import_sys_mem_to_msdk_surface (upload_buf,
1748 thiz->aligned_info);
1751 gst_buffer_replace (&frame->input_buffer, upload_buf);
1752 gst_buffer_unref (upload_buf);
1754 return msdk_surface;
1757 static GstMsdkSurface *
1758 gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
1759 GstVideoCodecFrame * frame)
1761 GstMsdkSurface *msdk_surface;
1764 inbuf = frame->input_buffer;
1765 if (gst_msdk_is_msdk_buffer (inbuf)) {
1766 msdk_surface = g_slice_new0 (GstMsdkSurface);
1767 msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
1768 return msdk_surface;
1771 msdk_surface = gst_msdk_import_to_msdk_surface (inbuf, thiz->context,
1772 &thiz->input_state->info, GST_MAP_READ);
1774 msdk_surface->buf = gst_buffer_ref (inbuf);
1775 return msdk_surface;
1778 /* If upstream hasn't accpeted the proposed msdk bufferpool,
1779 * just copy frame to msdk buffer and take a surface from it.
1782 return gst_msdkenc_get_surface_from_pool (thiz, frame, inbuf);
1785 static GstFlowReturn
1786 gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1788 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1789 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1790 GstVideoInfo *info = &thiz->input_state->info;
1792 GstMsdkSurface *surface;
1794 if (thiz->reconfig || klass->need_reconfig (thiz, frame)) {
1795 gst_msdkenc_flush_frames (thiz, FALSE);
1796 gst_msdkenc_close_encoder (thiz);
1798 klass->set_extra_params (thiz, frame);
1800 // This will reinitialized the encoder but keep same input format.
1801 gst_msdkenc_set_format (encoder, NULL);
1804 if (G_UNLIKELY (thiz->context == NULL))
1807 if (thiz->has_vpp) {
1808 GstMsdkSurface *vpp_surface;
1809 GstVideoFrame vframe;
1811 mfxSyncPoint vpp_sync_point = NULL;
1814 vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1816 goto invalid_surface;
1818 gst_msdkenc_get_surface_from_pool_old (thiz, thiz->msdk_converted_pool,
1821 goto invalid_surface;
1823 if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
1826 if (frame->pts != GST_CLOCK_TIME_NONE) {
1827 vpp_surface->surface->Data.TimeStamp =
1828 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1829 surface->surface->Data.TimeStamp =
1830 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1832 vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1833 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1836 session = gst_msdk_context_get_session (thiz->context);
1839 MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface,
1840 surface->surface, NULL, &vpp_sync_point);
1841 if (status != MFX_WRN_DEVICE_BUSY)
1843 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1847 gst_video_frame_unmap (&vframe);
1849 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1850 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Converting frame failed."),
1851 ("MSDK VPP error (%s)", msdk_status_to_string (status)));
1852 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1853 return GST_FLOW_ERROR;
1856 fdata = g_slice_new0 (FrameData);
1857 fdata->frame = gst_video_codec_frame_ref (frame);
1858 fdata->frame_surface = vpp_surface;
1859 fdata->converted_surface = surface;
1861 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
1863 surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1865 goto invalid_surface;
1867 fdata = gst_msdkenc_queue_frame (thiz, frame, info);
1871 fdata->frame_surface = surface;
1873 if (frame->pts != GST_CLOCK_TIME_NONE) {
1874 surface->surface->Data.TimeStamp =
1875 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1877 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1881 return gst_msdkenc_encode_frame (thiz, surface->surface, frame);
1886 GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1887 return GST_FLOW_NOT_NEGOTIATED;
1891 GST_ERROR_OBJECT (encoder, "Surface pool is full");
1892 return GST_FLOW_ERROR;
1896 GST_WARNING_OBJECT (encoder, "Failed to map frame");
1902 gst_msdkenc_context_prepare (GstMsdkEnc * thiz)
1904 /* Try to find an existing context from the pipeline. This may (indirectly)
1905 * invoke gst_msdkenc_set_context, which will set thiz->context. */
1906 if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
1909 if (thiz->context == thiz->old_context) {
1910 GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
1911 ", reusing as-is", thiz->context);
1915 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
1918 /* Check GST_MSDK_JOB_VPP and GST_MSDK_JOB_ENCODER together to avoid sharing context
1919 * between VPP and ENCODER
1921 * gst-launch-1.0 videotestsrc ! video/x-raw,format=I420 ! msdkh264enc ! \
1922 * msdkh264dec ! msdkvpp ! video/x-raw,format=YUY2 ! fakesink
1924 if (!(gst_msdk_context_get_job_type (thiz->context) & (GST_MSDK_JOB_VPP |
1925 GST_MSDK_JOB_ENCODER))) {
1926 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_ENCODER);
1930 /* Found an existing context that's already being used as an encoder, clone
1931 * the MFX session inside it to create a new one */
1933 GstMsdkContext *parent_context, *msdk_context;
1935 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
1936 "joined session", thiz->context);
1937 parent_context = thiz->context;
1938 msdk_context = gst_msdk_context_new_with_parent (parent_context);
1940 if (!msdk_context) {
1941 GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
1942 "as %" GST_PTR_FORMAT, parent_context);
1946 thiz->context = msdk_context;
1947 gst_object_unref (parent_context);
1954 gst_msdkenc_start (GstVideoEncoder * encoder)
1956 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1958 if (!gst_msdkenc_context_prepare (thiz)) {
1959 if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
1960 thiz->hardware, GST_MSDK_JOB_ENCODER, &thiz->context))
1962 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1966 /* Save the current context in a separate field so that we know whether it
1967 * has changed between calls to _start() */
1968 gst_object_replace ((GstObject **) & thiz->old_context,
1969 (GstObject *) thiz->context);
1971 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
1973 /* Set the minimum pts to some huge value (1000 hours). This keeps
1974 the dts at the start of the stream from needing to be
1976 gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
1982 gst_msdkenc_stop (GstVideoEncoder * encoder)
1984 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1986 gst_msdkenc_flush_frames (thiz, TRUE);
1987 gst_msdkenc_close_encoder (thiz);
1988 gst_msdkenc_dequeue_all_frames (thiz);
1990 if (thiz->input_state)
1991 gst_video_codec_state_unref (thiz->input_state);
1992 thiz->input_state = NULL;
1994 gst_clear_object (&thiz->context);
2000 gst_msdkenc_flush (GstVideoEncoder * encoder)
2002 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2004 GST_DEBUG_OBJECT (encoder, "flush and close encoder");
2006 gst_msdkenc_flush_frames (thiz, TRUE);
2007 gst_msdkenc_close_encoder (thiz);
2008 gst_msdkenc_dequeue_all_frames (thiz);
2010 gst_msdkenc_init_encoder (thiz);
2015 static GstFlowReturn
2016 gst_msdkenc_finish (GstVideoEncoder * encoder)
2018 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2020 gst_msdkenc_flush_frames (thiz, FALSE);
2027 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
2029 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2031 GstBufferPool *pool = NULL;
2032 GstAllocator *allocator = NULL;
2036 if (!thiz->input_state)
2039 gst_query_parse_allocation (query, &caps, NULL);
2042 GST_INFO_OBJECT (encoder, "failed to get caps");
2046 if (!gst_video_info_from_caps (&info, caps)) {
2047 GST_INFO_OBJECT (encoder, "failed to get video info");
2051 /* if upstream allocation query supports dmabuf-capsfeatures,
2052 * we do allocate dmabuf backed memory */
2053 if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
2054 GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
2055 thiz->use_dmabuf = TRUE;
2058 num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
2059 pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, FALSE);
2061 gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info),
2063 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2066 GstStructure *config;
2067 GstAllocationParams params = { 0, 31, 0, 0, };
2069 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
2071 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
2072 gst_query_add_allocation_param (query, allocator, ¶ms);
2073 gst_structure_free (config);
2076 gst_object_unref (pool);
2078 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
2083 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
2085 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2087 GstBufferPool *pool = NULL;
2088 GstD3D11Device *device;
2091 GstCapsFeatures *features;
2093 GstStructure *config;
2094 gboolean is_d3d11 = FALSE;
2096 if (!thiz->input_state)
2099 gst_query_parse_allocation (query, &caps, NULL);
2102 GST_INFO_OBJECT (encoder, "failed to get caps");
2106 if (!gst_video_info_from_caps (&info, caps)) {
2107 GST_INFO_OBJECT (encoder, "failed to get video info");
2111 features = gst_caps_get_features (caps, 0);
2112 if (features && gst_caps_features_contains (features,
2113 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
2114 GST_DEBUG_OBJECT (thiz, "upstream support d3d11 memory");
2115 device = gst_msdk_context_get_d3d11_device (thiz->context);
2116 pool = gst_d3d11_buffer_pool_new (device);
2119 pool = gst_video_buffer_pool_new ();
2122 config = gst_buffer_pool_get_config (pool);
2123 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
2126 GstD3D11AllocationParams *d3d11_params;
2127 GstVideoAlignment align;
2129 /* d3d11 buffer pool doesn't support generic video alignment
2130 * because memory layout of CPU accessible staging texture is uncontrollable.
2131 * Do D3D11 specific handling */
2132 gst_msdk_set_video_alignment (&info, 0, 0, &align);
2134 d3d11_params = gst_d3d11_allocation_params_new (device, &info,
2135 GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, 0);
2137 gst_d3d11_allocation_params_alignment (d3d11_params, &align);
2138 gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
2139 gst_d3d11_allocation_params_free (d3d11_params);
2141 gst_buffer_pool_config_add_option (config,
2142 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
2145 num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
2146 gst_buffer_pool_config_set_params (config,
2147 caps, GST_VIDEO_INFO_SIZE (&info), num_buffers, 0);
2148 gst_buffer_pool_set_config (pool, config);
2150 /* d3d11 buffer pool will update actual CPU accessible buffer size based on
2151 * allocated staging texture per gst_buffer_pool_set_config() call,
2152 * need query again to get the size */
2153 config = gst_buffer_pool_get_config (pool);
2154 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
2155 gst_structure_free (config);
2157 gst_query_add_allocation_pool (query, pool, size, num_buffers, 0);
2158 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2159 gst_object_unref (pool);
2166 gst_msdkenc_query (GstVideoEncoder * encoder, GstQuery * query,
2167 GstPadDirection dir)
2169 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
2170 gboolean ret = FALSE;
2172 switch (GST_QUERY_TYPE (query)) {
2173 case GST_QUERY_CONTEXT:{
2174 GstMsdkContext *msdk_context = NULL;
2176 gst_object_replace ((GstObject **) & msdk_context,
2177 (GstObject *) thiz->context);
2178 ret = gst_msdk_handle_context_query (GST_ELEMENT_CAST (encoder),
2179 query, msdk_context);
2180 gst_clear_object (&msdk_context);
2184 if (dir == GST_PAD_SRC) {
2186 GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
2189 GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
2198 gst_msdkenc_src_query (GstVideoEncoder * encoder, GstQuery * query)
2200 return gst_msdkenc_query (encoder, query, GST_PAD_SRC);
2204 gst_msdkenc_sink_query (GstVideoEncoder * encoder, GstQuery * query)
2206 return gst_msdkenc_query (encoder, query, GST_PAD_SINK);
2210 gst_msdkenc_dispose (GObject * object)
2212 GstMsdkEnc *thiz = GST_MSDKENC (object);
2214 if (thiz->input_state)
2215 gst_video_codec_state_unref (thiz->input_state);
2216 thiz->input_state = NULL;
2218 gst_clear_object (&thiz->msdk_pool);
2219 gst_clear_object (&thiz->msdk_converted_pool);
2220 gst_clear_object (&thiz->old_context);
2222 gst_clear_structure (&thiz->ext_coding_props);
2224 G_OBJECT_CLASS (parent_class)->dispose (object);
2228 gst_msdkenc_need_conversion (GstMsdkEnc * encoder, GstVideoInfo * info,
2229 GstVideoFormat * out_format)
2231 switch (GST_VIDEO_INFO_FORMAT (info)) {
2232 case GST_VIDEO_FORMAT_NV12:
2233 case GST_VIDEO_FORMAT_P010_10LE:
2234 case GST_VIDEO_FORMAT_VUYA:
2235 #if (MFX_VERSION >= 1027)
2236 case GST_VIDEO_FORMAT_Y410:
2237 case GST_VIDEO_FORMAT_Y210:
2242 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10)
2243 *out_format = GST_VIDEO_FORMAT_P010_10LE;
2245 *out_format = GST_VIDEO_FORMAT_NV12;
2251 gst_msdkenc_need_reconfig (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
2257 gst_msdkenc_set_extra_params (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
2263 gst_msdkenc_class_init (GstMsdkEncClass * klass)
2265 GObjectClass *gobject_class;
2266 GstElementClass *element_class;
2267 GstVideoEncoderClass *gstencoder_class;
2269 gobject_class = G_OBJECT_CLASS (klass);
2270 element_class = GST_ELEMENT_CLASS (klass);
2271 gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
2273 klass->need_conversion = gst_msdkenc_need_conversion;
2274 klass->need_reconfig = gst_msdkenc_need_reconfig;
2275 klass->set_extra_params = gst_msdkenc_set_extra_params;
2279 gobject_class->dispose = gst_msdkenc_dispose;
2281 element_class->set_context = gst_msdkenc_set_context;
2283 gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkenc_set_format);
2284 gstencoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkenc_handle_frame);
2285 gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkenc_start);
2286 gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkenc_stop);
2287 gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkenc_flush);
2288 gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkenc_finish);
2289 gstencoder_class->propose_allocation =
2290 GST_DEBUG_FUNCPTR (gst_msdkenc_propose_allocation);
2291 gstencoder_class->src_query = GST_DEBUG_FUNCPTR (gst_msdkenc_src_query);
2292 gstencoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_msdkenc_sink_query);
2294 gst_element_class_add_static_pad_template (element_class, &sink_factory);
2298 gst_msdkenc_init (GstMsdkEnc * thiz)
2300 thiz->hardware = PROP_HARDWARE_DEFAULT;
2301 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
2302 thiz->target_usage = PROP_TARGET_USAGE_DEFAULT;
2303 thiz->rate_control = PROP_RATE_CONTROL_DEFAULT;
2304 thiz->bitrate = PROP_BITRATE_DEFAULT;
2305 thiz->max_frame_size = PROP_MAX_FRAME_SIZE_DEFAULT;
2306 thiz->max_frame_size_i = PROP_MAX_FRAME_SIZE_I_DEFAULT;
2307 thiz->max_frame_size_p = PROP_MAX_FRAME_SIZE_P_DEFAULT;
2308 thiz->max_vbv_bitrate = PROP_MAX_VBV_BITRATE_DEFAULT;
2309 thiz->accuracy = PROP_AVBR_ACCURACY_DEFAULT;
2310 thiz->convergence = PROP_AVBR_ACCURACY_DEFAULT;
2311 thiz->lookahead_depth = PROP_RC_LOOKAHEAD_DEPTH_DEFAULT;
2312 thiz->qpi = PROP_QPI_DEFAULT;
2313 thiz->qpp = PROP_QPP_DEFAULT;
2314 thiz->qpb = PROP_QPB_DEFAULT;
2315 thiz->gop_size = PROP_GOP_SIZE_DEFAULT;
2316 thiz->ref_frames = PROP_REF_FRAMES_DEFAULT;
2317 thiz->i_frames = PROP_I_FRAMES_DEFAULT;
2318 thiz->b_frames = PROP_B_FRAMES_DEFAULT;
2319 thiz->num_slices = PROP_NUM_SLICES_DEFAULT;
2320 thiz->mbbrc = PROP_MBBRC_DEFAULT;
2321 thiz->lowdelay_brc = PROP_LOWDELAY_BRC_DEFAULT;
2322 thiz->adaptive_i = PROP_ADAPTIVE_I_DEFAULT;
2323 thiz->adaptive_b = PROP_ADAPTIVE_B_DEFAULT;
2325 thiz->ext_coding_props = gst_structure_new (EC_PROPS_STRUCT_NAME,
2326 EC_PROPS_EXTBRC, G_TYPE_STRING, "off", NULL);
2329 /* gst_msdkenc_set_common_property:
2331 * This is a helper function to set the common property
2332 * of base encoder from subclass implementation.
2335 gst_msdkenc_set_common_property (GObject * object, guint prop_id,
2336 const GValue * value, GParamSpec * pspec)
2338 GstMsdkEnc *thiz = GST_MSDKENC (object);
2340 gboolean ret = TRUE;
2342 GST_OBJECT_LOCK (thiz);
2344 state = GST_STATE (thiz);
2345 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
2346 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) {
2352 case GST_MSDKENC_PROP_HARDWARE:
2353 thiz->hardware = g_value_get_boolean (value);
2355 case GST_MSDKENC_PROP_ASYNC_DEPTH:
2356 thiz->async_depth = g_value_get_uint (value);
2358 case GST_MSDKENC_PROP_TARGET_USAGE:
2359 thiz->target_usage = g_value_get_uint (value);
2361 case GST_MSDKENC_PROP_RATE_CONTROL:
2362 thiz->rate_control = g_value_get_enum (value);
2364 case GST_MSDKENC_PROP_BITRATE:
2366 guint bitrate = g_value_get_uint (value);
2367 /* Ensure that bitrate changed before triggering a reconfig */
2368 if (bitrate != thiz->bitrate) {
2369 thiz->bitrate = bitrate;
2370 thiz->reconfig = TRUE;
2371 GST_DEBUG_OBJECT (thiz, "changed bitrate to %u", bitrate);
2375 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
2376 thiz->max_frame_size = g_value_get_uint (value);
2378 case GST_MSDKENC_PROP_MAX_FRAME_SIZE_I:
2379 thiz->max_frame_size_i = g_value_get_uint (value);
2381 case GST_MSDKENC_PROP_MAX_FRAME_SIZE_P:
2382 thiz->max_frame_size_p = g_value_get_uint (value);
2384 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
2385 thiz->max_vbv_bitrate = g_value_get_uint (value);
2387 case GST_MSDKENC_PROP_AVBR_ACCURACY:
2388 thiz->accuracy = g_value_get_uint (value);
2390 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
2391 thiz->convergence = g_value_get_uint (value);
2393 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
2394 thiz->lookahead_depth = g_value_get_uint (value);
2396 case GST_MSDKENC_PROP_QPI:
2397 thiz->qpi = g_value_get_uint (value);
2399 case GST_MSDKENC_PROP_QPP:
2400 thiz->qpp = g_value_get_uint (value);
2402 case GST_MSDKENC_PROP_QPB:
2403 thiz->qpb = g_value_get_uint (value);
2405 case GST_MSDKENC_PROP_GOP_SIZE:
2406 thiz->gop_size = g_value_get_uint (value);
2408 case GST_MSDKENC_PROP_REF_FRAMES:
2409 thiz->ref_frames = g_value_get_uint (value);
2411 case GST_MSDKENC_PROP_I_FRAMES:
2412 thiz->i_frames = g_value_get_uint (value);
2414 case GST_MSDKENC_PROP_B_FRAMES:
2415 thiz->b_frames = g_value_get_uint (value);
2417 case GST_MSDKENC_PROP_NUM_SLICES:
2418 thiz->num_slices = g_value_get_uint (value);
2420 case GST_MSDKENC_PROP_MBBRC:
2421 thiz->mbbrc = g_value_get_enum (value);
2423 case GST_MSDKENC_PROP_LOWDELAY_BRC:
2424 thiz->lowdelay_brc = g_value_get_enum (value);
2426 case GST_MSDKENC_PROP_ADAPTIVE_I:
2427 thiz->adaptive_i = g_value_get_enum (value);
2429 case GST_MSDKENC_PROP_ADAPTIVE_B:
2430 thiz->adaptive_b = g_value_get_enum (value);
2432 case GST_MSDKENC_PROP_EXT_CODING_PROPS:
2434 const GstStructure *s = gst_value_get_structure (value);
2435 const gchar *name = gst_structure_get_name (s);
2436 gst_structure_set_name (thiz->ext_coding_props, name);
2437 if (!structure_transform (s, thiz->ext_coding_props)) {
2438 GST_ERROR_OBJECT (thiz, "failed to transform structure");
2446 GST_OBJECT_UNLOCK (thiz);
2452 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
2453 GST_OBJECT_UNLOCK (thiz);
2458 /* gst_msdkenc_get_common_property:
2460 * This is a helper function to get the common property
2461 * of base encoder from subclass implementation.
2464 gst_msdkenc_get_common_property (GObject * object, guint prop_id,
2465 GValue * value, GParamSpec * pspec)
2467 GstMsdkEnc *thiz = GST_MSDKENC (object);
2468 gboolean ret = TRUE;
2470 GST_OBJECT_LOCK (thiz);
2472 case GST_MSDKENC_PROP_HARDWARE:
2473 g_value_set_boolean (value, thiz->hardware);
2475 case GST_MSDKENC_PROP_ASYNC_DEPTH:
2476 g_value_set_uint (value, thiz->async_depth);
2478 case GST_MSDKENC_PROP_TARGET_USAGE:
2479 g_value_set_uint (value, thiz->target_usage);
2481 case GST_MSDKENC_PROP_RATE_CONTROL:
2482 g_value_set_enum (value, thiz->rate_control);
2484 case GST_MSDKENC_PROP_BITRATE:
2485 g_value_set_uint (value, thiz->bitrate);
2487 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
2488 g_value_set_uint (value, thiz->max_frame_size);
2490 case GST_MSDKENC_PROP_MAX_FRAME_SIZE_I:
2491 g_value_set_uint (value, thiz->max_frame_size_i);
2493 case GST_MSDKENC_PROP_MAX_FRAME_SIZE_P:
2494 g_value_set_uint (value, thiz->max_frame_size_p);
2496 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
2497 g_value_set_uint (value, thiz->max_vbv_bitrate);
2499 case GST_MSDKENC_PROP_AVBR_ACCURACY:
2500 g_value_set_uint (value, thiz->accuracy);
2502 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
2503 g_value_set_uint (value, thiz->convergence);
2505 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
2506 g_value_set_uint (value, thiz->lookahead_depth);
2508 case GST_MSDKENC_PROP_QPI:
2509 g_value_set_uint (value, thiz->qpi);
2511 case GST_MSDKENC_PROP_QPP:
2512 g_value_set_uint (value, thiz->qpp);
2514 case GST_MSDKENC_PROP_QPB:
2515 g_value_set_uint (value, thiz->qpb);
2517 case GST_MSDKENC_PROP_GOP_SIZE:
2518 g_value_set_uint (value, thiz->gop_size);
2520 case GST_MSDKENC_PROP_REF_FRAMES:
2521 g_value_set_uint (value, thiz->ref_frames);
2523 case GST_MSDKENC_PROP_I_FRAMES:
2524 g_value_set_uint (value, thiz->i_frames);
2526 case GST_MSDKENC_PROP_B_FRAMES:
2527 g_value_set_uint (value, thiz->b_frames);
2529 case GST_MSDKENC_PROP_NUM_SLICES:
2530 g_value_set_uint (value, thiz->num_slices);
2532 case GST_MSDKENC_PROP_MBBRC:
2533 g_value_set_enum (value, thiz->mbbrc);
2535 case GST_MSDKENC_PROP_LOWDELAY_BRC:
2536 g_value_set_enum (value, thiz->lowdelay_brc);
2538 case GST_MSDKENC_PROP_ADAPTIVE_I:
2539 g_value_set_enum (value, thiz->adaptive_i);
2541 case GST_MSDKENC_PROP_ADAPTIVE_B:
2542 g_value_set_enum (value, thiz->adaptive_b);
2544 case GST_MSDKENC_PROP_EXT_CODING_PROPS:
2545 gst_value_set_structure (value, thiz->ext_coding_props);
2551 GST_OBJECT_UNLOCK (thiz);
2555 /* gst_msdkenc_install_common_properties:
2556 * @thiz: a #GstMsdkEnc
2558 * This is a helper function to install common properties
2559 * of base encoder from subclass implementation.
2560 * Encoders like jpeg do't require all the common properties
2561 * and they can avoid installing it into base gobject.
2564 gst_msdkenc_install_common_properties (GstMsdkEncClass * klass)
2566 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2567 GParamSpec *obj_properties[GST_MSDKENC_PROP_MAX] = { NULL, };
2568 guint qp_range_max = klass->qp_max;
2569 guint qp_range_min = klass->qp_min;
2571 obj_properties[GST_MSDKENC_PROP_HARDWARE] =
2572 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware encoders",
2573 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2575 obj_properties[GST_MSDKENC_PROP_ASYNC_DEPTH] =
2576 g_param_spec_uint ("async-depth", "Async Depth",
2577 "Depth of asynchronous pipeline",
2578 1, 20, PROP_ASYNC_DEPTH_DEFAULT,
2579 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2581 obj_properties[GST_MSDKENC_PROP_TARGET_USAGE] =
2582 g_param_spec_uint ("target-usage", "Target Usage",
2583 "1: Best quality, 4: Balanced, 7: Best speed",
2584 1, 7, PROP_TARGET_USAGE_DEFAULT,
2585 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2587 obj_properties[GST_MSDKENC_PROP_RATE_CONTROL] =
2588 g_param_spec_enum ("rate-control", "Rate Control",
2589 "Rate control method", gst_msdkenc_rate_control_get_type (),
2590 PROP_RATE_CONTROL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2592 obj_properties[GST_MSDKENC_PROP_BITRATE] =
2593 g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
2594 2000 * 1024, PROP_BITRATE_DEFAULT,
2595 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING);
2597 obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE] =
2598 g_param_spec_uint ("max-frame-size", "Max Frame Size",
2599 "Maximum possible size (in kbyte) of any compressed frames (0: auto-calculate)",
2600 0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_DEFAULT,
2601 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2603 obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE_I] =
2604 g_param_spec_uint ("max-frame-size-i", "Max Frame Size for I frame",
2605 "Maximum possible size (in kbyte) of I frames (0: auto-calculate)",
2606 0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_I_DEFAULT,
2607 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2609 obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE_P] =
2610 g_param_spec_uint ("max-frame-size-p", "Max Frame Size for P frame",
2611 "Maximum possible size (in kbyte) of P frames (0: auto-calculate)",
2612 0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_P_DEFAULT,
2613 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2615 /* Set the same upper bound with bitrate */
2616 obj_properties[GST_MSDKENC_PROP_MAX_VBV_BITRATE] =
2617 g_param_spec_uint ("max-vbv-bitrate", "Max VBV Bitrate",
2618 "Maximum bitrate(kbit/sec) at which data enters Video Buffering Verifier (0: auto-calculate)",
2619 0, 2000 * 1024, PROP_MAX_VBV_BITRATE_DEFAULT,
2620 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2622 obj_properties[GST_MSDKENC_PROP_AVBR_ACCURACY] =
2623 g_param_spec_uint ("accuracy", "Accuracy", "The AVBR Accuracy in "
2624 "the unit of tenth of percent", 0, G_MAXUINT16,
2625 PROP_AVBR_ACCURACY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2627 obj_properties[GST_MSDKENC_PROP_AVBR_CONVERGENCE] =
2628 g_param_spec_uint ("convergence", "Convergence",
2629 "The AVBR Convergence in the unit of 100 frames", 0, G_MAXUINT16,
2630 PROP_AVBR_CONVERGENCE_DEFAULT,
2631 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2633 obj_properties[GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH] =
2634 g_param_spec_uint ("rc-lookahead", "Look-ahead depth",
2635 "Number of frames to look ahead for Rate control", 10, 100,
2636 PROP_RC_LOOKAHEAD_DEPTH_DEFAULT,
2637 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2639 obj_properties[GST_MSDKENC_PROP_QPI] =
2640 g_param_spec_uint ("qpi", "QPI",
2641 "Constant quantizer for I frames (0 unlimited). Also used as "
2642 "ICQQuality or QVBRQuality for different RateControl methods",
2643 qp_range_min, qp_range_max, PROP_QPI_DEFAULT,
2644 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2646 obj_properties[GST_MSDKENC_PROP_QPP] =
2647 g_param_spec_uint ("qpp", "QPP",
2648 "Constant quantizer for P frames (0 unlimited)",
2649 qp_range_min, qp_range_max, PROP_QPP_DEFAULT,
2650 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2652 obj_properties[GST_MSDKENC_PROP_QPB] =
2653 g_param_spec_uint ("qpb", "QPB",
2654 "Constant quantizer for B frames (0 unlimited)",
2655 qp_range_min, qp_range_max, PROP_QPB_DEFAULT,
2656 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2658 obj_properties[GST_MSDKENC_PROP_GOP_SIZE] =
2659 g_param_spec_uint ("gop-size", "GOP Size", "GOP Size", 0,
2660 G_MAXINT, PROP_GOP_SIZE_DEFAULT,
2661 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2663 obj_properties[GST_MSDKENC_PROP_REF_FRAMES] =
2664 g_param_spec_uint ("ref-frames", "Reference Frames",
2665 "Number of reference frames",
2666 0, G_MAXINT, PROP_REF_FRAMES_DEFAULT,
2667 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2669 obj_properties[GST_MSDKENC_PROP_I_FRAMES] =
2670 g_param_spec_uint ("i-frames", "I Frames",
2671 "Number of I frames between IDR frames",
2672 0, G_MAXINT, PROP_I_FRAMES_DEFAULT,
2673 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2675 obj_properties[GST_MSDKENC_PROP_B_FRAMES] =
2676 g_param_spec_uint ("b-frames", "B Frames",
2677 "Number of B frames between I and P frames",
2678 0, G_MAXINT, PROP_B_FRAMES_DEFAULT,
2679 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2681 obj_properties[GST_MSDKENC_PROP_NUM_SLICES] =
2682 g_param_spec_uint ("num-slices", "Number of Slices",
2683 "Number of slices per frame, Zero tells the encoder to "
2684 "choose any slice partitioning allowed by the codec standard",
2685 0, G_MAXINT, PROP_NUM_SLICES_DEFAULT,
2686 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2688 obj_properties[GST_MSDKENC_PROP_MBBRC] =
2689 g_param_spec_enum ("mbbrc", "MB level bitrate control",
2690 "Macroblock level bitrate control",
2691 gst_msdkenc_mbbrc_get_type (),
2692 PROP_MBBRC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2694 obj_properties[GST_MSDKENC_PROP_LOWDELAY_BRC] =
2695 g_param_spec_enum ("lowdelay-brc", "Low delay bitrate control",
2696 "Bitrate control for low-delay user scenarios",
2697 gst_msdkenc_lowdelay_brc_get_type (),
2698 PROP_LOWDELAY_BRC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2700 obj_properties[GST_MSDKENC_PROP_ADAPTIVE_I] =
2701 g_param_spec_enum ("i-adapt", "Adaptive I-Frame Insertion",
2702 "Adaptive I-Frame Insertion control",
2703 gst_msdkenc_adaptive_i_get_type (),
2704 PROP_ADAPTIVE_I_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2706 obj_properties[GST_MSDKENC_PROP_ADAPTIVE_B] =
2707 g_param_spec_enum ("b-adapt", "Adaptive B-Frame Insertion",
2708 "Adaptive B-Frame Insertion control",
2709 gst_msdkenc_adaptive_b_get_type (),
2710 PROP_ADAPTIVE_B_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2713 * GstMsdkEnc:ext-coding-props
2715 * The properties for the external coding.
2717 * Supported properties:
2719 * extbrc : External bitrate control
2720 * String. Range: { auto, on, off } Default: off
2725 * ext-coding-props="props,extbrc=on"
2731 obj_properties[GST_MSDKENC_PROP_EXT_CODING_PROPS] =
2732 g_param_spec_boxed ("ext-coding-props", "External coding properties",
2733 "The properties for the external coding, refer to the hotdoc for the "
2734 "supported properties",
2735 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2737 g_object_class_install_properties (gobject_class,
2738 GST_MSDKENC_PROP_MAX, obj_properties);