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-nvcudah264enc:
23 * NVIDIA CUDA mode H.264 encoder
29 * element-nvd3d11h264enc:
31 * NVIDIA Direct3D11 mode H.264 encoder
37 * element-nvautogpuh264enc:
39 * NVIDIA auto GPU select mode H.264 encoder
48 #include "gstnvh264encoder.h"
49 #include <gst/codecparsers/gsth264parser.h>
50 #include <gst/pbutils/codec-utils.h>
55 GST_DEBUG_CATEGORY_STATIC (gst_nv_h264_encoder_debug);
56 #define GST_CAT_DEFAULT gst_nv_h264_encoder_debug
58 static GTypeClass *parent_class = nullptr;
74 /* rate-control params */
90 PROP_ZERO_REORDER_DELAY,
108 PROP_REPEAT_SEQUENCE_HEADER,
111 #define DEFAULT_PRESET GST_NV_ENCODER_PRESET_DEFAULT
112 #define DEFAULT_WEIGHTED_PRED FALSE
113 #define DEFAULT_GOP_SIZE 30
114 #define DEFAULT_B_FRAMES 0
115 #define DEFAULT_RATE_CONTROL GST_NV_ENCODER_RC_MODE_VBR
116 #define DEFAULT_QP -1
117 #define DEFAULT_BITRATE 0
118 #define DEFAULT_MAX_BITRATE 0
119 #define DEFAULT_VBV_BUFFER_SIZE 0
120 #define DEFAULT_RC_LOOKAHEAD 0
121 #define DEFAULT_I_ADAPT FALSE
122 #define DEFAULT_B_ADAPT FALSE
123 #define DEFAULT_SPATIAL_AQ FALSE
124 #define DEFAULT_TEMPORAL_AQ FALSE
125 #define DEFAULT_ZERO_REORDER_DELAY FALSE
126 #define DEFAULT_NON_REF_P FALSE
127 #define DEFAULT_STRICT_GOP FALSE
128 #define DEFAULT_AQ_STRENGTH FALSE
129 #define DEFAULT_CONST_QUALITY 0
130 #define DEFAULT_AUD TRUE
131 #define DEFAULT_REPEAT_SEQUENCE_HEADER FALSE
133 typedef struct _GstNvH264Encoder
138 gboolean init_param_updated;
139 gboolean rc_param_updated;
140 gboolean bitrate_updated;
143 GstH264NalParser *parser;
145 GstNvEncoderDeviceMode selected_device_mode;
148 guint cuda_device_id;
151 GstNvEncoderPreset preset;
152 gboolean weighted_pred;
157 GstNvEncoderRCMode rc_mode;
163 guint vbv_buffer_size;
168 gboolean temporal_aq;
169 gboolean zero_reorder_delay;
179 gdouble const_quality;
183 gboolean repeat_sequence_header;
186 typedef struct _GstNvH264EncoderClass
188 GstNvEncoderClass parent_class;
190 guint cuda_device_id;
193 GstNvEncoderDeviceMode device_mode;
195 /* representative device caps */
196 GstNvEncoderDeviceCaps device_caps;
198 /* auto gpu select mode */
199 guint cuda_device_id_size;
200 guint cuda_device_id_list[8];
202 guint adapter_luid_size;
203 gint64 adapter_luid_list[8];
204 } GstNvH264EncoderClass;
206 #define GST_NV_H264_ENCODER(object) ((GstNvH264Encoder *) (object))
207 #define GST_NV_H264_ENCODER_GET_CLASS(object) \
208 (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvH264EncoderClass))
210 static void gst_nv_h264_encoder_finalize (GObject * object);
211 static void gst_nv_h264_encoder_set_property (GObject * object, guint prop_id,
212 const GValue * value, GParamSpec * pspec);
213 static void gst_nv_h264_encoder_get_property (GObject * object, guint prop_id,
214 GValue * value, GParamSpec * pspec);
215 static GstCaps *gst_nv_h264_encoder_getcaps (GstVideoEncoder * encoder,
217 static gboolean gst_nv_h264_encoder_set_format (GstNvEncoder * encoder,
218 GstVideoCodecState * state, gpointer session,
219 NV_ENC_INITIALIZE_PARAMS * init_params, NV_ENC_CONFIG * config);
220 static gboolean gst_nv_h264_encoder_set_output_state (GstNvEncoder * encoder,
221 GstVideoCodecState * state, gpointer session);
222 static GstBuffer *gst_nv_h264_encoder_create_output_buffer (GstNvEncoder *
223 encoder, NV_ENC_LOCK_BITSTREAM * bitstream);
224 static GstNvEncoderReconfigure
225 gst_nv_h264_encoder_check_reconfigure (GstNvEncoder * encoder,
226 NV_ENC_CONFIG * config);
227 static gboolean gst_nv_h264_encoder_select_device (GstNvEncoder * encoder,
228 const GstVideoInfo * info, GstBuffer * buffer,
229 GstNvEncoderDeviceData * data);
232 gst_nv_h264_encoder_class_init (GstNvH264EncoderClass * klass, gpointer data)
234 GObjectClass *object_class = G_OBJECT_CLASS (klass);
235 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
236 GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
237 GstNvEncoderClass *nvenc_class = GST_NV_ENCODER_CLASS (klass);
238 GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) data;
239 GstNvEncoderDeviceCaps *dev_caps = &cdata->device_caps;
240 GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE |
241 GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS);
242 GParamFlags conditional_param_flags = (GParamFlags) (G_PARAM_READWRITE |
243 GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_PLAYING |
244 G_PARAM_STATIC_STRINGS);
246 parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
248 object_class->finalize = gst_nv_h264_encoder_finalize;
249 object_class->set_property = gst_nv_h264_encoder_set_property;
250 object_class->get_property = gst_nv_h264_encoder_get_property;
252 switch (cdata->device_mode) {
253 case GST_NV_ENCODER_DEVICE_CUDA:
254 g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
255 g_param_spec_uint ("cuda-device-id", "CUDA Device ID",
256 "CUDA device ID of associated GPU",
258 (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
259 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
261 case GST_NV_ENCODER_DEVICE_D3D11:
262 g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
263 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
264 "DXGI Adapter LUID (Locally Unique Identifier) of associated GPU",
265 G_MININT64, G_MAXINT64, 0,
266 (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
267 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
269 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
270 if (cdata->cuda_device_id_size > 0) {
271 g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
272 g_param_spec_uint ("cuda-device-id", "CUDA Device ID",
273 "CUDA device ID to use",
275 (GParamFlags) (conditional_param_flags |
276 GST_PARAM_DOC_SHOW_DEFAULT)));
278 if (cdata->adapter_luid_size > 0) {
279 g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
280 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
281 "DXGI Adapter LUID (Locally Unique Identifier) to use",
282 G_MININT64, G_MAXINT64, 0,
283 (GParamFlags) (conditional_param_flags |
284 GST_PARAM_DOC_SHOW_DEFAULT)));
288 g_assert_not_reached ();
292 g_object_class_install_property (object_class, PROP_PRESET,
293 g_param_spec_enum ("preset", "Encoding Preset",
294 "Encoding Preset", GST_TYPE_NV_ENCODER_PRESET,
295 DEFAULT_PRESET, param_flags));
296 if (dev_caps->weighted_prediction) {
297 g_object_class_install_property (object_class, PROP_WEIGHTED_PRED,
298 g_param_spec_boolean ("weighted-pred", "Weighted Pred",
299 "Enables Weighted Prediction", DEFAULT_WEIGHTED_PRED,
300 conditional_param_flags));
302 g_object_class_install_property (object_class, PROP_GOP_SIZE,
303 g_param_spec_int ("gop-size", "GOP size",
304 "Number of frames between intra frames (-1 = infinite)",
305 -1, G_MAXINT, DEFAULT_GOP_SIZE, param_flags));
306 if (dev_caps->max_bframes > 0) {
307 g_object_class_install_property (object_class, PROP_B_FRAMES,
308 g_param_spec_uint ("b-frames", "B-Frames",
309 "Number of B-frames between I and P", 0, dev_caps->max_bframes,
310 DEFAULT_B_FRAMES, conditional_param_flags));
312 g_object_class_install_property (object_class, PROP_RATE_CONTROL,
313 g_param_spec_enum ("rate-control", "Rate Control", "Rate Control Method",
314 GST_TYPE_NV_ENCODER_RC_MODE, DEFAULT_RATE_CONTROL, param_flags));
315 g_object_class_install_property (object_class, PROP_QP_I,
316 g_param_spec_int ("qp-i", "QP I",
317 "Constant QP value for I frame (-1 = default)", -1, 51,
318 DEFAULT_QP, param_flags));
319 g_object_class_install_property (object_class, PROP_QP_P,
320 g_param_spec_int ("qp-p", "QP P",
321 "Constant QP value for P frame (-1 = default)", -1, 51,
322 DEFAULT_QP, param_flags));
323 g_object_class_install_property (object_class, PROP_QP_B,
324 g_param_spec_int ("qp-b", "QP B",
325 "Constant QP value for B frame (-1 = default)", -1, 51,
326 DEFAULT_QP, param_flags));
327 g_object_class_install_property (object_class, PROP_BITRATE,
328 g_param_spec_uint ("bitrate", "Bitrate",
329 "Bitrate in kbit/sec (0 = automatic)", 0, 2000 * 1024,
330 DEFAULT_BITRATE, param_flags));
331 g_object_class_install_property (object_class, PROP_MAX_BITRATE,
332 g_param_spec_uint ("max-bitrate", "Max Bitrate",
333 "Maximum Bitrate in kbit/sec (ignored in CBR mode)", 0, 2000 * 1024,
334 DEFAULT_MAX_BITRATE, param_flags));
335 if (dev_caps->custom_vbv_buf_size) {
336 g_object_class_install_property (object_class,
337 PROP_VBV_BUFFER_SIZE,
338 g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
339 "VBV(HRD) Buffer Size in kbits (0 = NVENC default)",
340 0, G_MAXUINT, DEFAULT_VBV_BUFFER_SIZE, conditional_param_flags));
342 if (dev_caps->lookahead) {
343 g_object_class_install_property (object_class, PROP_RC_LOOKAHEAD,
344 g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead",
345 "Number of frames for frame type lookahead",
346 0, 32, DEFAULT_RC_LOOKAHEAD, conditional_param_flags));
347 g_object_class_install_property (object_class, PROP_I_ADAPT,
348 g_param_spec_boolean ("i-adapt", "I Adapt",
349 "Enable adaptive I-frame insert when lookahead is enabled",
350 DEFAULT_I_ADAPT, conditional_param_flags));
351 if (dev_caps->max_bframes > 0) {
352 g_object_class_install_property (object_class, PROP_B_ADAPT,
353 g_param_spec_boolean ("b-adapt", "B Adapt",
354 "Enable adaptive B-frame insert when lookahead is enabled",
355 DEFAULT_B_ADAPT, conditional_param_flags));
358 g_object_class_install_property (object_class, PROP_SPATIAL_AQ,
359 g_param_spec_boolean ("spatial-aq", "Spatial AQ",
360 "Spatial Adaptive Quantization", DEFAULT_SPATIAL_AQ, param_flags));
361 if (dev_caps->temporal_aq) {
362 g_object_class_install_property (object_class, PROP_TEMPORAL_AQ,
363 g_param_spec_boolean ("temporal-aq", "Temporal AQ",
364 "Temporal Adaptive Quantization", DEFAULT_TEMPORAL_AQ,
365 conditional_param_flags));
367 g_object_class_install_property (object_class, PROP_ZERO_REORDER_DELAY,
368 g_param_spec_boolean ("zero-reorder-delay", "Zero Reorder Delay",
369 "Zero latency operation (i.e., num_reorder_frames = 0)",
370 DEFAULT_ZERO_REORDER_DELAY, param_flags));
371 g_object_class_install_property (object_class, PROP_NON_REF_P,
372 g_param_spec_boolean ("nonref-p", "Nonref P",
373 "Automatic insertion of non-reference P-frames", DEFAULT_NON_REF_P,
375 g_object_class_install_property (object_class, PROP_STRICT_GOP,
376 g_param_spec_boolean ("strict-gop", "Strict GOP",
377 "Minimize GOP-to-GOP rate fluctuations", DEFAULT_STRICT_GOP,
379 g_object_class_install_property (object_class, PROP_AQ_STRENGTH,
380 g_param_spec_uint ("aq-strength", "AQ Strength",
381 "Adaptive Quantization Strength when spatial-aq is enabled"
382 " from 1 (low) to 15 (aggressive), (0 = autoselect)",
383 0, 15, DEFAULT_AQ_STRENGTH, param_flags));
384 g_object_class_install_property (object_class, PROP_MIN_QP_I,
385 g_param_spec_int ("min-qp-i", "Min QP I",
386 "Minimum QP value for I frame, (-1 = disabled)", -1, 51,
387 DEFAULT_QP, param_flags));
388 g_object_class_install_property (object_class, PROP_MIN_QP_P,
389 g_param_spec_int ("min-qp-p", "Min QP P",
390 "Minimum QP value for P frame, (-1 = automatic)", -1, 51,
391 DEFAULT_QP, param_flags));
392 g_object_class_install_property (object_class, PROP_MIN_QP_B,
393 g_param_spec_int ("min-qp-b", "Min QP B",
394 "Minimum QP value for B frame, (-1 = automatic)", -1, 51,
395 DEFAULT_QP, param_flags));
396 g_object_class_install_property (object_class, PROP_MAX_QP_I,
397 g_param_spec_int ("max-qp-i", "Max QP I",
398 "Maximum QP value for I frame, (-1 = disabled)", -1, 51,
399 DEFAULT_QP, param_flags));
400 g_object_class_install_property (object_class, PROP_MAX_QP_P,
401 g_param_spec_int ("max-qp-p", "Max QP P",
402 "Maximum QP value for P frame, (-1 = automatic)", -1, 51,
403 DEFAULT_QP, param_flags));
404 g_object_class_install_property (object_class, PROP_MAX_QP_B,
405 g_param_spec_int ("max-qp-b", "Max QP B",
406 "Maximum QP value for B frame, (-1 = automatic)", -1, 51,
407 DEFAULT_QP, param_flags));
408 g_object_class_install_property (object_class, PROP_CONST_QUALITY,
409 g_param_spec_double ("const-quality", "Constant Quality",
410 "Target Constant Quality level for VBR mode (0 = automatic)",
411 0, 51, DEFAULT_CONST_QUALITY, param_flags));
412 g_object_class_install_property (object_class, PROP_AUD,
413 g_param_spec_boolean ("aud", "AUD",
414 "Use AU (Access Unit) delimiter", DEFAULT_AUD, param_flags));
415 if (dev_caps->cabac) {
416 g_object_class_install_property (object_class, PROP_CABAC,
417 g_param_spec_boolean ("cabac", "CABAC",
418 "Enable CABAC entropy coding", TRUE, conditional_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 DEFAULT_REPEAT_SEQUENCE_HEADER, param_flags));
425 switch (cdata->device_mode) {
426 case GST_NV_ENCODER_DEVICE_CUDA:
427 gst_element_class_set_static_metadata (element_class,
428 "NVENC H.264 Video Encoder CUDA Mode",
429 "Codec/Encoder/Video/Hardware",
430 "Encode H.264 video streams using NVCODEC API CUDA Mode",
431 "Seungha Yang <seungha@centricular.com>");
433 case GST_NV_ENCODER_DEVICE_D3D11:
434 gst_element_class_set_static_metadata (element_class,
435 "NVENC H.264 Video Encoder Direct3D11 Mode",
436 "Codec/Encoder/Video/Hardware",
437 "Encode H.264 video streams using NVCODEC API Direct3D11 Mode",
438 "Seungha Yang <seungha@centricular.com>");
440 case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
441 gst_element_class_set_static_metadata (element_class,
442 "NVENC H.264 Video Encoder Auto GPU select Mode",
443 "Codec/Encoder/Video/Hardware",
444 "Encode H.264 video streams using NVCODEC API auto GPU select Mode",
445 "Seungha Yang <seungha@centricular.com>");
448 g_assert_not_reached ();
452 gst_element_class_add_pad_template (element_class,
453 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
455 gst_element_class_add_pad_template (element_class,
456 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
459 videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_getcaps);
461 nvenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_set_format);
462 nvenc_class->set_output_state =
463 GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_set_output_state);
464 nvenc_class->create_output_buffer =
465 GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_create_output_buffer);
466 nvenc_class->check_reconfigure =
467 GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_check_reconfigure);
468 nvenc_class->select_device =
469 GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_select_device);
471 klass->device_caps = cdata->device_caps;
472 klass->cuda_device_id = cdata->cuda_device_id;
473 klass->adapter_luid = cdata->adapter_luid;
474 klass->device_mode = cdata->device_mode;
475 klass->cuda_device_id_size = cdata->cuda_device_id_size;
476 klass->adapter_luid_size = cdata->adapter_luid_size;
477 memcpy (klass->cuda_device_id_list, cdata->cuda_device_id_list,
478 sizeof (klass->cuda_device_id_list));
479 memcpy (klass->adapter_luid_list, cdata->adapter_luid_list,
480 sizeof (klass->adapter_luid_list));
482 gst_nv_encoder_class_data_unref (cdata);
486 gst_nv_h264_encoder_init (GstNvH264Encoder * self)
488 GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
490 g_mutex_init (&self->prop_lock);
492 self->selected_device_mode = klass->device_mode;
493 self->cuda_device_id = klass->cuda_device_id;
494 self->adapter_luid = klass->adapter_luid;
495 self->preset = DEFAULT_PRESET;
496 self->weighted_pred = DEFAULT_WEIGHTED_PRED;
497 self->gop_size = DEFAULT_GOP_SIZE;
498 self->bframes = DEFAULT_B_FRAMES;
499 self->rc_mode = DEFAULT_RATE_CONTROL;
500 self->qp_i = DEFAULT_QP;
501 self->qp_p = DEFAULT_QP;
502 self->qp_b = DEFAULT_QP;
503 self->bitrate = DEFAULT_BITRATE;
504 self->max_bitrate = DEFAULT_MAX_BITRATE;
505 self->vbv_buffer_size = DEFAULT_VBV_BUFFER_SIZE;
506 self->rc_lookahead = DEFAULT_RC_LOOKAHEAD;
507 self->i_adapt = DEFAULT_I_ADAPT;
508 self->b_adapt = DEFAULT_B_ADAPT;
509 self->spatial_aq = DEFAULT_SPATIAL_AQ;
510 self->temporal_aq = DEFAULT_TEMPORAL_AQ;
511 self->zero_reorder_delay = DEFAULT_ZERO_REORDER_DELAY;
512 self->non_ref_p = DEFAULT_NON_REF_P;
513 self->strict_gop = DEFAULT_STRICT_GOP;
514 self->aq_strength = DEFAULT_AQ_STRENGTH;
515 self->min_qp_i = DEFAULT_QP;
516 self->min_qp_p = DEFAULT_QP;
517 self->min_qp_b = DEFAULT_QP;
518 self->max_qp_i = DEFAULT_QP;
519 self->max_qp_p = DEFAULT_QP;
520 self->max_qp_b = DEFAULT_QP;
521 self->const_quality = DEFAULT_CONST_QUALITY;
522 self->aud = DEFAULT_AUD;
523 if (klass->device_caps.cabac)
525 self->repeat_sequence_header = DEFAULT_REPEAT_SEQUENCE_HEADER;
527 self->parser = gst_h264_nal_parser_new ();
529 gst_nv_encoder_set_device_mode (GST_NV_ENCODER (self), klass->device_mode,
530 klass->cuda_device_id, klass->adapter_luid);
534 gst_nv_h264_encoder_finalize (GObject * object)
536 GstNvH264Encoder *self = GST_NV_H264_ENCODER (object);
538 g_mutex_clear (&self->prop_lock);
539 gst_h264_nal_parser_free (self->parser);
541 G_OBJECT_CLASS (parent_class)->finalize (object);
552 update_boolean (GstNvH264Encoder * self, gboolean * old_val,
553 const GValue * new_val, PropUpdateLevel level)
555 gboolean val = g_value_get_boolean (new_val);
562 case UPDATE_INIT_PARAM:
563 self->init_param_updated = TRUE;
565 case UPDATE_RC_PARAM:
566 self->rc_param_updated = TRUE;
569 self->bitrate_updated = TRUE;
575 update_int (GstNvH264Encoder * self, gint * old_val,
576 const GValue * new_val, PropUpdateLevel level)
578 gint val = g_value_get_int (new_val);
585 case UPDATE_INIT_PARAM:
586 self->init_param_updated = TRUE;
588 case UPDATE_RC_PARAM:
589 self->rc_param_updated = TRUE;
592 self->bitrate_updated = TRUE;
598 update_uint (GstNvH264Encoder * self, guint * old_val,
599 const GValue * new_val, PropUpdateLevel level)
601 guint val = g_value_get_uint (new_val);
608 case UPDATE_INIT_PARAM:
609 self->init_param_updated = TRUE;
611 case UPDATE_RC_PARAM:
612 self->rc_param_updated = TRUE;
615 self->bitrate_updated = TRUE;
621 update_double (GstNvH264Encoder * self, gdouble * old_val,
622 const GValue * new_val, PropUpdateLevel level)
624 gdouble val = g_value_get_double (new_val);
631 case UPDATE_INIT_PARAM:
632 self->init_param_updated = TRUE;
634 case UPDATE_RC_PARAM:
635 self->rc_param_updated = TRUE;
638 self->bitrate_updated = TRUE;
644 gst_nv_h264_encoder_set_property (GObject * object, guint prop_id,
645 const GValue * value, GParamSpec * pspec)
647 GstNvH264Encoder *self = GST_NV_H264_ENCODER (object);
648 GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
650 g_mutex_lock (&self->prop_lock);
652 case PROP_ADAPTER_LUID:{
653 gint64 adapter_luid = g_value_get_int64 (value);
654 gboolean is_valid = FALSE;
656 for (guint i = 0; i < klass->adapter_luid_size; i++) {
657 if (klass->adapter_luid_list[i] == adapter_luid) {
658 self->adapter_luid = adapter_luid;
665 g_warning ("%" G_GINT64_FORMAT " is not a valid adapter luid",
669 case PROP_CUDA_DEVICE_ID:{
670 guint cuda_device_id = g_value_get_uint (value);
671 gboolean is_valid = FALSE;
673 for (guint i = 0; i < klass->cuda_device_id_size; i++) {
674 if (klass->cuda_device_id_list[i] == cuda_device_id) {
675 self->cuda_device_id = cuda_device_id;
682 g_warning ("%d is not a valid cuda device id", cuda_device_id);
686 GstNvEncoderPreset preset = (GstNvEncoderPreset) g_value_get_enum (value);
687 if (preset != self->preset) {
688 self->preset = preset;
689 self->init_param_updated = TRUE;
693 case PROP_WEIGHTED_PRED:
694 update_boolean (self, &self->weighted_pred, value, UPDATE_INIT_PARAM);
697 update_int (self, &self->gop_size, value, UPDATE_INIT_PARAM);
700 update_uint (self, &self->bframes, value, UPDATE_INIT_PARAM);
702 case PROP_RATE_CONTROL:{
703 GstNvEncoderRCMode mode = (GstNvEncoderRCMode) g_value_get_enum (value);
704 if (mode != self->rc_mode) {
705 self->rc_mode = mode;
706 self->rc_param_updated = TRUE;
711 update_int (self, &self->qp_i, value, UPDATE_RC_PARAM);
714 update_int (self, &self->qp_p, value, UPDATE_RC_PARAM);
717 update_int (self, &self->qp_b, value, UPDATE_RC_PARAM);
720 update_uint (self, &self->bitrate, value, UPDATE_BITRATE);
722 case PROP_MAX_BITRATE:
723 update_uint (self, &self->max_bitrate, value, UPDATE_BITRATE);
725 case PROP_VBV_BUFFER_SIZE:
726 update_uint (self, &self->vbv_buffer_size, value, UPDATE_RC_PARAM);
728 case PROP_RC_LOOKAHEAD:
729 /* rc-lookahead update requires pool size change */
730 update_uint (self, &self->rc_lookahead, value, UPDATE_INIT_PARAM);
733 update_boolean (self, &self->i_adapt, value, UPDATE_RC_PARAM);
736 update_boolean (self, &self->b_adapt, value, UPDATE_RC_PARAM);
738 case PROP_SPATIAL_AQ:
739 update_boolean (self, &self->spatial_aq, value, UPDATE_RC_PARAM);
741 case PROP_TEMPORAL_AQ:
742 update_boolean (self, &self->temporal_aq, value, UPDATE_RC_PARAM);
744 case PROP_ZERO_REORDER_DELAY:
745 update_boolean (self, &self->zero_reorder_delay, value, UPDATE_RC_PARAM);
748 update_boolean (self, &self->non_ref_p, value, UPDATE_RC_PARAM);
750 case PROP_STRICT_GOP:
751 update_boolean (self, &self->strict_gop, value, UPDATE_RC_PARAM);
753 case PROP_AQ_STRENGTH:
754 update_uint (self, &self->aq_strength, value, UPDATE_RC_PARAM);
757 update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
760 update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
763 update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
766 update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
769 update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
772 update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
774 case PROP_CONST_QUALITY:
775 update_double (self, &self->const_quality, value, UPDATE_RC_PARAM);
778 update_boolean (self, &self->aud, value, UPDATE_INIT_PARAM);
781 update_boolean (self, &self->cabac, value, UPDATE_INIT_PARAM);
783 case PROP_REPEAT_SEQUENCE_HEADER:
784 update_boolean (self,
785 &self->repeat_sequence_header, value, UPDATE_INIT_PARAM);
788 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
792 g_mutex_unlock (&self->prop_lock);
796 gst_nv_h264_encoder_get_property (GObject * object, guint prop_id,
797 GValue * value, GParamSpec * pspec)
799 GstNvH264Encoder *self = GST_NV_H264_ENCODER (object);
802 case PROP_ADAPTER_LUID:
803 g_value_set_int64 (value, self->adapter_luid);
805 case PROP_CUDA_DEVICE_ID:
806 g_value_set_uint (value, self->cuda_device_id);
809 g_value_set_enum (value, self->preset);
811 case PROP_WEIGHTED_PRED:
812 g_value_set_boolean (value, self->weighted_pred);
815 g_value_set_int (value, self->gop_size);
818 g_value_set_uint (value, self->bframes);
820 case PROP_RATE_CONTROL:
821 g_value_set_enum (value, self->rc_mode);
824 g_value_set_int (value, self->qp_i);
827 g_value_set_int (value, self->qp_p);
830 g_value_set_int (value, self->qp_b);
833 g_value_set_uint (value, self->bitrate);
835 case PROP_MAX_BITRATE:
836 g_value_set_uint (value, self->max_bitrate);
838 case PROP_VBV_BUFFER_SIZE:
839 g_value_set_uint (value, self->vbv_buffer_size);
841 case PROP_RC_LOOKAHEAD:
842 g_value_set_uint (value, self->rc_lookahead);
845 g_value_set_boolean (value, self->i_adapt);
848 g_value_set_boolean (value, self->b_adapt);
850 case PROP_SPATIAL_AQ:
851 g_value_set_boolean (value, self->spatial_aq);
853 case PROP_TEMPORAL_AQ:
854 g_value_set_boolean (value, self->temporal_aq);
856 case PROP_ZERO_REORDER_DELAY:
857 g_value_set_boolean (value, self->zero_reorder_delay);
860 g_value_set_boolean (value, self->non_ref_p);
862 case PROP_STRICT_GOP:
863 g_value_set_boolean (value, self->strict_gop);
865 case PROP_AQ_STRENGTH:
866 g_value_set_uint (value, self->aq_strength);
869 g_value_set_int (value, self->min_qp_i);
872 g_value_set_int (value, self->min_qp_p);
875 g_value_set_int (value, self->min_qp_b);
878 g_value_set_int (value, self->max_qp_i);
881 g_value_set_int (value, self->max_qp_p);
884 g_value_set_int (value, self->max_qp_b);
886 case PROP_CONST_QUALITY:
887 g_value_set_double (value, self->const_quality);
890 g_value_set_boolean (value, self->aud);
893 g_value_set_boolean (value, self->cabac);
895 case PROP_REPEAT_SEQUENCE_HEADER:
896 g_value_set_boolean (value, self->repeat_sequence_header);
899 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
905 gst_nv_h264_encoder_get_downstream_profiles_and_format (GstNvH264Encoder * self,
906 std::set < std::string > &downstream_profiles, gboolean * packetized)
908 GstCaps *allowed_caps;
910 const gchar *stream_format;
912 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
914 if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
915 gst_caps_is_any (allowed_caps)) {
916 gst_clear_caps (&allowed_caps);
921 for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
922 const GValue *profile_value;
923 const gchar *profile;
925 s = gst_caps_get_structure (allowed_caps, i);
926 profile_value = gst_structure_get_value (s, "profile");
930 if (GST_VALUE_HOLDS_LIST (profile_value)) {
931 for (guint j = 0; j < gst_value_list_get_size (profile_value); j++) {
932 const GValue *p = gst_value_list_get_value (profile_value, j);
934 if (!G_VALUE_HOLDS_STRING (p))
937 profile = g_value_get_string (p);
939 downstream_profiles.insert (profile);
942 } else if (G_VALUE_HOLDS_STRING (profile_value)) {
943 profile = g_value_get_string (profile_value);
945 downstream_profiles.insert (profile);
951 allowed_caps = gst_caps_fixate (allowed_caps);
952 s = gst_caps_get_structure (allowed_caps, 0);
953 stream_format = gst_structure_get_string (s, "stream-format");
954 if (g_strcmp0 (stream_format, "avc") == 0)
958 gst_caps_unref (allowed_caps);
962 gst_nv_h264_encoder_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
964 GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
965 GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
966 GstCaps *allowed_caps;
967 GstCaps *template_caps;
968 GstCaps *filtered_caps;
969 GstCaps *supported_caps;
970 std::set < std::string > downstream_profiles;
971 std::set < std::string > allowed_formats;
972 gboolean profile_support_interlaced = FALSE;
974 gst_nv_h264_encoder_get_downstream_profiles_and_format (self,
975 downstream_profiles, nullptr);
977 GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
978 downstream_profiles.size ());
980 if (downstream_profiles.size () == 0)
981 return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
984 for (const auto &iter: downstream_profiles) {
985 if (iter == "high" || iter == "main") {
986 profile_support_interlaced = TRUE;
989 if (iter == "high-4:4:4") {
990 profile_support_interlaced = TRUE;
991 allowed_formats.insert("Y444");
993 allowed_formats.insert("NV12");
998 GST_DEBUG_OBJECT (self, "Downstream %s support interlaced format",
999 profile_support_interlaced ? "can" : "cannot");
1001 template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
1002 allowed_caps = gst_caps_copy (template_caps);
1004 if (klass->device_caps.field_encoding == 0 || !profile_support_interlaced) {
1005 gst_caps_set_simple (allowed_caps, "interlace-mode", G_TYPE_STRING,
1006 "progressive", nullptr);
1009 GValue formats = G_VALUE_INIT;
1011 g_value_init (&formats, GST_TYPE_LIST);
1013 for (const auto &iter: allowed_formats) {
1014 GValue val = G_VALUE_INIT;
1015 g_value_init (&val, G_TYPE_STRING);
1017 g_value_set_string (&val, iter.c_str());
1018 gst_value_list_append_and_take_value (&formats, &val);
1022 gst_caps_set_value (allowed_caps, "format", &formats);
1023 g_value_unset (&formats);
1025 filtered_caps = gst_caps_intersect_full (template_caps, allowed_caps,
1026 GST_CAPS_INTERSECT_FIRST);
1028 supported_caps = gst_video_encoder_proxy_getcaps (encoder,
1029 filtered_caps, filter);
1030 gst_caps_unref (filtered_caps);
1031 gst_caps_unref (allowed_caps);
1032 gst_caps_unref (template_caps);
1034 GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
1036 return supported_caps;
1040 gst_nv_h264_encoder_set_format (GstNvEncoder * encoder,
1041 GstVideoCodecState * state, gpointer session,
1042 NV_ENC_INITIALIZE_PARAMS * init_params, NV_ENC_CONFIG * config)
1044 GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1045 GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
1046 GstNvEncoderDeviceCaps *dev_caps = &klass->device_caps;
1047 NV_ENC_RC_PARAMS *rc_params;
1048 GstVideoInfo *info = &state->info;
1050 NV_ENC_PRESET_CONFIG preset_config = { 0, };
1052 GstNvEncoderRCMode rc_mode;
1053 NV_ENC_CONFIG_H264 *h264_config;
1054 NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui;
1055 std::set < std::string > downstream_profiles;
1056 GUID selected_profile = NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID;
1057 gboolean downstream_supports_bframe = FALSE;
1058 gboolean bframe_aborted = FALSE;
1059 gboolean weight_pred_aborted = FALSE;
1060 gboolean vbv_buffer_size_aborted = FALSE;
1061 gboolean lookahead_aborted = FALSE;
1062 gboolean temporal_aq_aborted = FALSE;
1064 self->packetized = FALSE;
1066 gst_nv_h264_encoder_get_downstream_profiles_and_format (self,
1067 downstream_profiles, &self->packetized);
1069 if (downstream_profiles.empty ()) {
1070 GST_ERROR_OBJECT (self, "Unable to get downstream profile");
1074 if (GST_VIDEO_INFO_IS_INTERLACED (info)) {
1075 downstream_profiles.erase ("progressive-high");
1076 downstream_profiles.erase ("constrained-high");
1077 downstream_profiles.erase ("constrained-baseline");
1078 downstream_profiles.erase ("baseline");
1080 if (downstream_profiles.empty ()) {
1081 GST_ERROR_OBJECT (self,
1082 "None of downstream profile supports interlaced encoding");
1087 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444) {
1088 if (downstream_profiles.find ("high-4:4:4") == downstream_profiles.end ()) {
1089 GST_ERROR_OBJECT (self, "Downstream does not support 4:4:4 profile");
1092 selected_profile = NV_ENC_H264_PROFILE_HIGH_444_GUID;
1093 downstream_supports_bframe = TRUE;
1097 for (const auto &iter: downstream_profiles) {
1098 if (iter == "high" || iter == "main" || iter == "progressive-high") {
1099 downstream_supports_bframe = TRUE;
1105 g_mutex_lock (&self->prop_lock);
1107 if (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1108 GstNvEncoderDeviceCaps dev_caps;
1110 gst_nv_encoder_get_encoder_caps (session,
1111 &NV_ENC_CODEC_H264_GUID, &dev_caps);
1113 if (self->bframes > 0 && !dev_caps.max_bframes) {
1115 bframe_aborted = TRUE;
1117 GST_INFO_OBJECT (self, "B-frame was enabled but not support by device");
1120 if (self->weighted_pred && !dev_caps.weighted_prediction) {
1121 self->weighted_pred = FALSE;
1122 weight_pred_aborted = TRUE;
1124 GST_INFO_OBJECT (self,
1125 "Weighted prediction was enabled but not support by device");
1128 if (self->vbv_buffer_size && !dev_caps.custom_vbv_buf_size) {
1129 self->vbv_buffer_size = 0;
1130 vbv_buffer_size_aborted = TRUE;
1132 GST_INFO_OBJECT (self,
1133 "VBV buffer size was specified but not supported by device");
1136 if (self->rc_lookahead && !dev_caps.lookahead) {
1137 self->rc_lookahead = 0;
1138 lookahead_aborted = TRUE;
1140 GST_INFO_OBJECT (self,
1141 "VBV buffer size was specified but not supported by device");
1144 if (self->temporal_aq && !dev_caps.temporal_aq) {
1145 self->temporal_aq = FALSE;
1146 temporal_aq_aborted = TRUE;
1148 GST_INFO_OBJECT (self,
1149 "temporal-aq was enabled but not supported by device");
1153 init_params->version = gst_nvenc_get_initialize_params_version ();
1154 init_params->encodeGUID = NV_ENC_CODEC_H264_GUID;
1156 init_params->encodeWidth = GST_VIDEO_INFO_WIDTH (info);
1157 init_params->maxEncodeWidth = GST_VIDEO_INFO_WIDTH (info);
1158 init_params->encodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1159 init_params->maxEncodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1160 init_params->enablePTD = TRUE;
1161 if (dev_caps->async_encoding_support)
1162 init_params->enableEncodeAsync = 1;
1163 if (info->fps_d > 0 && info->fps_n > 0) {
1164 init_params->frameRateNum = info->fps_n;
1165 init_params->frameRateDen = info->fps_d;
1167 init_params->frameRateNum = 0;
1168 init_params->frameRateDen = 1;
1171 init_params->enableWeightedPrediction = self->weighted_pred;
1173 if (gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (info),
1174 GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_PAR_N (info),
1175 GST_VIDEO_INFO_PAR_D (info), &dar_n, &dar_d) && dar_n > 0
1177 init_params->darWidth = dar_n;
1178 init_params->darHeight = dar_d;
1181 if (GST_VIDEO_INFO_IS_INTERLACED (info) && dev_caps->field_encoding > 0) {
1182 switch (GST_VIDEO_INFO_INTERLACE_MODE (info)) {
1183 case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
1184 case GST_VIDEO_INTERLACE_MODE_MIXED:
1185 config->frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
1186 preset_config.presetCfg.frameFieldMode =
1187 NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
1194 gst_nv_encoder_preset_to_guid (self->preset, &init_params->presetGUID);
1196 preset_config.version = gst_nvenc_get_preset_config_version ();
1197 preset_config.presetCfg.version = gst_nvenc_get_config_version ();
1199 status = NvEncGetEncodePresetConfig (session, NV_ENC_CODEC_H264_GUID,
1200 init_params->presetGUID, &preset_config);
1201 if (status != NV_ENC_SUCCESS) {
1202 GST_ERROR_OBJECT (self, "Failed to get preset config %"
1203 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1204 g_mutex_unlock (&self->prop_lock);
1208 *config = preset_config.presetCfg;
1209 if (self->gop_size < 0) {
1210 config->gopLength = NVENC_INFINITE_GOPLENGTH;
1211 config->frameIntervalP = 1;
1212 } else if (self->gop_size > 0) {
1213 config->gopLength = self->gop_size;
1215 * 0: All Intra frames
1220 config->frameIntervalP = 1;
1221 if (self->bframes > 0 && !downstream_supports_bframe) {
1222 GST_WARNING_OBJECT (self,
1223 "B-frame was enabled but downstream profile does not support it");
1224 bframe_aborted = TRUE;
1228 config->frameIntervalP = self->bframes + 1;
1230 /* gop size == 0 means all intra frames */
1231 config->gopLength = 1;
1232 config->frameIntervalP = 0;
1235 rc_params = &config->rcParams;
1236 rc_mode = self->rc_mode;
1239 rc_params->averageBitRate = self->bitrate * 1024;
1240 if (self->max_bitrate)
1241 rc_params->maxBitRate = self->max_bitrate * 1024;
1242 if (self->vbv_buffer_size)
1243 rc_params->vbvBufferSize = self->vbv_buffer_size * 1024;
1245 if (self->min_qp_i >= 0) {
1246 rc_params->enableMinQP = TRUE;
1247 rc_params->minQP.qpIntra = self->min_qp_i;
1248 if (self->min_qp_p >= 0) {
1249 rc_params->minQP.qpInterP = self->min_qp_p;
1251 rc_params->minQP.qpInterP = rc_params->minQP.qpIntra;
1253 if (self->min_qp_b >= 0) {
1254 rc_params->minQP.qpInterB = self->min_qp_b;
1256 rc_params->minQP.qpInterB = rc_params->minQP.qpInterP;
1260 if (self->max_qp_i >= 0) {
1261 rc_params->enableMaxQP = TRUE;
1262 rc_params->maxQP.qpIntra = self->max_qp_i;
1263 if (self->max_qp_p >= 0) {
1264 rc_params->maxQP.qpInterP = self->max_qp_p;
1266 rc_params->maxQP.qpInterP = rc_params->maxQP.qpIntra;
1268 if (self->max_qp_b >= 0) {
1269 rc_params->maxQP.qpInterB = self->max_qp_b;
1271 rc_params->maxQP.qpInterB = rc_params->maxQP.qpInterP;
1275 if (rc_mode == GST_NV_ENCODER_RC_MODE_CONSTQP) {
1276 if (self->qp_i >= 0)
1277 rc_params->constQP.qpIntra = self->qp_i;
1278 if (self->qp_p >= 0)
1279 rc_params->constQP.qpInterP = self->qp_p;
1280 if (self->qp_p >= 0)
1281 rc_params->constQP.qpInterB = self->qp_b;
1284 rc_params->rateControlMode = gst_nv_encoder_rc_mode_to_native (rc_mode);
1286 if (self->spatial_aq) {
1287 rc_params->enableAQ = TRUE;
1288 rc_params->aqStrength = self->aq_strength;
1291 rc_params->enableTemporalAQ = self->temporal_aq;
1293 if (self->rc_lookahead) {
1294 rc_params->enableLookahead = 1;
1295 rc_params->lookaheadDepth = self->rc_lookahead;
1296 rc_params->disableIadapt = !self->i_adapt;
1297 rc_params->disableBadapt = !self->b_adapt;
1300 rc_params->strictGOPTarget = self->strict_gop;
1301 rc_params->enableNonRefP = self->non_ref_p;
1302 rc_params->zeroReorderDelay = self->zero_reorder_delay;
1304 if (self->const_quality) {
1305 guint scaled = (gint) (self->const_quality * 256.0);
1307 rc_params->targetQuality = (guint8) (scaled >> 8);
1308 rc_params->targetQualityLSB = (guint8) (scaled & 0xff);
1310 self->init_param_updated = FALSE;
1311 self->bitrate_updated = FALSE;
1312 self->rc_param_updated = FALSE;
1314 if (selected_profile == NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID &&
1315 config->frameIntervalP > 1) {
1316 if (downstream_profiles.find ("main") != downstream_profiles.end ()) {
1317 selected_profile = NV_ENC_H264_PROFILE_MAIN_GUID;
1318 } else if (downstream_profiles.find ("high") != downstream_profiles.end ()) {
1319 selected_profile = NV_ENC_H264_PROFILE_HIGH_GUID;
1320 } else if (downstream_profiles.find ("progressive-high") !=
1321 downstream_profiles.end ()) {
1322 selected_profile = NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID;
1326 /* Pick the first profile */
1327 if (selected_profile == NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID) {
1328 if (*downstream_profiles.begin () == "baseline" ||
1329 *downstream_profiles.begin () == "constrained-baseline") {
1330 selected_profile = NV_ENC_H264_PROFILE_BASELINE_GUID;
1331 } else if (*downstream_profiles.begin () == "main") {
1332 selected_profile = NV_ENC_H264_PROFILE_MAIN_GUID;
1333 } else if (*downstream_profiles.begin () == "progressive-high") {
1334 selected_profile = NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID;
1335 } else if (*downstream_profiles.begin () == "constrained-high") {
1336 selected_profile = NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID;
1340 config->profileGUID = selected_profile;
1342 h264_config = &config->encodeCodecConfig.h264Config;
1343 vui = &h264_config->h264VUIParameters;
1345 h264_config->level = NV_ENC_LEVEL_AUTOSELECT;
1346 h264_config->chromaFormatIDC = 1;
1347 if (selected_profile == NV_ENC_H264_PROFILE_HIGH_444_GUID)
1348 h264_config->chromaFormatIDC = 3;
1349 h264_config->idrPeriod = config->gopLength;
1350 h264_config->outputAUD = self->aud;
1351 if (self->repeat_sequence_header) {
1352 h264_config->disableSPSPPS = 0;
1353 h264_config->repeatSPSPPS = 1;
1355 if (self->packetized)
1356 h264_config->disableSPSPPS = 1;
1358 h264_config->disableSPSPPS = 0;
1361 if (dev_caps->cabac && selected_profile != NV_ENC_H264_PROFILE_BASELINE_GUID) {
1363 h264_config->entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CABAC;
1365 h264_config->entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC;
1367 h264_config->entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_AUTOSELECT;
1370 vui->videoSignalTypePresentFlag = 1;
1372 vui->videoFormat = 5;
1373 if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) {
1374 vui->videoFullRangeFlag = 1;
1376 vui->videoFullRangeFlag = 0;
1379 vui->colourDescriptionPresentFlag = 1;
1380 vui->colourMatrix = gst_video_color_matrix_to_iso (info->colorimetry.matrix);
1381 vui->colourPrimaries =
1382 gst_video_color_primaries_to_iso (info->colorimetry.primaries);
1383 vui->transferCharacteristics =
1384 gst_video_transfer_function_to_iso (info->colorimetry.transfer);
1386 g_mutex_unlock (&self->prop_lock);
1389 g_object_notify (G_OBJECT (self), "b-frames");
1390 if (weight_pred_aborted)
1391 g_object_notify (G_OBJECT (self), "weighted-pred");
1392 if (vbv_buffer_size_aborted)
1393 g_object_notify (G_OBJECT (self), "vbv-buffer-size");
1394 if (lookahead_aborted)
1395 g_object_notify (G_OBJECT (self), "rc-lookahead");
1396 if (temporal_aq_aborted)
1397 g_object_notify (G_OBJECT (self), "temporal-aq");
1403 gst_nv_h264_encoder_set_output_state (GstNvEncoder * encoder,
1404 GstVideoCodecState * state, gpointer session)
1406 GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1407 GstVideoCodecState *output_state;
1408 NV_ENC_SEQUENCE_PARAM_PAYLOAD seq_params = { 0, };
1409 guint8 spspps[1024];
1412 const gchar *profile_from_sps;
1414 std::set < std::string > downstream_profiles;
1415 std::string caps_str;
1417 GstBuffer *codec_data = nullptr;
1418 GstH264NalUnit sps_nalu, pps_nalu;
1419 GstH264ParserResult rst;
1421 caps_str = "video/x-h264, alignment = (string) au";
1423 gst_nv_h264_encoder_get_downstream_profiles_and_format (self,
1424 downstream_profiles, nullptr);
1426 seq_params.version = gst_nvenc_get_sequence_param_payload_version ();
1427 seq_params.inBufferSize = sizeof (spspps);
1428 seq_params.spsppsBuffer = &spspps;
1429 seq_params.outSPSPPSPayloadSize = &seq_size;
1430 status = NvEncGetSequenceParams (session, &seq_params);
1431 if (status != NV_ENC_SUCCESS) {
1432 GST_ERROR_OBJECT (self, "Failed to get sequence header, status %"
1433 GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1437 rst = gst_h264_parser_identify_nalu (self->parser,
1438 spspps, 0, seq_size, &sps_nalu);
1439 if (rst != GST_H264_PARSER_OK) {
1440 GST_ERROR_OBJECT (self, "Failed to identify SPS nal");
1444 if (sps_nalu.size < 4) {
1445 GST_ERROR_OBJECT (self, "Too small sps nal size %d", sps_nalu.size);
1449 rst = gst_h264_parser_identify_nalu_unchecked (self->parser,
1450 spspps, sps_nalu.offset + sps_nalu.size, seq_size, &pps_nalu);
1451 if (rst != GST_H264_PARSER_OK && self->packetized) {
1452 GST_ERROR_OBJECT (self, "Failed to identify PPS nal, %d", rst);
1456 if (self->packetized) {
1459 guint8 profile_idc, profile_comp, level_idc;
1460 const guint nal_length_size = 4;
1461 const guint num_sps = 1;
1462 const guint num_pps = 1;
1464 data = sps_nalu.data + sps_nalu.offset + sps_nalu.header_bytes;
1465 profile_idc = data[0];
1466 profile_comp = data[1];
1467 level_idc = data[2];
1469 /* 5: configuration version, profile, compatibility, level, nal length
1477 * -> 11 + sps_size + pps_size
1479 codec_data = gst_buffer_new_and_alloc (11 + sps_nalu.size + pps_nalu.size);
1481 gst_buffer_map (codec_data, &info, GST_MAP_WRITE);
1483 data = (guint8 *) info.data;
1485 data[1] = profile_idc;
1486 data[2] = profile_comp;
1487 data[3] = level_idc;
1488 data[4] = 0xfc | (nal_length_size - 1);
1489 data[5] = 0xe0 | num_sps;
1491 GST_WRITE_UINT16_BE (data, sps_nalu.size);
1493 memcpy (data, sps_nalu.data + sps_nalu.offset, sps_nalu.size);
1494 data += sps_nalu.size;
1499 GST_WRITE_UINT16_BE (data, pps_nalu.size);
1501 memcpy (data, pps_nalu.data + pps_nalu.offset, pps_nalu.size);
1503 gst_buffer_unmap (codec_data, &info);
1507 gst_codec_utils_h264_get_profile (sps_nalu.data + sps_nalu.offset +
1508 sps_nalu.header_bytes, 3);
1510 if (!profile_from_sps) {
1511 GST_WARNING_OBJECT (self, "Failed to parse profile from SPS");
1512 } else if (!downstream_profiles.empty ()) {
1513 if (downstream_profiles.find (profile_from_sps) !=
1514 downstream_profiles.end ()) {
1515 caps_str += ", profile = (string) " + std::string (profile_from_sps);
1516 } else if (downstream_profiles.find ("baseline") !=
1517 downstream_profiles.end () &&
1518 strcmp (profile_from_sps, "constrained-baseline") == 0) {
1519 caps_str += ", profile = (string) baseline";
1520 } else if (downstream_profiles.find ("constrained-baseline") !=
1521 downstream_profiles.end () &&
1522 strcmp (profile_from_sps, "constrained-baseline") == 0) {
1523 caps_str += ", profile = (string) constrained-baseline";
1526 caps_str += ", profile = (string) " + std::string (profile_from_sps);
1529 if (self->packetized) {
1530 caps_str += ", stream-format = (string) avc";
1532 caps_str += ", stream-format = (string) byte-stream";
1535 caps = gst_caps_from_string (caps_str.c_str ());
1537 if (self->packetized) {
1538 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data,
1540 gst_buffer_unref (codec_data);
1543 output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1546 GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
1547 gst_video_codec_state_unref (output_state);
1549 tags = gst_tag_list_new_empty ();
1550 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1551 "nvh264encoder", nullptr);
1553 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
1554 tags, GST_TAG_MERGE_REPLACE);
1555 gst_tag_list_unref (tags);
1561 gst_nv_h264_encoder_create_output_buffer (GstNvEncoder * encoder,
1562 NV_ENC_LOCK_BITSTREAM * bitstream)
1564 GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1566 GstH264ParserResult rst;
1567 GstH264NalUnit nalu;
1569 if (!self->packetized) {
1570 return gst_buffer_new_memdup (bitstream->bitstreamBufferPtr,
1571 bitstream->bitstreamSizeInBytes);
1574 buffer = gst_buffer_new ();
1575 rst = gst_h264_parser_identify_nalu (self->parser,
1576 (guint8 *) bitstream->bitstreamBufferPtr, 0,
1577 bitstream->bitstreamSizeInBytes, &nalu);
1579 if (rst == GST_H264_PARSER_NO_NAL_END)
1580 rst = GST_H264_PARSER_OK;
1582 while (rst == GST_H264_PARSER_OK) {
1586 data = (guint8 *) g_malloc0 (nalu.size + 4);
1587 GST_WRITE_UINT32_BE (data, nalu.size);
1588 memcpy (data + 4, nalu.data + nalu.offset, nalu.size);
1590 mem = gst_memory_new_wrapped ((GstMemoryFlags) 0, data, nalu.size + 4,
1591 0, nalu.size + 4, data, (GDestroyNotify) g_free);
1592 gst_buffer_append_memory (buffer, mem);
1594 rst = gst_h264_parser_identify_nalu (self->parser,
1595 (guint8 *) bitstream->bitstreamBufferPtr, nalu.offset + nalu.size,
1596 bitstream->bitstreamSizeInBytes, &nalu);
1598 if (rst == GST_H264_PARSER_NO_NAL_END)
1599 rst = GST_H264_PARSER_OK;
1605 static GstNvEncoderReconfigure
1606 gst_nv_h264_encoder_check_reconfigure (GstNvEncoder * encoder,
1607 NV_ENC_CONFIG * config)
1609 GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1610 GstNvEncoderReconfigure reconfig = GST_NV_ENCODER_RECONFIGURE_NONE;
1612 /* Dynamic RC param update is not tested, do soft-reconfigure only for
1614 g_mutex_lock (&self->prop_lock);
1615 if (self->init_param_updated || self->rc_param_updated) {
1616 reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1620 if (self->bitrate_updated) {
1621 GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
1622 if (klass->device_caps.dyn_bitrate_change > 0) {
1623 config->rcParams.averageBitRate = self->bitrate * 1024;
1624 config->rcParams.maxBitRate = self->max_bitrate * 1024;
1625 reconfig = GST_NV_ENCODER_RECONFIGURE_BITRATE;
1627 reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1632 self->init_param_updated = FALSE;
1633 self->rc_param_updated = FALSE;
1634 self->bitrate_updated = FALSE;
1635 g_mutex_unlock (&self->prop_lock);
1641 gst_nv_h264_encoder_select_device (GstNvEncoder * encoder,
1642 const GstVideoInfo * info, GstBuffer * buffer,
1643 GstNvEncoderDeviceData * data)
1645 GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1646 GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
1649 memset (data, 0, sizeof (GstNvEncoderDeviceData));
1651 g_assert (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT);
1653 mem = gst_buffer_peek_memory (buffer, 0);
1654 if (klass->cuda_device_id_size > 0 && gst_is_cuda_memory (mem)) {
1655 GstCudaMemory *cmem = GST_CUDA_MEMORY_CAST (mem);
1656 GstCudaContext *context = cmem->context;
1658 gboolean found = FALSE;
1660 g_object_get (context, "cuda-device-id", &device_id, nullptr);
1662 data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1663 self->selected_device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1665 for (guint i = 0; i < klass->cuda_device_id_size; i++) {
1666 if (klass->cuda_device_id_list[i] == device_id) {
1667 data->cuda_device_id = device_id;
1674 GST_INFO_OBJECT (self,
1675 "Upstream CUDA device is not in supported device list");
1676 data->cuda_device_id = self->cuda_device_id;
1678 data->device = (GstObject *) gst_object_ref (context);
1681 if (data->cuda_device_id != self->cuda_device_id) {
1682 self->cuda_device_id = data->cuda_device_id;
1683 g_object_notify (G_OBJECT (self), "cuda-device-id");
1688 #ifdef GST_CUDA_HAS_D3D
1689 if (klass->adapter_luid_size > 0 && gst_is_d3d11_memory (mem)) {
1690 GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
1691 GstD3D11Device *device = dmem->device;
1692 gint64 adapter_luid;
1693 gboolean found = FALSE;
1695 g_object_get (device, "adapter-luid", &adapter_luid, nullptr);
1697 data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1698 self->selected_device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1700 for (guint i = 0; i < klass->cuda_device_id_size; i++) {
1701 if (klass->adapter_luid_list[i] == adapter_luid) {
1702 data->adapter_luid = adapter_luid;
1709 GST_INFO_OBJECT (self,
1710 "Upstream D3D11 device is not in supported device list");
1711 data->adapter_luid = self->adapter_luid;
1713 data->device = (GstObject *) gst_object_ref (device);
1716 if (data->adapter_luid != self->adapter_luid) {
1717 self->adapter_luid = data->adapter_luid;
1718 g_object_notify (G_OBJECT (self), "adapter-luid");
1725 if (klass->cuda_device_id_size > 0 &&
1726 (self->selected_device_mode != GST_NV_ENCODER_DEVICE_D3D11)) {
1727 GST_INFO_OBJECT (self, "Upstream is system memory, use CUDA mode");
1728 data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1729 data->cuda_device_id = self->cuda_device_id;
1731 GST_INFO_OBJECT (self, "Upstream is system memory, use D3D11 mode");
1732 data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1733 data->adapter_luid = klass->adapter_luid;
1736 self->selected_device_mode = data->device_mode;
1741 static GstNvEncoderClassData *
1742 gst_nv_h264_encoder_create_class_data (GstObject * device, gpointer session,
1743 GstNvEncoderDeviceMode device_mode)
1746 GstNvEncoderDeviceCaps dev_caps = { 0, };
1747 GUID profile_guids[16];
1748 NV_ENC_BUFFER_FORMAT input_formats[16];
1749 guint32 profile_guid_count = 0;
1750 guint32 input_format_count = 0;
1751 std::string sink_caps_str;
1752 std::string src_caps_str;
1753 std::string format_str;
1754 std::set < std::string > formats;
1755 std::set < std::string > profiles;
1756 std::string profile_str;
1757 std::string resolution_str;
1758 GstNvEncoderClassData *cdata;
1760 GstCaps *system_caps;
1762 status = NvEncGetEncodeProfileGUIDs (session, NV_ENC_CODEC_H264_GUID,
1763 profile_guids, G_N_ELEMENTS (profile_guids), &profile_guid_count);
1764 if (status != NV_ENC_SUCCESS || profile_guid_count == 0) {
1765 GST_WARNING_OBJECT (device, "Unable to get supported profiles");
1769 status = NvEncGetInputFormats (session, NV_ENC_CODEC_H264_GUID, input_formats,
1770 G_N_ELEMENTS (input_formats), &input_format_count);
1771 if (status != NV_ENC_SUCCESS || input_format_count == 0) {
1772 GST_WARNING_OBJECT (device, "Unable to get supported input formats");
1776 gst_nv_encoder_get_encoder_caps (session, &NV_ENC_CODEC_H264_GUID, &dev_caps);
1778 for (guint32 i = 0; i < input_format_count; i++) {
1779 switch (input_formats[i]) {
1780 case NV_ENC_BUFFER_FORMAT_NV12:
1781 formats.insert ("NV12");
1783 case NV_ENC_BUFFER_FORMAT_YUV444:
1784 if (dev_caps.yuv444_encode)
1785 formats.insert ("Y444");
1792 if (formats.empty ()) {
1793 GST_WARNING_OBJECT (device, "Empty supported input format");
1796 #define APPEND_STRING(dst,set,str) G_STMT_START { \
1797 if (set.find(str) != set.end()) { \
1805 if (formats.size () == 1) {
1806 format_str = "format = (string) " + *(formats.begin ());
1810 format_str = "format = (string) { ";
1811 APPEND_STRING (format_str, formats, "NV12");
1812 APPEND_STRING (format_str, formats, "Y444");
1816 for (guint32 i = 0; i < profile_guid_count; i++) {
1817 if (profile_guids[i] == NV_ENC_H264_PROFILE_BASELINE_GUID) {
1818 profiles.insert ("baseline");
1819 profiles.insert ("constrained-baseline");
1820 } else if (profile_guids[i] == NV_ENC_H264_PROFILE_MAIN_GUID) {
1821 profiles.insert ("main");
1822 } else if (profile_guids[i] == NV_ENC_H264_PROFILE_HIGH_GUID) {
1823 profiles.insert ("high");
1824 } else if (profile_guids[i] == NV_ENC_H264_PROFILE_HIGH_444_GUID) {
1825 profiles.insert ("high-4:4:4");
1826 } else if (profile_guids[i] == NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID) {
1827 profiles.insert ("progressive-high");
1828 } else if (profile_guids[i] == NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID) {
1829 profiles.insert ("constrained-high");
1833 if (profiles.empty ()) {
1834 GST_WARNING_OBJECT (device, "Empty supported h264 profile");
1838 if (profiles.size () == 1) {
1839 profile_str = "profile = (string) " + *(profiles.begin ());
1843 profile_str = "profile = (string) { ";
1844 APPEND_STRING (profile_str, profiles, "main");
1845 APPEND_STRING (profile_str, profiles, "high");
1846 APPEND_STRING (profile_str, profiles, "progressive-high");
1847 APPEND_STRING (profile_str, profiles, "constrained-high");
1848 APPEND_STRING (profile_str, profiles, "constrained-baseline");
1849 APPEND_STRING (profile_str, profiles, "baseline");
1850 APPEND_STRING (profile_str, profiles, "high-4:4:4");
1851 profile_str += " }";
1853 #undef APPEND_STRING
1855 resolution_str = "width = (int) [ " +
1856 std::to_string (GST_ROUND_UP_16 (dev_caps.width_min))
1857 + ", " + std::to_string (dev_caps.width_max) + " ]";
1858 resolution_str += ", height = (int) [ " +
1859 std::to_string (GST_ROUND_UP_16 (dev_caps.height_min))
1860 + ", " + std::to_string (dev_caps.height_max) + " ]";
1862 sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str;
1864 if (dev_caps.field_encoding > 0) {
1865 sink_caps_str += ", interlace-mode = (string) { interleaved, mixed }";
1867 sink_caps_str += ", interlace-mode = (string) progressive";
1870 src_caps_str = "video/x-h264, " + resolution_str + ", " + profile_str +
1871 ", stream-format = (string) { avc, byte-stream }, alignment = (string) au";
1873 system_caps = gst_caps_from_string (sink_caps_str.c_str ());
1874 sink_caps = gst_caps_copy (system_caps);
1875 #ifdef GST_CUDA_HAS_D3D
1876 if (device_mode == GST_NV_ENCODER_DEVICE_D3D11) {
1877 gst_caps_set_features (sink_caps, 0,
1878 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
1882 if (device_mode == GST_NV_ENCODER_DEVICE_CUDA) {
1883 gst_caps_set_features (sink_caps, 0,
1884 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr));
1887 gst_caps_append (sink_caps, system_caps);
1889 cdata = gst_nv_encoder_class_data_new ();
1890 cdata->sink_caps = sink_caps;
1891 cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
1892 cdata->device_caps = dev_caps;
1893 cdata->device_mode = device_mode;
1896 for (const auto &iter: formats)
1897 cdata->formats = g_list_append (cdata->formats, g_strdup (iter.c_str()));
1899 for (const auto &iter: profiles)
1900 cdata->profiles = g_list_append (cdata->profiles, g_strdup (iter.c_str()));
1903 if (device_mode == GST_NV_ENCODER_DEVICE_D3D11)
1904 g_object_get (device, "adapter-luid", &cdata->adapter_luid, nullptr);
1906 if (device_mode == GST_NV_ENCODER_DEVICE_CUDA)
1907 g_object_get (device, "cuda-device-id", &cdata->cuda_device_id, nullptr);
1909 /* class data will be leaked if the element never gets instantiated */
1910 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1911 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1912 GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
1913 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1918 GstNvEncoderClassData *
1919 gst_nv_h264_encoder_register_cuda (GstPlugin * plugin, GstCudaContext * context,
1922 NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
1925 GstNvEncoderClassData *cdata;
1927 GST_DEBUG_CATEGORY_INIT (gst_nv_h264_encoder_debug, "nvh264encoder", 0,
1930 session_params.version =
1931 gst_nvenc_get_open_encode_session_ex_params_version ();
1932 session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
1933 session_params.device = gst_cuda_context_get_handle (context);
1934 session_params.apiVersion = gst_nvenc_get_api_version ();
1936 status = NvEncOpenEncodeSessionEx (&session_params, &session);
1937 if (status != NV_ENC_SUCCESS) {
1938 GST_WARNING_OBJECT (context, "Failed to open session");
1942 cdata = gst_nv_h264_encoder_create_class_data (GST_OBJECT (context), session,
1943 GST_NV_ENCODER_DEVICE_CUDA);
1944 NvEncDestroyEncoder (session);
1949 gst_nv_encoder_class_data_ref (cdata);
1953 gchar *feature_name;
1954 GTypeInfo type_info = {
1955 sizeof (GstNvH264EncoderClass),
1958 (GClassInitFunc) gst_nv_h264_encoder_class_init,
1961 sizeof (GstNvH264Encoder),
1963 (GInstanceInitFunc) gst_nv_h264_encoder_init,
1966 type_name = g_strdup ("GstNvCudaH264Enc");
1967 feature_name = g_strdup ("nvcudah264enc");
1970 while (g_type_from_name (type_name)) {
1973 g_free (feature_name);
1974 type_name = g_strdup_printf ("GstNvCudaH264Device%dEnc", index);
1975 feature_name = g_strdup_printf ("nvcudah264device%denc", index);
1978 type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
1979 &type_info, (GTypeFlags) 0);
1981 if (rank > 0 && index != 0)
1985 gst_element_type_set_skip_documentation (type);
1987 if (!gst_element_register (plugin, feature_name, rank, type))
1988 GST_WARNING ("Failed to register plugin '%s'", type_name);
1991 g_free (feature_name);
1996 #ifdef GST_CUDA_HAS_D3D
1997 GstNvEncoderClassData *
1998 gst_nv_h264_encoder_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
2001 NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
2004 GstNvEncoderClassData *cdata;
2006 GST_DEBUG_CATEGORY_INIT (gst_nv_h264_encoder_debug, "nvh264encoder", 0,
2009 session_params.version =
2010 gst_nvenc_get_open_encode_session_ex_params_version ();
2011 session_params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
2012 session_params.device = gst_d3d11_device_get_device_handle (device);
2013 session_params.apiVersion = gst_nvenc_get_api_version ();
2015 status = NvEncOpenEncodeSessionEx (&session_params, &session);
2016 if (status != NV_ENC_SUCCESS) {
2017 GST_WARNING_OBJECT (device, "Failed to open session");
2021 cdata = gst_nv_h264_encoder_create_class_data (GST_OBJECT (device), session,
2022 GST_NV_ENCODER_DEVICE_D3D11);
2023 NvEncDestroyEncoder (session);
2028 gst_nv_encoder_class_data_ref (cdata);
2032 gchar *feature_name;
2033 GTypeInfo type_info = {
2034 sizeof (GstNvH264EncoderClass),
2037 (GClassInitFunc) gst_nv_h264_encoder_class_init,
2040 sizeof (GstNvH264Encoder),
2042 (GInstanceInitFunc) gst_nv_h264_encoder_init,
2045 type_name = g_strdup ("GstNvD3D11H264Enc");
2046 feature_name = g_strdup ("nvd3d11h264enc");
2049 while (g_type_from_name (type_name)) {
2052 g_free (feature_name);
2053 type_name = g_strdup_printf ("GstNvD3D11H264Device%dEnc", index);
2054 feature_name = g_strdup_printf ("nvd3d11h264device%denc", index);
2057 type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
2058 &type_info, (GTypeFlags) 0);
2060 if (rank > 0 && index != 0)
2064 gst_element_type_set_skip_documentation (type);
2066 if (!gst_element_register (plugin, feature_name, rank, type))
2067 GST_WARNING ("Failed to register plugin '%s'", type_name);
2070 g_free (feature_name);
2077 gst_nv_h264_encoder_register_auto_select (GstPlugin * plugin,
2078 GList * device_caps_list, guint rank)
2080 std::set < std::string > formats;
2081 std::set < std::string > profiles;
2082 std::string sink_caps_str;
2083 std::string src_caps_str;
2084 std::string format_str;
2085 std::string profile_str;
2086 std::string resolution_str;
2088 guint adapter_luid_size = 0;
2089 gint64 adapter_luid_list[8];
2090 guint cuda_device_id_size = 0;
2091 guint cuda_device_id_list[8];
2092 GstNvEncoderDeviceCaps dev_caps;
2093 GstNvEncoderClassData *cdata;
2094 GstCaps *sink_caps = nullptr;
2095 GstCaps *system_caps;
2097 GST_DEBUG_CATEGORY_INIT (gst_nv_h264_encoder_debug, "nvh264encoder", 0,
2100 for (iter = device_caps_list; iter; iter = g_list_next (iter)) {
2101 GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) iter->data;
2104 for (walk = cdata->formats; walk; walk = g_list_next (walk))
2105 formats.insert ((gchar *) walk->data);
2107 for (walk = cdata->profiles; walk; walk = g_list_next (walk))
2108 profiles.insert ((gchar *) walk->data);
2110 if (cdata->device_mode == GST_NV_ENCODER_DEVICE_D3D11 &&
2111 adapter_luid_size < G_N_ELEMENTS (adapter_luid_list) - 1) {
2112 adapter_luid_list[adapter_luid_size] = cdata->adapter_luid;
2113 adapter_luid_size++;
2116 if (cdata->device_mode == GST_NV_ENCODER_DEVICE_CUDA &&
2117 cuda_device_id_size < G_N_ELEMENTS (cuda_device_id_list) - 1) {
2118 cuda_device_id_list[cuda_device_id_size] = cdata->cuda_device_id;
2119 cuda_device_id_size++;
2122 if (iter == device_caps_list) {
2123 dev_caps = cdata->device_caps;
2125 gst_nv_encoder_merge_device_caps (&dev_caps, &cdata->device_caps,
2130 g_list_free_full (device_caps_list,
2131 (GDestroyNotify) gst_nv_encoder_class_data_unref);
2132 if (formats.empty () || profiles.empty ())
2135 #define APPEND_STRING(dst,set,str) G_STMT_START { \
2136 if (set.find(str) != set.end()) { \
2144 if (formats.size () == 1) {
2145 format_str = "format = (string) " + *(formats.begin ());
2149 format_str = "format = (string) { ";
2150 APPEND_STRING (format_str, formats, "NV12");
2151 APPEND_STRING (format_str, formats, "Y444");
2155 if (profiles.size () == 1) {
2156 profile_str = "profile = (string) " + *(profiles.begin ());
2160 profile_str = "profile = (string) { ";
2161 APPEND_STRING (profile_str, profiles, "main");
2162 APPEND_STRING (profile_str, profiles, "high");
2163 APPEND_STRING (profile_str, profiles, "progressive-high");
2164 APPEND_STRING (profile_str, profiles, "constrained-high");
2165 APPEND_STRING (profile_str, profiles, "constrained-baseline");
2166 APPEND_STRING (profile_str, profiles, "baseline");
2167 APPEND_STRING (profile_str, profiles, "high-4:4:4");
2168 profile_str += " }";
2170 #undef APPEND_STRING
2172 resolution_str = "width = (int) [ " +
2173 std::to_string (GST_ROUND_UP_16 (dev_caps.width_min))
2174 + ", " + std::to_string (dev_caps.width_max) + " ]";
2175 resolution_str += ", height = (int) [ " +
2176 std::to_string (GST_ROUND_UP_16 (dev_caps.height_min))
2177 + ", " + std::to_string (dev_caps.height_max) + " ]";
2179 sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str;
2181 if (dev_caps.field_encoding > 0) {
2182 sink_caps_str += ", interlace-mode = (string) { interleaved, mixed }";
2184 sink_caps_str += ", interlace-mode = (string) progressive";
2187 src_caps_str = "video/x-h264, " + resolution_str + ", " + profile_str +
2188 ", stream-format = (string) { avc, byte-stream }, alignment = (string) au";
2190 system_caps = gst_caps_from_string (sink_caps_str.c_str ());
2191 sink_caps = gst_caps_new_empty ();
2193 if (cuda_device_id_size > 0) {
2194 GstCaps *cuda_caps = gst_caps_copy (system_caps);
2195 gst_caps_set_features (cuda_caps, 0,
2196 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr));
2197 gst_caps_append (sink_caps, cuda_caps);
2199 #ifdef GST_CUDA_HAS_D3D
2200 if (adapter_luid_size > 0) {
2201 GstCaps *d3d11_caps = gst_caps_copy (system_caps);
2202 gst_caps_set_features (d3d11_caps, 0,
2203 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
2204 gst_caps_append (sink_caps, d3d11_caps);
2208 gst_caps_append (sink_caps, system_caps);
2210 cdata = gst_nv_encoder_class_data_new ();
2211 cdata->sink_caps = sink_caps;
2212 cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
2213 cdata->device_caps = dev_caps;
2214 cdata->device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
2215 cdata->adapter_luid = adapter_luid_list[0];
2216 cdata->adapter_luid_size = adapter_luid_size;
2217 memcpy (&cdata->adapter_luid_list,
2218 adapter_luid_list, sizeof (adapter_luid_list));
2219 cdata->cuda_device_id = cuda_device_id_list[0];
2220 cdata->cuda_device_id_size = cuda_device_id_size;
2221 memcpy (&cdata->cuda_device_id_list,
2222 cuda_device_id_list, sizeof (cuda_device_id_list));
2224 /* class data will be leaked if the element never gets instantiated */
2225 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
2226 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2227 GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
2228 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2231 GTypeInfo type_info = {
2232 sizeof (GstNvH264EncoderClass),
2235 (GClassInitFunc) gst_nv_h264_encoder_class_init,
2238 sizeof (GstNvH264Encoder),
2240 (GInstanceInitFunc) gst_nv_h264_encoder_init,
2243 type = g_type_register_static (GST_TYPE_NV_ENCODER, "GstNvAutoGpuH264Enc",
2244 &type_info, (GTypeFlags) 0);
2246 if (!gst_element_register (plugin, "nvautogpuh264enc", rank, type))
2247 GST_WARNING ("Failed to register plugin 'GstNvAutoGpuH264Enc'");