2 * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * element-nvcudah265enc:
23 * NVIDIA CUDA mode H.265 encoder
29 * element-nvd3d11h265enc:
31 * NVIDIA Direct3D11 mode H.265 encoder
37 * element-nvautogpuh265enc:
39 * NVIDIA auto GPU select mode H.265 encoder
48 #include "gstnvh265encoder.h"
49 #include <gst/codecparsers/gsth265parser.h>
50 #include <gst/pbutils/codec-utils.h>
55 GST_DEBUG_CATEGORY_STATIC (gst_nv_h265_encoder_debug);
56 #define GST_CAT_DEFAULT gst_nv_h265_encoder_debug
58 static GTypeClass *parent_class = NULL;
74 /* rate-control params */
90 PROP_ZERO_REORDER_DELAY,
107 PROP_REPEAT_SEQUENCE_HEADER,
110 #define DEFAULT_PRESET GST_NV_ENCODER_PRESET_DEFAULT
111 #define DEFAULT_WEIGHTED_PRED FALSE
112 #define DEFAULT_GOP_SIZE 30
113 #define DEFAULT_B_FRAMES 0
114 #define DEFAULT_RATE_CONTROL GST_NV_ENCODER_RC_MODE_VBR
115 #define DEFAULT_QP -1
116 #define DEFAULT_BITRATE 0
117 #define DEFAULT_MAX_BITRATE 0
118 #define DEFAULT_VBV_BUFFER_SIZE 0
119 #define DEFAULT_RC_LOOKAHEAD 0
120 #define DEFAULT_I_ADAPT FALSE
121 #define DEFAULT_B_ADAPT FALSE
122 #define DEFAULT_SPATIAL_AQ FALSE
123 #define DEFAULT_TEMPORAL_AQ FALSE
124 #define DEFAULT_ZERO_REORDER_DELAY FALSE
125 #define DEFAULT_NON_REF_P FALSE
126 #define DEFAULT_STRICT_GOP FALSE
127 #define DEFAULT_AQ_STRENGTH FALSE
128 #define DEFAULT_CONST_QUALITY 0
129 #define DEFAULT_AUD TRUE
130 #define DEFAULT_REPEAT_SEQUENCE_HEADER FALSE
134 GST_NV_H265_ENCODER_BYTE_STREAM,
135 GST_NV_H265_ENCODER_HVC1,
136 GST_NV_H265_ENCODER_HEV1,
137 } GstNvH265EncoderStreamFormat;
139 typedef struct _GstNvH265Encoder
144 gboolean init_param_updated;
145 gboolean rc_param_updated;
146 gboolean bitrate_updated;
148 GstNvH265EncoderStreamFormat stream_format;
149 GstH265Parser *parser;
151 GstNvEncoderDeviceMode selected_device_mode;
154 guint cuda_device_id;
157 GstNvEncoderPreset preset;
158 gboolean weighted_pred;
163 GstNvEncoderRCMode rc_mode;
169 guint vbv_buffer_size;
174 gboolean temporal_aq;
175 gboolean zero_reorder_delay;
185 gdouble const_quality;
188 gboolean repeat_sequence_header;
191 typedef struct _GstNvH265EncoderClass
193 GstNvEncoderClass parent_class;
195 guint cuda_device_id;
198 GstNvEncoderDeviceMode device_mode;
200 /* representative device caps */
201 GstNvEncoderDeviceCaps device_caps;
203 /* auto gpu select mode */
204 guint cuda_device_id_list[8];
205 guint cuda_device_id_size;
207 gint64 adapter_luid_list[8];
208 guint adapter_luid_size;
209 } GstNvH265EncoderClass;
211 #define GST_NV_H265_ENCODER(object) ((GstNvH265Encoder *) (object))
212 #define GST_NV_H265_ENCODER_GET_CLASS(object) \
213 (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvH265EncoderClass))
215 static void gst_nv_h265_encoder_finalize (GObject * object);
216 static void gst_nv_h265_encoder_set_property (GObject * object, guint prop_id,
217 const GValue * value, GParamSpec * pspec);
218 static void gst_nv_h265_encoder_get_property (GObject * object, guint prop_id,
219 GValue * value, GParamSpec * pspec);
220 static GstCaps *gst_nv_h265_encoder_getcaps (GstVideoEncoder * encoder,
222 static gboolean gst_nv_h265_encoder_set_format (GstNvEncoder * encoder,
223 GstVideoCodecState * state, gpointer session,
224 NV_ENC_INITIALIZE_PARAMS * init_params, NV_ENC_CONFIG * config);
225 static gboolean gst_nv_h265_encoder_set_output_state (GstNvEncoder * encoder,
226 GstVideoCodecState * state, gpointer session);
227 static GstBuffer *gst_nv_h265_encoder_create_output_buffer (GstNvEncoder *
228 encoder, NV_ENC_LOCK_BITSTREAM * bitstream);
229 static GstNvEncoderReconfigure
230 gst_nv_h265_encoder_check_reconfigure (GstNvEncoder * encoder,
231 NV_ENC_CONFIG * config);
232 static gboolean gst_nv_h265_encoder_select_device (GstNvEncoder * encoder,
233 const GstVideoInfo * info, GstBuffer * buffer,
234 GstNvEncoderDeviceData * data);
237 gst_nv_h265_encoder_class_init (GstNvH265EncoderClass * klass, gpointer data)
239 GObjectClass *object_class = G_OBJECT_CLASS (klass);
240 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
241 GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
242 GstNvEncoderClass *nvenc_class = GST_NV_ENCODER_CLASS (klass);
243 GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) data;
244 GstNvEncoderDeviceCaps *dev_caps = &cdata->device_caps;
245 GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE |
246 GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS);
247 GParamFlags conditional_param_flags = (GParamFlags) (G_PARAM_READWRITE |
248 GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_PLAYING |
249 G_PARAM_STATIC_STRINGS);
251 parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
253 object_class->finalize = gst_nv_h265_encoder_finalize;
254 object_class->set_property = gst_nv_h265_encoder_set_property;
255 object_class->get_property = gst_nv_h265_encoder_get_property;
257 switch (cdata->device_mode) {
258 case GST_NV_ENCODER_DEVICE_CUDA:
259 g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
260 g_param_spec_uint ("cuda-device-id", "CUDA Device ID",
261 "CUDA device ID of associated GPU",
263 (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
264 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
266 case GST_NV_ENCODER_DEVICE_D3D11:
267 g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
268 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
269 "DXGI Adapter LUID (Locally Unique Identifier) of associated GPU",
270 G_MININT64, G_MAXINT64, 0,
271 (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
272 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
274 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
275 if (cdata->cuda_device_id_size > 0) {
276 g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
277 g_param_spec_uint ("cuda-device-id", "CUDA Device ID",
278 "CUDA device ID to use",
280 (GParamFlags) (conditional_param_flags |
281 GST_PARAM_DOC_SHOW_DEFAULT)));
283 if (cdata->adapter_luid_size > 0) {
284 g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
285 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
286 "DXGI Adapter LUID (Locally Unique Identifier) to use",
287 G_MININT64, G_MAXINT64, 0,
288 (GParamFlags) (conditional_param_flags |
289 GST_PARAM_DOC_SHOW_DEFAULT)));
293 g_assert_not_reached ();
297 g_object_class_install_property (object_class, PROP_PRESET,
298 g_param_spec_enum ("preset", "Encoding Preset",
299 "Encoding Preset", GST_TYPE_NV_ENCODER_PRESET,
300 DEFAULT_PRESET, param_flags));
301 if (dev_caps->weighted_prediction) {
302 g_object_class_install_property (object_class, PROP_WEIGHTED_PRED,
303 g_param_spec_boolean ("weighted-pred", "Weighted Pred",
304 "Enables Weighted Prediction", DEFAULT_WEIGHTED_PRED,
305 conditional_param_flags));
307 g_object_class_install_property (object_class, PROP_GOP_SIZE,
308 g_param_spec_int ("gop-size", "GOP size",
309 "Number of frames between intra frames (-1 = infinite)",
310 -1, G_MAXINT, DEFAULT_GOP_SIZE, param_flags));
311 if (dev_caps->max_bframes > 0) {
312 g_object_class_install_property (object_class, PROP_B_FRAMES,
313 g_param_spec_uint ("b-frames", "B-Frames",
314 "Number of B-frames between I and P", 0, dev_caps->max_bframes,
315 DEFAULT_B_FRAMES, conditional_param_flags));
317 g_object_class_install_property (object_class, PROP_RATE_CONTROL,
318 g_param_spec_enum ("rate-control", "Rate Control", "Rate Control Method",
319 GST_TYPE_NV_ENCODER_RC_MODE, DEFAULT_RATE_CONTROL, param_flags));
320 g_object_class_install_property (object_class, PROP_QP_I,
321 g_param_spec_int ("qp-i", "QP I",
322 "Constant QP value for I frame (-1 = default)", -1, 51,
323 DEFAULT_QP, param_flags));
324 g_object_class_install_property (object_class, PROP_QP_P,
325 g_param_spec_int ("qp-p", "QP P",
326 "Constant QP value for P frame (-1 = default)", -1, 51,
327 DEFAULT_QP, param_flags));
328 g_object_class_install_property (object_class, PROP_QP_B,
329 g_param_spec_int ("qp-b", "QP B",
330 "Constant QP value for B frame (-1 = default)", -1, 51,
331 DEFAULT_QP, param_flags));
332 g_object_class_install_property (object_class, PROP_BITRATE,
333 g_param_spec_uint ("bitrate", "Bitrate",
334 "Bitrate in kbit/sec (0 = automatic)", 0, 2000 * 1024,
335 DEFAULT_BITRATE, param_flags));
336 g_object_class_install_property (object_class, PROP_MAX_BITRATE,
337 g_param_spec_uint ("max-bitrate", "Max Bitrate",
338 "Maximum Bitrate in kbit/sec (ignored in CBR mode)", 0, 2000 * 1024,
339 DEFAULT_MAX_BITRATE, param_flags));
340 if (dev_caps->custom_vbv_buf_size) {
341 g_object_class_install_property (object_class,
342 PROP_VBV_BUFFER_SIZE,
343 g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
344 "VBV(HRD) Buffer Size in kbits (0 = NVENC default)",
345 0, G_MAXUINT, DEFAULT_VBV_BUFFER_SIZE, conditional_param_flags));
347 if (dev_caps->lookahead) {
348 g_object_class_install_property (object_class, PROP_RC_LOOKAHEAD,
349 g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead",
350 "Number of frames for frame type lookahead",
351 0, 32, DEFAULT_RC_LOOKAHEAD, conditional_param_flags));
352 g_object_class_install_property (object_class, PROP_I_ADAPT,
353 g_param_spec_boolean ("i-adapt", "I Adapt",
354 "Enable adaptive I-frame insert when lookahead is enabled",
355 DEFAULT_I_ADAPT, conditional_param_flags));
356 if (dev_caps->max_bframes > 0) {
357 g_object_class_install_property (object_class, PROP_B_ADAPT,
358 g_param_spec_boolean ("b-adapt", "B Adapt",
359 "Enable adaptive B-frame insert when lookahead is enabled",
360 DEFAULT_B_ADAPT, conditional_param_flags));
363 g_object_class_install_property (object_class, PROP_SPATIAL_AQ,
364 g_param_spec_boolean ("spatial-aq", "Spatial AQ",
365 "Spatial Adaptive Quantization", DEFAULT_SPATIAL_AQ, param_flags));
366 if (dev_caps->temporal_aq) {
367 g_object_class_install_property (object_class, PROP_TEMPORAL_AQ,
368 g_param_spec_boolean ("temporal-aq", "Temporal AQ",
369 "Temporal Adaptive Quantization", DEFAULT_TEMPORAL_AQ,
370 conditional_param_flags));
372 g_object_class_install_property (object_class, PROP_ZERO_REORDER_DELAY,
373 g_param_spec_boolean ("zero-reorder-delay", "Zero Reorder Delay",
374 "Zero latency operation (i.e., num_reorder_frames = 0)",
375 DEFAULT_ZERO_REORDER_DELAY, param_flags));
376 g_object_class_install_property (object_class, PROP_NON_REF_P,
377 g_param_spec_boolean ("nonref-p", "Nonref P",
378 "Automatic insertion of non-reference P-frames", DEFAULT_NON_REF_P,
380 g_object_class_install_property (object_class, PROP_STRICT_GOP,
381 g_param_spec_boolean ("strict-gop", "Strict GOP",
382 "Minimize GOP-to-GOP rate fluctuations", DEFAULT_STRICT_GOP,
384 g_object_class_install_property (object_class, PROP_AQ_STRENGTH,
385 g_param_spec_uint ("aq-strength", "AQ Strength",
386 "Adaptive Quantization Strength when spatial-aq is enabled"
387 " from 1 (low) to 15 (aggressive), (0 = autoselect)",
388 0, 15, DEFAULT_AQ_STRENGTH, param_flags));
389 g_object_class_install_property (object_class, PROP_MIN_QP_I,
390 g_param_spec_int ("min-qp-i", "Min QP I",
391 "Minimum QP value for I frame, (-1 = disabled)", -1, 51,
392 DEFAULT_QP, param_flags));
393 g_object_class_install_property (object_class, PROP_MIN_QP_P,
394 g_param_spec_int ("min-qp-p", "Min QP P",
395 "Minimum QP value for P frame, (-1 = automatic)", -1, 51,
396 DEFAULT_QP, param_flags));
397 g_object_class_install_property (object_class, PROP_MIN_QP_B,
398 g_param_spec_int ("min-qp-b", "Min QP B",
399 "Minimum QP value for B frame, (-1 = automatic)", -1, 51,
400 DEFAULT_QP, param_flags));
401 g_object_class_install_property (object_class, PROP_MAX_QP_I,
402 g_param_spec_int ("max-qp-i", "Max QP I",
403 "Maximum QP value for I frame, (-1 = disabled)", -1, 51,
404 DEFAULT_QP, param_flags));
405 g_object_class_install_property (object_class, PROP_MAX_QP_P,
406 g_param_spec_int ("max-qp-p", "Max QP P",
407 "Maximum QP value for P frame, (-1 = automatic)", -1, 51,
408 DEFAULT_QP, param_flags));
409 g_object_class_install_property (object_class, PROP_MAX_QP_B,
410 g_param_spec_int ("max-qp-b", "Max QP B",
411 "Maximum QP value for B frame, (-1 = automatic)", -1, 51,
412 DEFAULT_QP, param_flags));
413 g_object_class_install_property (object_class, PROP_CONST_QUALITY,
414 g_param_spec_double ("const-quality", "Constant Quality",
415 "Target Constant Quality level for VBR mode (0 = automatic)",
416 0, 51, DEFAULT_CONST_QUALITY, param_flags));
417 g_object_class_install_property (object_class, PROP_AUD,
418 g_param_spec_boolean ("aud", "AUD",
419 "Use AU (Access Unit) delimiter", DEFAULT_AUD, param_flags));
420 g_object_class_install_property (object_class, PROP_REPEAT_SEQUENCE_HEADER,
421 g_param_spec_boolean ("repeat-sequence-header", "Repeat Sequence Header",
422 "Insert sequence headers (SPS/PPS) per IDR, "
423 "ignored if negotiated stream-format is \"hvc1\"",
424 DEFAULT_REPEAT_SEQUENCE_HEADER, param_flags));
426 switch (cdata->device_mode) {
427 case GST_NV_ENCODER_DEVICE_CUDA:
428 gst_element_class_set_static_metadata (element_class,
429 "NVENC H.265 Video Encoder CUDA Mode",
430 "Codec/Encoder/Video/Hardware",
431 "Encode H.265 video streams using NVCODEC API CUDA Mode",
432 "Seungha Yang <seungha@centricular.com>");
434 case GST_NV_ENCODER_DEVICE_D3D11:
435 gst_element_class_set_static_metadata (element_class,
436 "NVENC H.265 Video Encoder Direct3D11 Mode",
437 "Codec/Encoder/Video/Hardware",
438 "Encode H.265 video streams using NVCODEC API Direct3D11 Mode",
439 "Seungha Yang <seungha@centricular.com>");
441 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
442 gst_element_class_set_static_metadata (element_class,
443 "NVENC H.265 Video Encoder Auto GPU select Mode",
444 "Codec/Encoder/Video/Hardware",
445 "Encode H.265 video streams using NVCODEC API auto GPU select Mode",
446 "Seungha Yang <seungha@centricular.com>");
449 g_assert_not_reached ();
453 gst_element_class_add_pad_template (element_class,
454 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
456 gst_element_class_add_pad_template (element_class,
457 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
460 videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_getcaps);
462 nvenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_set_format);
463 nvenc_class->set_output_state =
464 GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_set_output_state);
465 nvenc_class->create_output_buffer =
466 GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_create_output_buffer);
467 nvenc_class->check_reconfigure =
468 GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_check_reconfigure);
469 nvenc_class->select_device =
470 GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_select_device);
472 klass->device_caps = cdata->device_caps;
473 klass->cuda_device_id = cdata->cuda_device_id;
474 klass->adapter_luid = cdata->adapter_luid;
475 klass->device_mode = cdata->device_mode;
476 klass->cuda_device_id_size = cdata->cuda_device_id_size;
477 klass->adapter_luid_size = cdata->adapter_luid_size;
478 memcpy (klass->cuda_device_id_list, cdata->cuda_device_id_list,
479 sizeof (klass->cuda_device_id_list));
480 memcpy (klass->adapter_luid_list, cdata->adapter_luid_list,
481 sizeof (klass->adapter_luid_list));
483 gst_nv_encoder_class_data_unref (cdata);
487 gst_nv_h265_encoder_init (GstNvH265Encoder * self)
489 GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
491 g_mutex_init (&self->prop_lock);
493 self->selected_device_mode = klass->device_mode;
494 self->cuda_device_id = klass->cuda_device_id;
495 self->adapter_luid = klass->adapter_luid;
496 self->preset = DEFAULT_PRESET;
497 self->weighted_pred = DEFAULT_WEIGHTED_PRED;
498 self->gop_size = DEFAULT_GOP_SIZE;
499 self->bframes = DEFAULT_B_FRAMES;
500 self->rc_mode = DEFAULT_RATE_CONTROL;
501 self->qp_i = DEFAULT_QP;
502 self->qp_p = DEFAULT_QP;
503 self->qp_b = DEFAULT_QP;
504 self->bitrate = DEFAULT_BITRATE;
505 self->max_bitrate = DEFAULT_MAX_BITRATE;
506 self->vbv_buffer_size = DEFAULT_VBV_BUFFER_SIZE;
507 self->rc_lookahead = DEFAULT_RC_LOOKAHEAD;
508 self->i_adapt = DEFAULT_I_ADAPT;
509 self->b_adapt = DEFAULT_B_ADAPT;
510 self->spatial_aq = DEFAULT_SPATIAL_AQ;
511 self->temporal_aq = DEFAULT_TEMPORAL_AQ;
512 self->zero_reorder_delay = DEFAULT_ZERO_REORDER_DELAY;
513 self->non_ref_p = DEFAULT_NON_REF_P;
514 self->strict_gop = DEFAULT_STRICT_GOP;
515 self->aq_strength = DEFAULT_AQ_STRENGTH;
516 self->min_qp_i = DEFAULT_QP;
517 self->min_qp_p = DEFAULT_QP;
518 self->min_qp_b = DEFAULT_QP;
519 self->max_qp_i = DEFAULT_QP;
520 self->max_qp_p = DEFAULT_QP;
521 self->max_qp_b = DEFAULT_QP;
522 self->const_quality = DEFAULT_CONST_QUALITY;
523 self->aud = DEFAULT_AUD;
524 self->repeat_sequence_header = DEFAULT_REPEAT_SEQUENCE_HEADER;
526 self->parser = gst_h265_parser_new ();
528 gst_nv_encoder_set_device_mode (GST_NV_ENCODER (self), klass->device_mode,
529 klass->cuda_device_id, klass->adapter_luid);
533 gst_nv_h265_encoder_finalize (GObject * object)
535 GstNvH265Encoder *self = GST_NV_H265_ENCODER (object);
537 g_mutex_clear (&self->prop_lock);
538 gst_h265_parser_free (self->parser);
540 G_OBJECT_CLASS (parent_class)->finalize (object);
551 update_boolean (GstNvH265Encoder * self, gboolean * old_val,
552 const GValue * new_val, PropUpdateLevel level)
554 gboolean val = g_value_get_boolean (new_val);
561 case UPDATE_INIT_PARAM:
562 self->init_param_updated = TRUE;
564 case UPDATE_RC_PARAM:
565 self->rc_param_updated = TRUE;
568 self->bitrate_updated = TRUE;
574 update_int (GstNvH265Encoder * self, gint * old_val,
575 const GValue * new_val, PropUpdateLevel level)
577 gint val = g_value_get_int (new_val);
584 case UPDATE_INIT_PARAM:
585 self->init_param_updated = TRUE;
587 case UPDATE_RC_PARAM:
588 self->rc_param_updated = TRUE;
591 self->bitrate_updated = TRUE;
597 update_uint (GstNvH265Encoder * self, guint * old_val,
598 const GValue * new_val, PropUpdateLevel level)
600 guint val = g_value_get_uint (new_val);
607 case UPDATE_INIT_PARAM:
608 self->init_param_updated = TRUE;
610 case UPDATE_RC_PARAM:
611 self->rc_param_updated = TRUE;
614 self->bitrate_updated = TRUE;
620 update_double (GstNvH265Encoder * self, gdouble * old_val,
621 const GValue * new_val, PropUpdateLevel level)
623 gdouble val = g_value_get_double (new_val);
630 case UPDATE_INIT_PARAM:
631 self->init_param_updated = TRUE;
633 case UPDATE_RC_PARAM:
634 self->rc_param_updated = TRUE;
637 self->bitrate_updated = TRUE;
643 gst_nv_h265_encoder_set_property (GObject * object, guint prop_id,
644 const GValue * value, GParamSpec * pspec)
646 GstNvH265Encoder *self = GST_NV_H265_ENCODER (object);
647 GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
649 g_mutex_lock (&self->prop_lock);
651 case PROP_ADAPTER_LUID:{
652 gint64 adapter_luid = g_value_get_int64 (value);
653 gboolean is_valid = FALSE;
655 for (guint i = 0; i < klass->adapter_luid_size; i++) {
656 if (klass->adapter_luid_list[i] == adapter_luid) {
657 self->adapter_luid = adapter_luid;
664 g_warning ("%" G_GINT64_FORMAT " is not a valid adapter luid",
668 case PROP_CUDA_DEVICE_ID:{
669 guint cuda_device_id = g_value_get_uint (value);
670 gboolean is_valid = FALSE;
672 for (guint i = 0; i < klass->cuda_device_id_size; i++) {
673 if (klass->cuda_device_id_list[i] == cuda_device_id) {
674 self->cuda_device_id = cuda_device_id;
681 g_warning ("%d is not a valid cuda device id", cuda_device_id);
685 GstNvEncoderPreset preset = (GstNvEncoderPreset) g_value_get_enum (value);
686 if (preset != self->preset) {
687 self->preset = preset;
688 self->init_param_updated = TRUE;
692 case PROP_WEIGHTED_PRED:
693 update_boolean (self, &self->weighted_pred, value, UPDATE_INIT_PARAM);
696 update_int (self, &self->gop_size, value, UPDATE_INIT_PARAM);
699 update_uint (self, &self->bframes, value, UPDATE_INIT_PARAM);
701 case PROP_RATE_CONTROL:{
702 GstNvEncoderRCMode mode = (GstNvEncoderRCMode) g_value_get_enum (value);
703 if (mode != self->rc_mode) {
704 self->rc_mode = mode;
705 self->rc_param_updated = TRUE;
710 update_int (self, &self->qp_i, value, UPDATE_RC_PARAM);
713 update_int (self, &self->qp_p, value, UPDATE_RC_PARAM);
716 update_int (self, &self->qp_b, value, UPDATE_RC_PARAM);
719 update_uint (self, &self->bitrate, value, UPDATE_BITRATE);
721 case PROP_MAX_BITRATE:
722 update_uint (self, &self->max_bitrate, value, UPDATE_BITRATE);
724 case PROP_VBV_BUFFER_SIZE:
725 update_uint (self, &self->vbv_buffer_size, value, UPDATE_RC_PARAM);
727 case PROP_RC_LOOKAHEAD:
728 /* rc-lookahead update requires pool size change */
729 update_uint (self, &self->rc_lookahead, value, UPDATE_INIT_PARAM);
732 update_boolean (self, &self->i_adapt, value, UPDATE_RC_PARAM);
735 update_boolean (self, &self->b_adapt, value, UPDATE_RC_PARAM);
737 case PROP_SPATIAL_AQ:
738 update_boolean (self, &self->spatial_aq, value, UPDATE_RC_PARAM);
740 case PROP_TEMPORAL_AQ:
741 update_boolean (self, &self->temporal_aq, value, UPDATE_RC_PARAM);
743 case PROP_ZERO_REORDER_DELAY:
744 update_boolean (self, &self->zero_reorder_delay, value, UPDATE_RC_PARAM);
747 update_boolean (self, &self->non_ref_p, value, UPDATE_RC_PARAM);
749 case PROP_STRICT_GOP:
750 update_boolean (self, &self->strict_gop, value, UPDATE_RC_PARAM);
752 case PROP_AQ_STRENGTH:
753 update_uint (self, &self->aq_strength, value, UPDATE_RC_PARAM);
756 update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
759 update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
762 update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
765 update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
768 update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
771 update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
773 case PROP_CONST_QUALITY:
774 update_double (self, &self->const_quality, value, UPDATE_RC_PARAM);
777 update_boolean (self, &self->aud, value, UPDATE_INIT_PARAM);
779 case PROP_REPEAT_SEQUENCE_HEADER:
780 update_boolean (self,
781 &self->repeat_sequence_header, value, UPDATE_INIT_PARAM);
784 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
788 g_mutex_unlock (&self->prop_lock);
792 gst_nv_h265_encoder_get_property (GObject * object, guint prop_id,
793 GValue * value, GParamSpec * pspec)
795 GstNvH265Encoder *self = GST_NV_H265_ENCODER (object);
798 case PROP_ADAPTER_LUID:
799 g_value_set_int64 (value, self->adapter_luid);
801 case PROP_CUDA_DEVICE_ID:
802 g_value_set_uint (value, self->cuda_device_id);
805 g_value_set_enum (value, self->preset);
807 case PROP_WEIGHTED_PRED:
808 g_value_set_boolean (value, self->weighted_pred);
811 g_value_set_int (value, self->gop_size);
814 g_value_set_uint (value, self->bframes);
816 case PROP_RATE_CONTROL:
817 g_value_set_enum (value, self->rc_mode);
820 g_value_set_int (value, self->qp_i);
823 g_value_set_int (value, self->qp_p);
826 g_value_set_int (value, self->qp_b);
829 g_value_set_uint (value, self->bitrate);
831 case PROP_MAX_BITRATE:
832 g_value_set_uint (value, self->max_bitrate);
834 case PROP_VBV_BUFFER_SIZE:
835 g_value_set_uint (value, self->vbv_buffer_size);
837 case PROP_RC_LOOKAHEAD:
838 g_value_set_uint (value, self->rc_lookahead);
841 g_value_set_boolean (value, self->i_adapt);
844 g_value_set_boolean (value, self->b_adapt);
846 case PROP_SPATIAL_AQ:
847 g_value_set_boolean (value, self->spatial_aq);
849 case PROP_TEMPORAL_AQ:
850 g_value_set_boolean (value, self->temporal_aq);
852 case PROP_ZERO_REORDER_DELAY:
853 g_value_set_boolean (value, self->zero_reorder_delay);
856 g_value_set_boolean (value, self->non_ref_p);
858 case PROP_STRICT_GOP:
859 g_value_set_boolean (value, self->strict_gop);
861 case PROP_AQ_STRENGTH:
862 g_value_set_uint (value, self->aq_strength);
865 g_value_set_int (value, self->min_qp_i);
868 g_value_set_int (value, self->min_qp_p);
871 g_value_set_int (value, self->min_qp_b);
874 g_value_set_int (value, self->max_qp_i);
877 g_value_set_int (value, self->max_qp_p);
880 g_value_set_int (value, self->max_qp_b);
882 case PROP_CONST_QUALITY:
883 g_value_set_double (value, self->const_quality);
886 g_value_set_boolean (value, self->aud);
888 case PROP_REPEAT_SEQUENCE_HEADER:
889 g_value_set_boolean (value, self->repeat_sequence_header);
892 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
898 gst_nv_h265_encoder_get_downstream_profiles_and_format (GstNvH265Encoder * self,
899 std::set < std::string > &downstream_profiles,
900 GstNvH265EncoderStreamFormat * format)
902 GstCaps *allowed_caps;
904 const gchar *stream_format;
906 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
908 if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
909 gst_caps_is_any (allowed_caps)) {
910 gst_clear_caps (&allowed_caps);
915 for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
916 const GValue *profile_value;
917 const gchar *profile;
919 s = gst_caps_get_structure (allowed_caps, i);
920 profile_value = gst_structure_get_value (s, "profile");
924 if (GST_VALUE_HOLDS_LIST (profile_value)) {
925 for (guint j = 0; j < gst_value_list_get_size (profile_value); j++) {
926 const GValue *p = gst_value_list_get_value (profile_value, j);
928 if (!G_VALUE_HOLDS_STRING (p))
931 profile = g_value_get_string (p);
933 downstream_profiles.insert (profile);
936 } else if (G_VALUE_HOLDS_STRING (profile_value)) {
937 profile = g_value_get_string (profile_value);
939 downstream_profiles.insert (profile);
944 *format = GST_NV_H265_ENCODER_BYTE_STREAM;
946 allowed_caps = gst_caps_fixate (allowed_caps);
947 s = gst_caps_get_structure (allowed_caps, 0);
948 stream_format = gst_structure_get_string (s, "stream-format");
949 if (g_strcmp0 (stream_format, "hvc1") == 0)
950 *format = GST_NV_H265_ENCODER_HVC1;
951 else if (g_strcmp0 (stream_format, "hev1") == 0)
952 *format = GST_NV_H265_ENCODER_HEV1;
955 gst_caps_unref (allowed_caps);
959 gst_nv_h265_encoder_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
961 GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
962 GstCaps *template_caps;
963 GstCaps *supported_caps;
964 std::set < std::string > downstream_profiles;
965 std::set < std::string > allowed_formats;
967 gst_nv_h265_encoder_get_downstream_profiles_and_format (self,
968 downstream_profiles, NULL);
970 GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
971 downstream_profiles.size ());
973 if (downstream_profiles.size () == 0)
974 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
977 for (const auto &iter: downstream_profiles) {
978 if (iter == "main") {
979 allowed_formats.insert("NV12");
980 } else if (iter == "main-10") {
981 allowed_formats.insert("P010_10LE");
982 } else if (iter == "main-444") {
983 allowed_formats.insert("Y444");
984 } else if (iter == "main-444-10") {
985 allowed_formats.insert("Y444_16LE");
990 template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
991 template_caps = gst_caps_make_writable (template_caps);
993 GValue formats = G_VALUE_INIT;
995 g_value_init (&formats, GST_TYPE_LIST);
997 for (const auto &iter: allowed_formats) {
998 GValue val = G_VALUE_INIT;
999 g_value_init (&val, G_TYPE_STRING);
1001 g_value_set_string (&val, iter.c_str());
1002 gst_value_list_append_and_take_value (&formats, &val);
1006 gst_caps_set_value (template_caps, "format", &formats);
1007 g_value_unset (&formats);
1009 supported_caps = gst_video_encoder_proxy_getcaps (encoder,
1010 template_caps, filter);
1011 gst_caps_unref (template_caps);
1013 GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
1015 return supported_caps;
1019 gst_nv_h265_encoder_set_format (GstNvEncoder * encoder,
1020 GstVideoCodecState * state, gpointer session,
1021 NV_ENC_INITIALIZE_PARAMS * init_params, NV_ENC_CONFIG * config)
1023 GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1024 GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
1025 GstNvEncoderDeviceCaps *dev_caps = &klass->device_caps;
1026 NV_ENC_RC_PARAMS *rc_params;
1027 GstVideoInfo *info = &state->info;
1029 NV_ENC_PRESET_CONFIG preset_config = { 0, };
1031 GstNvEncoderRCMode rc_mode;
1032 NV_ENC_CONFIG_HEVC *hevc_config;
1033 NV_ENC_CONFIG_HEVC_VUI_PARAMETERS *vui;
1034 std::set < std::string > downstream_profiles;
1035 GUID selected_profile = NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID;
1036 guint chroma_format_index = 1;
1037 guint bitdepth_minus8 = 0;
1038 gboolean bframe_aborted = FALSE;
1039 gboolean weight_pred_aborted = FALSE;
1040 gboolean vbv_buffer_size_aborted = FALSE;
1041 gboolean lookahead_aborted = FALSE;
1042 gboolean temporal_aq_aborted = FALSE;
1044 self->stream_format = GST_NV_H265_ENCODER_BYTE_STREAM;
1046 gst_nv_h265_encoder_get_downstream_profiles_and_format (self,
1047 downstream_profiles, &self->stream_format);
1049 if (downstream_profiles.empty ()) {
1050 GST_ERROR_OBJECT (self, "Unable to get downstream profile");
1054 /* XXX: we may need to relax condition a little */
1055 switch (GST_VIDEO_INFO_FORMAT (info)) {
1056 case GST_VIDEO_FORMAT_NV12:
1057 if (downstream_profiles.find ("main") == downstream_profiles.end ()) {
1058 GST_ERROR_OBJECT (self, "Downstream does not support main profile");
1061 selected_profile = NV_ENC_HEVC_PROFILE_MAIN_GUID;
1064 case GST_VIDEO_FORMAT_P010_10LE:
1065 if (downstream_profiles.find ("main-10") == downstream_profiles.end ()) {
1066 GST_ERROR_OBJECT (self, "Downstream does not support main profile");
1069 selected_profile = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
1070 bitdepth_minus8 = 2;
1073 case GST_VIDEO_FORMAT_Y444:
1074 if (downstream_profiles.find ("main-444") == downstream_profiles.end ()) {
1075 GST_ERROR_OBJECT (self, "Downstream does not support 4:4:4 profile");
1078 selected_profile = NV_ENC_HEVC_PROFILE_FREXT_GUID;
1079 chroma_format_index = 3;
1082 case GST_VIDEO_FORMAT_Y444_16LE:
1083 if (downstream_profiles.find ("main-444-10") ==
1084 downstream_profiles.end ()) {
1085 GST_ERROR_OBJECT (self,
1086 "Downstream does not support 4:4:4 10bits profile");
1089 selected_profile = NV_ENC_HEVC_PROFILE_FREXT_GUID;
1090 chroma_format_index = 3;
1091 bitdepth_minus8 = 2;
1095 GST_ERROR_OBJECT (self, "Unexpected format %s",
1096 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
1097 g_assert_not_reached ();
1101 g_mutex_lock (&self->prop_lock);
1103 if (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1104 GstNvEncoderDeviceCaps dev_caps;
1106 gst_nv_encoder_get_encoder_caps (session,
1107 &NV_ENC_CODEC_HEVC_GUID, &dev_caps);
1109 if (self->bframes > 0 && !dev_caps.max_bframes) {
1111 bframe_aborted = TRUE;
1113 GST_INFO_OBJECT (self, "B-frame was enabled but not support by device");
1116 if (self->weighted_pred && !dev_caps.weighted_prediction) {
1117 self->weighted_pred = FALSE;
1118 weight_pred_aborted = TRUE;
1120 GST_INFO_OBJECT (self,
1121 "Weighted prediction was enabled but not support by device");
1124 if (self->vbv_buffer_size && !dev_caps.custom_vbv_buf_size) {
1125 self->vbv_buffer_size = 0;
1126 vbv_buffer_size_aborted = TRUE;
1128 GST_INFO_OBJECT (self,
1129 "VBV buffer size was specified but not supported by device");
1132 if (self->rc_lookahead && !dev_caps.lookahead) {
1133 self->rc_lookahead = 0;
1134 lookahead_aborted = TRUE;
1136 GST_INFO_OBJECT (self,
1137 "VBV buffer size was specified but not supported by device");
1140 if (self->temporal_aq && !dev_caps.temporal_aq) {
1141 self->temporal_aq = FALSE;
1142 temporal_aq_aborted = TRUE;
1144 GST_INFO_OBJECT (self,
1145 "temporal-aq was enabled but not supported by device");
1149 init_params->version = gst_nvenc_get_initialize_params_version ();
1150 init_params->encodeGUID = NV_ENC_CODEC_HEVC_GUID;
1152 init_params->encodeWidth = GST_VIDEO_INFO_WIDTH (info);
1153 init_params->maxEncodeWidth = GST_VIDEO_INFO_WIDTH (info);
1154 init_params->encodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1155 init_params->maxEncodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1156 init_params->enablePTD = TRUE;
1157 if (dev_caps->async_encoding_support)
1158 init_params->enableEncodeAsync = 1;
1159 if (info->fps_d > 0 && info->fps_n > 0) {
1160 init_params->frameRateNum = info->fps_n;
1161 init_params->frameRateDen = info->fps_d;
1163 init_params->frameRateNum = 0;
1164 init_params->frameRateDen = 1;
1167 init_params->enableWeightedPrediction = self->weighted_pred;
1169 if (gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (info),
1170 GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_PAR_N (info),
1171 GST_VIDEO_INFO_PAR_D (info), &dar_n, &dar_d) && dar_n > 0
1173 init_params->darWidth = dar_n;
1174 init_params->darHeight = dar_d;
1177 gst_nv_encoder_preset_to_guid (self->preset, &init_params->presetGUID);
1179 preset_config.version = gst_nvenc_get_preset_config_version ();
1180 preset_config.presetCfg.version = gst_nvenc_get_config_version ();
1182 status = NvEncGetEncodePresetConfig (session, NV_ENC_CODEC_HEVC_GUID,
1183 init_params->presetGUID, &preset_config);
1184 if (status != NV_ENC_SUCCESS) {
1185 GST_ERROR_OBJECT (self, "Failed to get preset config %"
1186 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1187 g_mutex_unlock (&self->prop_lock);
1191 *config = preset_config.presetCfg;
1192 if (self->gop_size < 0) {
1193 config->gopLength = NVENC_INFINITE_GOPLENGTH;
1194 config->frameIntervalP = 1;
1195 } else if (self->gop_size > 0) {
1196 config->gopLength = self->gop_size;
1198 * 0: All Intra frames
1203 config->frameIntervalP = self->bframes + 1;
1205 /* gop size == 0 means all intra frames */
1206 config->gopLength = 1;
1207 config->frameIntervalP = 0;
1210 rc_params = &config->rcParams;
1211 rc_mode = self->rc_mode;
1214 rc_params->averageBitRate = self->bitrate * 1024;
1215 if (self->max_bitrate)
1216 rc_params->maxBitRate = self->max_bitrate * 1024;
1217 if (self->vbv_buffer_size)
1218 rc_params->vbvBufferSize = self->vbv_buffer_size * 1024;
1220 if (self->min_qp_i >= 0) {
1221 rc_params->enableMinQP = TRUE;
1222 rc_params->minQP.qpIntra = self->min_qp_i;
1223 if (self->min_qp_p >= 0) {
1224 rc_params->minQP.qpInterP = self->min_qp_p;
1226 rc_params->minQP.qpInterP = rc_params->minQP.qpIntra;
1228 if (self->min_qp_b >= 0) {
1229 rc_params->minQP.qpInterB = self->min_qp_b;
1231 rc_params->minQP.qpInterB = rc_params->minQP.qpInterP;
1235 if (self->max_qp_i >= 0) {
1236 rc_params->enableMaxQP = TRUE;
1237 rc_params->maxQP.qpIntra = self->max_qp_i;
1238 if (self->max_qp_p >= 0) {
1239 rc_params->maxQP.qpInterP = self->max_qp_p;
1241 rc_params->maxQP.qpInterP = rc_params->maxQP.qpIntra;
1243 if (self->max_qp_b >= 0) {
1244 rc_params->maxQP.qpInterB = self->max_qp_b;
1246 rc_params->maxQP.qpInterB = rc_params->maxQP.qpInterP;
1250 if (rc_mode == GST_NV_ENCODER_RC_MODE_CONSTQP) {
1251 if (self->qp_i >= 0)
1252 rc_params->constQP.qpIntra = self->qp_i;
1253 if (self->qp_p >= 0)
1254 rc_params->constQP.qpInterP = self->qp_p;
1255 if (self->qp_p >= 0)
1256 rc_params->constQP.qpInterB = self->qp_b;
1259 rc_params->rateControlMode = gst_nv_encoder_rc_mode_to_native (rc_mode);
1261 if (self->spatial_aq) {
1262 rc_params->enableAQ = TRUE;
1263 rc_params->aqStrength = self->aq_strength;
1266 rc_params->enableTemporalAQ = self->temporal_aq;
1268 if (self->rc_lookahead) {
1269 rc_params->enableLookahead = 1;
1270 rc_params->lookaheadDepth = self->rc_lookahead;
1271 rc_params->disableIadapt = !self->i_adapt;
1272 rc_params->disableBadapt = !self->b_adapt;
1275 rc_params->strictGOPTarget = self->strict_gop;
1276 rc_params->enableNonRefP = self->non_ref_p;
1277 rc_params->zeroReorderDelay = self->zero_reorder_delay;
1279 if (self->const_quality) {
1280 guint scaled = (gint) (self->const_quality * 256.0);
1282 rc_params->targetQuality = (guint8) (scaled >> 8);
1283 rc_params->targetQualityLSB = (guint8) (scaled & 0xff);
1285 self->init_param_updated = FALSE;
1286 self->bitrate_updated = FALSE;
1287 self->rc_param_updated = FALSE;
1289 config->profileGUID = selected_profile;
1291 hevc_config = &config->encodeCodecConfig.hevcConfig;
1292 vui = &hevc_config->hevcVUIParameters;
1294 hevc_config->level = NV_ENC_LEVEL_AUTOSELECT;
1295 hevc_config->chromaFormatIDC = chroma_format_index;
1296 hevc_config->pixelBitDepthMinus8 = bitdepth_minus8;
1297 hevc_config->idrPeriod = config->gopLength;
1298 hevc_config->outputAUD = self->aud;
1299 if (self->stream_format == GST_NV_H265_ENCODER_HVC1) {
1300 hevc_config->disableSPSPPS = 1;
1301 hevc_config->repeatSPSPPS = 0;
1302 } else if (self->repeat_sequence_header) {
1303 hevc_config->disableSPSPPS = 0;
1304 hevc_config->repeatSPSPPS = 1;
1306 hevc_config->disableSPSPPS = 0;
1307 hevc_config->repeatSPSPPS = 0;
1310 vui->videoSignalTypePresentFlag = 1;
1312 vui->videoFormat = 5;
1313 if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) {
1314 vui->videoFullRangeFlag = 1;
1316 vui->videoFullRangeFlag = 0;
1319 vui->colourDescriptionPresentFlag = 1;
1320 vui->colourMatrix = gst_video_color_matrix_to_iso (info->colorimetry.matrix);
1321 vui->colourPrimaries =
1322 gst_video_color_primaries_to_iso (info->colorimetry.primaries);
1323 vui->transferCharacteristics =
1324 gst_video_transfer_function_to_iso (info->colorimetry.transfer);
1326 g_mutex_unlock (&self->prop_lock);
1329 g_object_notify (G_OBJECT (self), "b-frames");
1330 if (weight_pred_aborted)
1331 g_object_notify (G_OBJECT (self), "weighted-pred");
1332 if (vbv_buffer_size_aborted)
1333 g_object_notify (G_OBJECT (self), "vbv-buffer-size");
1334 if (lookahead_aborted)
1335 g_object_notify (G_OBJECT (self), "rc-lookahead");
1336 if (temporal_aq_aborted)
1337 g_object_notify (G_OBJECT (self), "temporal-aq");
1343 gst_nv_h265_encoder_set_output_state (GstNvEncoder * encoder,
1344 GstVideoCodecState * state, gpointer session)
1346 GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1347 GstVideoCodecState *output_state;
1348 NV_ENC_SEQUENCE_PARAM_PAYLOAD seq_params = { 0, };
1349 guint8 vpsspspps[1024];
1352 const gchar *profile_from_vps;
1354 std::set < std::string > downstream_profiles;
1355 std::string caps_str;
1357 GstBuffer *codec_data = NULL;
1358 GstH265NalUnit vps_nalu, sps_nalu, pps_nalu;
1359 GstH265ParserResult rst;
1360 gboolean packetized = FALSE;
1365 if (self->stream_format != GST_NV_H265_ENCODER_BYTE_STREAM)
1368 caps_str = "video/x-h265, alignment = (string) au";
1370 gst_nv_h265_encoder_get_downstream_profiles_and_format (self,
1371 downstream_profiles, NULL);
1373 seq_params.version = gst_nvenc_get_sequence_param_payload_version ();
1374 seq_params.inBufferSize = sizeof (vpsspspps);
1375 seq_params.spsppsBuffer = &vpsspspps;
1376 seq_params.outSPSPPSPayloadSize = &seq_size;
1377 status = NvEncGetSequenceParams (session, &seq_params);
1378 if (status != NV_ENC_SUCCESS) {
1379 GST_ERROR_OBJECT (self, "Failed to get sequence header, status %"
1380 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1384 rst = gst_h265_parser_identify_nalu (self->parser,
1385 vpsspspps, 0, seq_size, &vps_nalu);
1386 if (rst != GST_H265_PARSER_OK) {
1387 GST_ERROR_OBJECT (self, "Failed to identify VPS nal");
1391 rst = gst_h265_parser_parse_vps (self->parser, &vps_nalu, &vps);
1392 if (rst != GST_H265_PARSER_OK) {
1393 GST_ERROR_OBJECT (self, "Failed to parse VPS");
1397 rst = gst_h265_parser_identify_nalu (self->parser,
1398 vpsspspps, vps_nalu.offset + vps_nalu.size, seq_size, &sps_nalu);
1399 if (rst != GST_H265_PARSER_OK && packetized) {
1400 GST_ERROR_OBJECT (self, "Failed to identify SPS nal, %d", rst);
1405 rst = gst_h265_parser_parse_sps (self->parser, &sps_nalu, &sps, TRUE);
1406 if (rst != GST_H265_PARSER_OK) {
1407 GST_ERROR_OBJECT (self, "Failed to parse SPS");
1412 rst = gst_h265_parser_identify_nalu_unchecked (self->parser,
1413 vpsspspps, sps_nalu.offset + sps_nalu.size, seq_size, &pps_nalu);
1414 if (rst != GST_H265_PARSER_OK && packetized) {
1415 GST_ERROR_OBJECT (self, "Failed to identify PPS nal, %d", rst);
1422 guint16 min_spatial_segmentation_idc = 0;
1423 GstH265ProfileTierLevel *ptl;
1425 codec_data = gst_buffer_new_and_alloc (38 +
1426 vps_nalu.size + sps_nalu.size + pps_nalu.size);
1428 gst_buffer_map (codec_data, &info, GST_MAP_WRITE);
1429 data = (guint8 *) info.data;
1431 memset (data, 0, info.size);
1433 ptl = &sps.profile_tier_level;
1434 if (sps.vui_parameters_present_flag) {
1435 min_spatial_segmentation_idc =
1436 sps.vui_params.min_spatial_segmentation_idc;
1441 (ptl->profile_space << 5) | (ptl->tier_flag << 5) | ptl->profile_idc;
1442 for (i = 2; i < 6; i++) {
1443 for (j = 7; j >= 0; j--) {
1444 data[i] |= (ptl->profile_compatibility_flag[k] << j);
1450 (ptl->progressive_source_flag << 7) |
1451 (ptl->interlaced_source_flag << 6) |
1452 (ptl->non_packed_constraint_flag << 5) |
1453 (ptl->frame_only_constraint_flag << 4) |
1454 (ptl->max_12bit_constraint_flag << 3) |
1455 (ptl->max_10bit_constraint_flag << 2) |
1456 (ptl->max_8bit_constraint_flag << 1) |
1457 (ptl->max_422chroma_constraint_flag);
1460 (ptl->max_420chroma_constraint_flag << 7) |
1461 (ptl->max_monochrome_constraint_flag << 6) |
1462 (ptl->intra_constraint_flag << 5) |
1463 (ptl->one_picture_only_constraint_flag << 4) |
1464 (ptl->lower_bit_rate_constraint_flag << 3) |
1465 (ptl->max_14bit_constraint_flag << 2);
1467 data[12] = ptl->level_idc;
1469 GST_WRITE_UINT16_BE (data + 13, min_spatial_segmentation_idc);
1472 data[16] = 0xfc | sps.chroma_format_idc;
1473 data[17] = 0xf8 | sps.bit_depth_luma_minus8;
1474 data[18] = 0xf8 | sps.bit_depth_chroma_minus8;
1478 0x00 | ((sps.max_sub_layers_minus1 +
1479 1) << 3) | (sps.temporal_id_nesting_flag << 2) | 3;
1480 GST_WRITE_UINT8 (data + 22, 3); /* numOfArrays */
1485 data[0] = 0x00 | 0x20;
1487 GST_WRITE_UINT16_BE (data, 1);
1489 GST_WRITE_UINT16_BE (data, vps_nalu.size);
1491 memcpy (data, vps_nalu.data + vps_nalu.offset, vps_nalu.size);
1492 data += vps_nalu.size;
1495 data[0] = 0x00 | 0x21;
1497 GST_WRITE_UINT16_BE (data, 1);
1499 GST_WRITE_UINT16_BE (data, sps_nalu.size);
1501 memcpy (data, sps_nalu.data + sps_nalu.offset, sps_nalu.size);
1502 data += sps_nalu.size;
1505 data[0] = 0x00 | 0x22;
1507 GST_WRITE_UINT16_BE (data, 1);
1509 GST_WRITE_UINT16_BE (data, pps_nalu.size);
1511 memcpy (data, pps_nalu.data + pps_nalu.offset, pps_nalu.size);
1512 gst_buffer_unmap (codec_data, &info);
1516 gst_codec_utils_h265_get_profile (vps_nalu.data + vps_nalu.offset +
1517 vps_nalu.header_bytes + 4, vps_nalu.size - vps_nalu.header_bytes - 4);
1518 if (!profile_from_vps) {
1519 GST_WARNING_OBJECT (self, "Failed to parse profile from SPS");
1520 } else if (!downstream_profiles.empty ()) {
1521 if (downstream_profiles.find (profile_from_vps) !=
1522 downstream_profiles.end ()) {
1523 caps_str += ", profile = (string) " + std::string (profile_from_vps);
1524 } else if (downstream_profiles.find ("main-10") !=
1525 downstream_profiles.end () && strcmp (profile_from_vps, "main") == 0) {
1526 caps_str += ", profile = (string) main-10";
1527 } else if (downstream_profiles.find ("main-444-10") !=
1528 downstream_profiles.end () &&
1529 strcmp (profile_from_vps, "main-444") == 0) {
1530 caps_str += ", profile = (string) main-444-10";
1533 caps_str += ", profile = (string) " + std::string (profile_from_vps);
1536 switch (self->stream_format) {
1537 case GST_NV_H265_ENCODER_HVC1:
1538 caps_str += ", stream-format = (string) hvc1";
1540 case GST_NV_H265_ENCODER_HEV1:
1541 caps_str += ", stream-format = (string) hev1";
1544 caps_str += ", stream-format = (string) byte-stream";
1548 caps = gst_caps_from_string (caps_str.c_str ());
1551 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
1552 gst_buffer_unref (codec_data);
1555 output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1558 GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
1559 gst_video_codec_state_unref (output_state);
1561 tags = gst_tag_list_new_empty ();
1562 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1563 "nvh265encoder", NULL);
1565 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
1566 tags, GST_TAG_MERGE_REPLACE);
1567 gst_tag_list_unref (tags);
1573 gst_nv_h265_encoder_create_output_buffer (GstNvEncoder *
1574 encoder, NV_ENC_LOCK_BITSTREAM * bitstream)
1576 GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1578 GstH265ParserResult rst;
1579 GstH265NalUnit nalu;
1581 if (self->stream_format == GST_NV_H265_ENCODER_BYTE_STREAM) {
1582 return gst_buffer_new_memdup (bitstream->bitstreamBufferPtr,
1583 bitstream->bitstreamSizeInBytes);
1586 buffer = gst_buffer_new ();
1587 rst = gst_h265_parser_identify_nalu (self->parser,
1588 (guint8 *) bitstream->bitstreamBufferPtr, 0,
1589 bitstream->bitstreamSizeInBytes, &nalu);
1591 if (rst == GST_H265_PARSER_NO_NAL_END)
1592 rst = GST_H265_PARSER_OK;
1594 while (rst == GST_H265_PARSER_OK) {
1598 data = (guint8 *) g_malloc0 (nalu.size + 4);
1599 GST_WRITE_UINT32_BE (data, nalu.size);
1600 memcpy (data + 4, nalu.data + nalu.offset, nalu.size);
1602 mem = gst_memory_new_wrapped ((GstMemoryFlags) 0, data, nalu.size + 4,
1603 0, nalu.size + 4, data, (GDestroyNotify) g_free);
1604 gst_buffer_append_memory (buffer, mem);
1606 rst = gst_h265_parser_identify_nalu (self->parser,
1607 (guint8 *) bitstream->bitstreamBufferPtr, nalu.offset + nalu.size,
1608 bitstream->bitstreamSizeInBytes, &nalu);
1610 if (rst == GST_H265_PARSER_NO_NAL_END)
1611 rst = GST_H265_PARSER_OK;
1617 static GstNvEncoderReconfigure
1618 gst_nv_h265_encoder_check_reconfigure (GstNvEncoder * encoder,
1619 NV_ENC_CONFIG * config)
1621 GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1622 GstNvEncoderReconfigure reconfig = GST_NV_ENCODER_RECONFIGURE_NONE;
1624 /* Dynamic RC param update is not tested, do soft-reconfigure only for
1626 g_mutex_lock (&self->prop_lock);
1627 if (self->init_param_updated || self->rc_param_updated) {
1628 reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1632 if (self->bitrate_updated) {
1633 GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
1634 if (klass->device_caps.dyn_bitrate_change > 0) {
1635 config->rcParams.averageBitRate = self->bitrate * 1024;
1636 config->rcParams.maxBitRate = self->max_bitrate * 1024;
1637 reconfig = GST_NV_ENCODER_RECONFIGURE_BITRATE;
1639 reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1644 self->init_param_updated = FALSE;
1645 self->rc_param_updated = FALSE;
1646 self->bitrate_updated = FALSE;
1647 g_mutex_unlock (&self->prop_lock);
1653 gst_nv_h265_encoder_select_device (GstNvEncoder * encoder,
1654 const GstVideoInfo * info, GstBuffer * buffer,
1655 GstNvEncoderDeviceData * data)
1657 GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1658 GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
1661 memset (data, 0, sizeof (GstNvEncoderDeviceData));
1663 g_assert (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT);
1665 mem = gst_buffer_peek_memory (buffer, 0);
1666 if (klass->cuda_device_id_size > 0 && gst_is_cuda_memory (mem)) {
1667 GstCudaMemory *cmem = GST_CUDA_MEMORY_CAST (mem);
1668 GstCudaContext *context = cmem->context;
1670 gboolean found = FALSE;
1672 g_object_get (context, "cuda-device-id", &device_id, nullptr);
1674 data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1675 self->selected_device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1677 for (guint i = 0; i < klass->cuda_device_id_size; i++) {
1678 if (klass->cuda_device_id_list[i] == device_id) {
1679 data->cuda_device_id = device_id;
1686 GST_INFO_OBJECT (self,
1687 "Upstream CUDA device is not in supported device list");
1688 data->cuda_device_id = self->cuda_device_id;
1690 data->device = (GstObject *) gst_object_ref (context);
1693 if (data->cuda_device_id != self->cuda_device_id) {
1694 self->cuda_device_id = data->cuda_device_id;
1695 g_object_notify (G_OBJECT (self), "cuda-device-id");
1700 #ifdef GST_CUDA_HAS_D3D
1701 if (klass->adapter_luid_size > 0 && gst_is_d3d11_memory (mem)) {
1702 GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
1703 GstD3D11Device *device = dmem->device;
1704 gint64 adapter_luid;
1705 gboolean found = FALSE;
1707 g_object_get (device, "adapter-luid", &adapter_luid, nullptr);
1709 data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1710 self->selected_device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1712 for (guint i = 0; i < klass->cuda_device_id_size; i++) {
1713 if (klass->adapter_luid_list[i] == adapter_luid) {
1714 data->adapter_luid = adapter_luid;
1721 GST_INFO_OBJECT (self,
1722 "Upstream D3D11 device is not in supported device list");
1723 data->adapter_luid = self->adapter_luid;
1725 data->device = (GstObject *) gst_object_ref (device);
1728 if (data->adapter_luid != self->adapter_luid) {
1729 self->adapter_luid = data->adapter_luid;
1730 g_object_notify (G_OBJECT (self), "adapter-luid");
1737 if (klass->cuda_device_id_size > 0 &&
1738 (self->selected_device_mode != GST_NV_ENCODER_DEVICE_D3D11)) {
1739 GST_INFO_OBJECT (self, "Upstream is system memory, use CUDA mode");
1740 data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1741 data->cuda_device_id = self->cuda_device_id;
1743 GST_INFO_OBJECT (self, "Upstream is system memory, use CUDA mode");
1744 data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1745 data->adapter_luid = self->adapter_luid;
1748 self->selected_device_mode = data->device_mode;
1753 static GstNvEncoderClassData *
1754 gst_nv_h265_encoder_create_class_data (GstObject * device, gpointer session,
1755 GstNvEncoderDeviceMode device_mode)
1758 GstNvEncoderDeviceCaps dev_caps = { 0, };
1759 GUID profile_guids[16];
1760 NV_ENC_BUFFER_FORMAT input_formats[16];
1761 guint32 profile_guid_count = 0;
1762 guint32 input_format_count = 0;
1763 std::string sink_caps_str;
1764 std::string src_caps_str;
1765 std::string format_str;
1766 std::set < std::string > formats;
1767 std::set < std::string > profiles;
1768 std::string profile_str;
1769 std::string resolution_str;
1770 GstNvEncoderClassData *cdata;
1772 GstCaps *system_caps;
1774 status = NvEncGetEncodeProfileGUIDs (session, NV_ENC_CODEC_HEVC_GUID,
1775 profile_guids, G_N_ELEMENTS (profile_guids), &profile_guid_count);
1776 if (status != NV_ENC_SUCCESS || profile_guid_count == 0) {
1777 GST_WARNING_OBJECT (device, "Unable to get supported profiles");
1781 status = NvEncGetInputFormats (session, NV_ENC_CODEC_HEVC_GUID, input_formats,
1782 G_N_ELEMENTS (input_formats), &input_format_count);
1783 if (status != NV_ENC_SUCCESS || input_format_count == 0) {
1784 GST_WARNING_OBJECT (device, "Unable to get supported input formats");
1788 gst_nv_encoder_get_encoder_caps (session, &NV_ENC_CODEC_HEVC_GUID, &dev_caps);
1790 for (guint32 i = 0; i < input_format_count; i++) {
1791 switch (input_formats[i]) {
1792 case NV_ENC_BUFFER_FORMAT_NV12:
1793 formats.insert ("NV12");
1795 case NV_ENC_BUFFER_FORMAT_YUV444:
1796 if (dev_caps.yuv444_encode)
1797 formats.insert ("Y444");
1799 case NV_ENC_BUFFER_FORMAT_YUV420_10BIT:
1800 if (dev_caps.supports_10bit_encode)
1801 formats.insert ("P010_10LE");
1803 case NV_ENC_BUFFER_FORMAT_YUV444_10BIT:
1804 if (dev_caps.supports_10bit_encode && dev_caps.yuv444_encode)
1805 formats.insert ("Y444_16LE");
1812 if (formats.empty ()) {
1813 GST_WARNING_OBJECT (device, "Empty supported input format");
1816 #define APPEND_STRING(dst,set,str) G_STMT_START { \
1817 if (set.find(str) != set.end()) { \
1825 if (formats.size () == 1) {
1826 format_str = "format = (string) " + *(formats.begin ());
1830 format_str = "format = (string) { ";
1831 APPEND_STRING (format_str, formats, "NV12");
1832 APPEND_STRING (format_str, formats, "P010_10LE");
1833 APPEND_STRING (format_str, formats, "Y444");
1834 APPEND_STRING (format_str, formats, "Y444_16LE");
1838 for (guint32 i = 0; i < profile_guid_count; i++) {
1839 if (profile_guids[i] == NV_ENC_HEVC_PROFILE_MAIN_GUID) {
1840 profiles.insert ("main");
1841 } else if (profile_guids[i] == NV_ENC_HEVC_PROFILE_MAIN10_GUID) {
1842 profiles.insert ("main-10");
1843 } else if (profile_guids[i] == NV_ENC_HEVC_PROFILE_FREXT_GUID) {
1844 if (formats.find ("Y444") != formats.end ())
1845 profiles.insert ("main-444");
1846 if (formats.find ("Y444_16LE") != formats.end ())
1847 profiles.insert ("main-444-10");
1851 if (profiles.empty ()) {
1852 GST_WARNING_OBJECT (device, "Empty supported h265 profile");
1856 if (profiles.size () == 1) {
1857 profile_str = "profile = (string) " + *(profiles.begin ());
1861 profile_str = "profile = (string) { ";
1862 APPEND_STRING (profile_str, profiles, "main");
1863 APPEND_STRING (profile_str, profiles, "main-10");
1864 APPEND_STRING (profile_str, profiles, "main-444");
1865 APPEND_STRING (profile_str, profiles, "main-444-10");
1866 profile_str += " }";
1868 #undef APPEND_STRING
1870 resolution_str = "width = (int) [ " +
1871 std::to_string (GST_ROUND_UP_16 (dev_caps.width_min))
1872 + ", " + std::to_string (dev_caps.width_max) + " ]";
1873 resolution_str += ", height = (int) [ " +
1874 std::to_string (GST_ROUND_UP_16 (dev_caps.height_min))
1875 + ", " + std::to_string (dev_caps.height_max) + " ]";
1877 sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str
1878 + ", interlace-mode = (string) progressive";
1880 src_caps_str = "video/x-h265, " + resolution_str + ", " + profile_str +
1881 ", stream-format = (string) { hvc1, hev1, byte-stream }" +
1882 ", alignment = (string) au";
1884 system_caps = gst_caps_from_string (sink_caps_str.c_str ());
1885 sink_caps = gst_caps_copy (system_caps);
1886 #ifdef GST_CUDA_HAS_D3D
1887 if (device_mode == GST_NV_ENCODER_DEVICE_D3D11) {
1888 gst_caps_set_features (sink_caps, 0,
1889 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
1893 if (device_mode == GST_NV_ENCODER_DEVICE_CUDA) {
1894 gst_caps_set_features (sink_caps, 0,
1895 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr));
1898 gst_caps_append (sink_caps, system_caps);
1900 cdata = gst_nv_encoder_class_data_new ();
1901 cdata->sink_caps = sink_caps;
1902 cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
1903 cdata->device_caps = dev_caps;
1904 cdata->device_mode = device_mode;
1907 for (const auto &iter: formats)
1908 cdata->formats = g_list_append (cdata->formats, g_strdup (iter.c_str()));
1910 for (const auto &iter: profiles)
1911 cdata->profiles = g_list_append (cdata->profiles, g_strdup (iter.c_str()));
1914 if (device_mode == GST_NV_ENCODER_DEVICE_D3D11)
1915 g_object_get (device, "adapter-luid", &cdata->adapter_luid, nullptr);
1917 if (device_mode == GST_NV_ENCODER_DEVICE_CUDA)
1918 g_object_get (device, "cuda-device-id", &cdata->cuda_device_id, nullptr);
1920 /* class data will be leaked if the element never gets instantiated */
1921 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1922 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1923 GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
1924 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1929 GstNvEncoderClassData *
1930 gst_nv_h265_encoder_register_cuda (GstPlugin * plugin, GstCudaContext * context,
1933 NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
1936 GstNvEncoderClassData *cdata;
1938 GST_DEBUG_CATEGORY_INIT (gst_nv_h265_encoder_debug, "nvh265encoder", 0,
1941 session_params.version =
1942 gst_nvenc_get_open_encode_session_ex_params_version ();
1943 session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
1944 session_params.device = gst_cuda_context_get_handle (context);
1945 session_params.apiVersion = gst_nvenc_get_api_version ();
1947 status = NvEncOpenEncodeSessionEx (&session_params, &session);
1948 if (status != NV_ENC_SUCCESS) {
1949 GST_WARNING_OBJECT (context, "Failed to open session");
1953 cdata = gst_nv_h265_encoder_create_class_data (GST_OBJECT (context), session,
1954 GST_NV_ENCODER_DEVICE_CUDA);
1955 NvEncDestroyEncoder (session);
1960 gst_nv_encoder_class_data_ref (cdata);
1964 gchar *feature_name;
1965 GTypeInfo type_info = {
1966 sizeof (GstNvH265EncoderClass),
1969 (GClassInitFunc) gst_nv_h265_encoder_class_init,
1972 sizeof (GstNvH265Encoder),
1974 (GInstanceInitFunc) gst_nv_h265_encoder_init,
1977 type_name = g_strdup ("GstNvCudaH265Enc");
1978 feature_name = g_strdup ("nvcudah265enc");
1981 while (g_type_from_name (type_name)) {
1984 g_free (feature_name);
1985 type_name = g_strdup_printf ("GstNvCudaH265Device%dEnc", index);
1986 feature_name = g_strdup_printf ("nvcudah265device%denc", index);
1989 type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
1990 &type_info, (GTypeFlags) 0);
1992 if (rank > 0 && index != 0)
1996 gst_element_type_set_skip_documentation (type);
1998 if (!gst_element_register (plugin, feature_name, rank, type))
1999 GST_WARNING ("Failed to register plugin '%s'", type_name);
2002 g_free (feature_name);
2007 #ifdef GST_CUDA_HAS_D3D
2008 GstNvEncoderClassData *
2009 gst_nv_h265_encoder_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
2012 NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
2015 GstNvEncoderClassData *cdata;
2017 GST_DEBUG_CATEGORY_INIT (gst_nv_h265_encoder_debug, "nvh265encoder", 0,
2020 session_params.version =
2021 gst_nvenc_get_open_encode_session_ex_params_version ();
2022 session_params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
2023 session_params.device = gst_d3d11_device_get_device_handle (device);
2024 session_params.apiVersion = gst_nvenc_get_api_version ();
2026 status = NvEncOpenEncodeSessionEx (&session_params, &session);
2027 if (status != NV_ENC_SUCCESS) {
2028 GST_WARNING_OBJECT (device, "Failed to open session");
2032 cdata = gst_nv_h265_encoder_create_class_data (GST_OBJECT (device), session,
2033 GST_NV_ENCODER_DEVICE_D3D11);
2034 NvEncDestroyEncoder (session);
2039 gst_nv_encoder_class_data_ref (cdata);
2043 gchar *feature_name;
2044 GTypeInfo type_info = {
2045 sizeof (GstNvH265EncoderClass),
2048 (GClassInitFunc) gst_nv_h265_encoder_class_init,
2051 sizeof (GstNvH265Encoder),
2053 (GInstanceInitFunc) gst_nv_h265_encoder_init,
2056 type_name = g_strdup ("GstNvD3D11H265Enc");
2057 feature_name = g_strdup ("nvd3d11h265enc");
2060 while (g_type_from_name (type_name)) {
2063 g_free (feature_name);
2064 type_name = g_strdup_printf ("GstNvD3D11H265Device%dEnc", index);
2065 feature_name = g_strdup_printf ("nvd3d11h265device%denc", index);
2068 type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
2069 &type_info, (GTypeFlags) 0);
2071 if (rank > 0 && index != 0)
2075 gst_element_type_set_skip_documentation (type);
2077 if (!gst_element_register (plugin, feature_name, rank, type))
2078 GST_WARNING ("Failed to register plugin '%s'", type_name);
2081 g_free (feature_name);
2088 gst_nv_h265_encoder_register_auto_select (GstPlugin * plugin,
2089 GList * device_caps_list, guint rank)
2091 std::set < std::string > formats;
2092 std::set < std::string > profiles;
2093 std::string sink_caps_str;
2094 std::string src_caps_str;
2095 std::string format_str;
2096 std::string profile_str;
2097 std::string resolution_str;
2099 guint adapter_luid_size = 0;
2100 gint64 adapter_luid_list[8];
2101 guint cuda_device_id_size = 0;
2102 guint cuda_device_id_list[8];
2103 GstNvEncoderDeviceCaps dev_caps;
2104 GstNvEncoderClassData *cdata;
2105 GstCaps *sink_caps = nullptr;
2106 GstCaps *system_caps;
2108 GST_DEBUG_CATEGORY_INIT (gst_nv_h265_encoder_debug, "nvh265encoder", 0,
2111 for (iter = device_caps_list; iter; iter = g_list_next (iter)) {
2112 GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) iter->data;
2115 for (walk = cdata->formats; walk; walk = g_list_next (walk))
2116 formats.insert ((gchar *) walk->data);
2118 for (walk = cdata->profiles; walk; walk = g_list_next (walk))
2119 profiles.insert ((gchar *) walk->data);
2121 if (cdata->device_mode == GST_NV_ENCODER_DEVICE_D3D11 &&
2122 adapter_luid_size < G_N_ELEMENTS (adapter_luid_list) - 1) {
2123 adapter_luid_list[adapter_luid_size] = cdata->adapter_luid;
2124 adapter_luid_size++;
2127 if (cdata->device_mode == GST_NV_ENCODER_DEVICE_CUDA &&
2128 cuda_device_id_size < G_N_ELEMENTS (cuda_device_id_list) - 1) {
2129 cuda_device_id_list[cuda_device_id_size] = cdata->cuda_device_id;
2130 cuda_device_id_size++;
2133 if (iter == device_caps_list) {
2134 dev_caps = cdata->device_caps;
2136 gst_nv_encoder_merge_device_caps (&dev_caps, &cdata->device_caps,
2141 g_list_free_full (device_caps_list,
2142 (GDestroyNotify) gst_nv_encoder_class_data_unref);
2143 if (formats.empty () || profiles.empty ())
2146 #define APPEND_STRING(dst,set,str) G_STMT_START { \
2147 if (set.find(str) != set.end()) { \
2155 if (formats.size () == 1) {
2156 format_str = "format = (string) " + *(formats.begin ());
2160 format_str = "format = (string) { ";
2161 APPEND_STRING (format_str, formats, "NV12");
2162 APPEND_STRING (format_str, formats, "P010_10LE");
2163 APPEND_STRING (format_str, formats, "Y444");
2164 APPEND_STRING (format_str, formats, "Y444_16LE");
2168 if (profiles.size () == 1) {
2169 profile_str = "profile = (string) " + *(profiles.begin ());
2173 profile_str = "profile = (string) { ";
2174 APPEND_STRING (profile_str, profiles, "main");
2175 APPEND_STRING (profile_str, profiles, "main-10");
2176 APPEND_STRING (profile_str, profiles, "main-444");
2177 APPEND_STRING (profile_str, profiles, "main-444-10");
2178 profile_str += " }";
2180 #undef APPEND_STRING
2182 resolution_str = "width = (int) [ " +
2183 std::to_string (GST_ROUND_UP_16 (dev_caps.width_min))
2184 + ", " + std::to_string (dev_caps.width_max) + " ]";
2185 resolution_str += ", height = (int) [ " +
2186 std::to_string (GST_ROUND_UP_16 (dev_caps.height_min))
2187 + ", " + std::to_string (dev_caps.height_max) + " ]";
2189 sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str
2190 + ", interlace-mode = (string) progressive";
2192 src_caps_str = "video/x-h265, " + resolution_str + ", " + profile_str +
2193 ", stream-format = (string) { hvc1, hev1, byte-stream }" +
2194 ", alignment = (string) au";
2196 system_caps = gst_caps_from_string (sink_caps_str.c_str ());
2197 sink_caps = gst_caps_new_empty ();
2199 if (cuda_device_id_size > 0) {
2200 GstCaps *cuda_caps = gst_caps_copy (system_caps);
2201 gst_caps_set_features (cuda_caps, 0,
2202 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr));
2203 gst_caps_append (sink_caps, cuda_caps);
2205 #ifdef GST_CUDA_HAS_D3D
2206 if (adapter_luid_size > 0) {
2207 GstCaps *d3d11_caps = gst_caps_copy (system_caps);
2208 gst_caps_set_features (d3d11_caps, 0,
2209 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
2210 gst_caps_append (sink_caps, d3d11_caps);
2214 gst_caps_append (sink_caps, system_caps);
2216 cdata = gst_nv_encoder_class_data_new ();
2217 cdata->sink_caps = sink_caps;
2218 cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
2219 cdata->device_caps = dev_caps;
2220 cdata->device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
2221 cdata->adapter_luid = adapter_luid_list[0];
2222 cdata->adapter_luid_size = adapter_luid_size;
2223 memcpy (&cdata->adapter_luid_list,
2224 adapter_luid_list, sizeof (adapter_luid_list));
2225 cdata->cuda_device_id = cuda_device_id_list[0];
2226 cdata->cuda_device_id_size = cuda_device_id_size;
2227 memcpy (&cdata->cuda_device_id_list,
2228 cuda_device_id_list, sizeof (cuda_device_id_list));
2230 /* class data will be leaked if the element never gets instantiated */
2231 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
2232 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2233 GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
2234 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2237 GTypeInfo type_info = {
2238 sizeof (GstNvH265EncoderClass),
2241 (GClassInitFunc) gst_nv_h265_encoder_class_init,
2244 sizeof (GstNvH265Encoder),
2246 (GInstanceInitFunc) gst_nv_h265_encoder_init,
2249 type = g_type_register_static (GST_TYPE_NV_ENCODER, "GstNvAutoGpuH265Enc",
2250 &type_info, (GTypeFlags) 0);
2252 if (!gst_element_register (plugin, "nvautogpuh265enc", rank, type))
2253 GST_WARNING ("Failed to register plugin 'GstNvAutoGpuH265Enc'");