nvcodec: Update for documentation
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / nvcodec / gstnvh264encoder.cpp
1 /* GStreamer
2  * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * element-nvcudah264enc:
22  *
23  * NVIDIA CUDA mode H.264 encoder
24  *
25  * Since: 1.22
26  */
27
28 /**
29  * element-nvd3d11h264enc:
30  *
31  * NVIDIA Direct3D11 mode H.264 encoder
32  *
33  * Since: 1.22
34  */
35
36 /**
37  * element-nvautogpuh264enc:
38  *
39  * NVIDIA auto GPU select mode H.264 encoder
40  *
41  * Since: 1.22
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "gstnvh264encoder.h"
49 #include <gst/codecparsers/gsth264parser.h>
50 #include <gst/pbutils/codec-utils.h>
51 #include <string>
52 #include <set>
53 #include <string.h>
54
55 GST_DEBUG_CATEGORY_STATIC (gst_nv_h264_encoder_debug);
56 #define GST_CAT_DEFAULT gst_nv_h264_encoder_debug
57
58 static GTypeClass *parent_class = nullptr;
59
60 enum
61 {
62   PROP_0,
63   PROP_ADAPTER_LUID,
64   PROP_CUDA_DEVICE_ID,
65
66   /* init params */
67   PROP_PRESET,
68   PROP_WEIGHTED_PRED,
69
70   /* encoding config */
71   PROP_GOP_SIZE,
72   PROP_B_FRAMES,
73
74   /* rate-control params */
75   PROP_RATE_CONTROL,
76
77   PROP_QP_I,
78   PROP_QP_P,
79   PROP_QP_B,
80
81   PROP_BITRATE,
82   PROP_MAX_BITRATE,
83   PROP_VBV_BUFFER_SIZE,
84
85   PROP_RC_LOOKAHEAD,
86   PROP_I_ADAPT,
87   PROP_B_ADAPT,
88   PROP_SPATIAL_AQ,
89   PROP_TEMPORAL_AQ,
90   PROP_ZERO_REORDER_DELAY,
91   PROP_NON_REF_P,
92   PROP_STRICT_GOP,
93   PROP_AQ_STRENGTH,
94
95   PROP_MIN_QP_I,
96   PROP_MIN_QP_P,
97   PROP_MIN_QP_B,
98
99   PROP_MAX_QP_I,
100   PROP_MAX_QP_P,
101   PROP_MAX_QP_B,
102
103   PROP_CONST_QUALITY,
104
105   /* h264 specific */
106   PROP_AUD,
107   PROP_CABAC,
108   PROP_REPEAT_SEQUENCE_HEADER,
109 };
110
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
132
133 typedef struct _GstNvH264Encoder
134 {
135   GstNvEncoder parent;
136   GMutex prop_lock;
137
138   gboolean init_param_updated;
139   gboolean rc_param_updated;
140   gboolean bitrate_updated;
141
142   gboolean packetized;
143   GstH264NalParser *parser;
144
145   GstNvEncoderDeviceMode selected_device_mode;
146
147   /* Properties */
148   guint cuda_device_id;
149   gint64 adapter_luid;
150
151   GstNvEncoderPreset preset;
152   gboolean weighted_pred;
153
154   gint gop_size;
155   guint bframes;
156
157   GstNvEncoderRCMode rc_mode;
158   gint qp_i;
159   gint qp_p;
160   gint qp_b;
161   guint bitrate;
162   guint max_bitrate;
163   guint vbv_buffer_size;
164   guint rc_lookahead;
165   gboolean i_adapt;
166   gboolean b_adapt;
167   gboolean spatial_aq;
168   gboolean temporal_aq;
169   gboolean zero_reorder_delay;
170   gboolean non_ref_p;
171   gboolean strict_gop;
172   guint aq_strength;
173   gint min_qp_i;
174   gint min_qp_p;
175   gint min_qp_b;
176   gint max_qp_i;
177   gint max_qp_p;
178   gint max_qp_b;
179   gdouble const_quality;
180
181   gboolean aud;
182   gboolean cabac;
183   gboolean repeat_sequence_header;
184 } GstNvH264Encoder;
185
186 typedef struct _GstNvH264EncoderClass
187 {
188   GstNvEncoderClass parent_class;
189
190   guint cuda_device_id;
191   gint64 adapter_luid;
192
193   GstNvEncoderDeviceMode device_mode;
194
195   /* representative device caps */
196   GstNvEncoderDeviceCaps device_caps;
197
198   /* auto gpu select mode */
199   guint cuda_device_id_size;
200   guint cuda_device_id_list[8];
201
202   guint adapter_luid_size;
203   gint64 adapter_luid_list[8];
204 } GstNvH264EncoderClass;
205
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))
209
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,
216     GstCaps * filter);
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);
230
231 static void
232 gst_nv_h264_encoder_class_init (GstNvH264EncoderClass * klass, gpointer data)
233 {
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);
245
246   parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
247
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;
251
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",
257               0, G_MAXINT, 0,
258               (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
259                   G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
260       break;
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)));
268       break;
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",
274                 0, G_MAXINT, 0,
275                 (GParamFlags) (conditional_param_flags |
276                     GST_PARAM_DOC_SHOW_DEFAULT)));
277       }
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)));
285       }
286       break;
287     default:
288       g_assert_not_reached ();
289       break;
290   }
291
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));
301   }
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));
311   }
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));
341   }
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));
356     }
357   }
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));
366   }
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,
374           param_flags));
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,
378           param_flags));
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));
419   }
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));
424
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>");
432       break;
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>");
439       break;
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>");
446       break;
447     default:
448       g_assert_not_reached ();
449       break;
450   }
451
452   gst_element_class_add_pad_template (element_class,
453       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
454           cdata->sink_caps));
455   gst_element_class_add_pad_template (element_class,
456       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
457           cdata->src_caps));
458
459   videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_nv_h264_encoder_getcaps);
460
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);
470
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));
481
482   gst_nv_encoder_class_data_unref (cdata);
483 }
484
485 static void
486 gst_nv_h264_encoder_init (GstNvH264Encoder * self)
487 {
488   GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
489
490   g_mutex_init (&self->prop_lock);
491
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)
524     self->cabac = TRUE;
525   self->repeat_sequence_header = DEFAULT_REPEAT_SEQUENCE_HEADER;
526
527   self->parser = gst_h264_nal_parser_new ();
528
529   gst_nv_encoder_set_device_mode (GST_NV_ENCODER (self), klass->device_mode,
530       klass->cuda_device_id, klass->adapter_luid);
531 }
532
533 static void
534 gst_nv_h264_encoder_finalize (GObject * object)
535 {
536   GstNvH264Encoder *self = GST_NV_H264_ENCODER (object);
537
538   g_mutex_clear (&self->prop_lock);
539   gst_h264_nal_parser_free (self->parser);
540
541   G_OBJECT_CLASS (parent_class)->finalize (object);
542 }
543
544 typedef enum
545 {
546   UPDATE_INIT_PARAM,
547   UPDATE_RC_PARAM,
548   UPDATE_BITRATE,
549 } PropUpdateLevel;
550
551 static void
552 update_boolean (GstNvH264Encoder * self, gboolean * old_val,
553     const GValue * new_val, PropUpdateLevel level)
554 {
555   gboolean val = g_value_get_boolean (new_val);
556
557   if (*old_val == val)
558     return;
559
560   *old_val = val;
561   switch (level) {
562     case UPDATE_INIT_PARAM:
563       self->init_param_updated = TRUE;
564       break;
565     case UPDATE_RC_PARAM:
566       self->rc_param_updated = TRUE;
567       break;
568     case UPDATE_BITRATE:
569       self->bitrate_updated = TRUE;
570       break;
571   }
572 }
573
574 static void
575 update_int (GstNvH264Encoder * self, gint * old_val,
576     const GValue * new_val, PropUpdateLevel level)
577 {
578   gint val = g_value_get_int (new_val);
579
580   if (*old_val == val)
581     return;
582
583   *old_val = val;
584   switch (level) {
585     case UPDATE_INIT_PARAM:
586       self->init_param_updated = TRUE;
587       break;
588     case UPDATE_RC_PARAM:
589       self->rc_param_updated = TRUE;
590       break;
591     case UPDATE_BITRATE:
592       self->bitrate_updated = TRUE;
593       break;
594   }
595 }
596
597 static void
598 update_uint (GstNvH264Encoder * self, guint * old_val,
599     const GValue * new_val, PropUpdateLevel level)
600 {
601   guint val = g_value_get_uint (new_val);
602
603   if (*old_val == val)
604     return;
605
606   *old_val = val;
607   switch (level) {
608     case UPDATE_INIT_PARAM:
609       self->init_param_updated = TRUE;
610       break;
611     case UPDATE_RC_PARAM:
612       self->rc_param_updated = TRUE;
613       break;
614     case UPDATE_BITRATE:
615       self->bitrate_updated = TRUE;
616       break;
617   }
618 }
619
620 static void
621 update_double (GstNvH264Encoder * self, gdouble * old_val,
622     const GValue * new_val, PropUpdateLevel level)
623 {
624   gdouble val = g_value_get_double (new_val);
625
626   if (*old_val == val)
627     return;
628
629   *old_val = val;
630   switch (level) {
631     case UPDATE_INIT_PARAM:
632       self->init_param_updated = TRUE;
633       break;
634     case UPDATE_RC_PARAM:
635       self->rc_param_updated = TRUE;
636       break;
637     case UPDATE_BITRATE:
638       self->bitrate_updated = TRUE;
639       break;
640   }
641 }
642
643 static void
644 gst_nv_h264_encoder_set_property (GObject * object, guint prop_id,
645     const GValue * value, GParamSpec * pspec)
646 {
647   GstNvH264Encoder *self = GST_NV_H264_ENCODER (object);
648   GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
649
650   g_mutex_lock (&self->prop_lock);
651   switch (prop_id) {
652     case PROP_ADAPTER_LUID:{
653       gint64 adapter_luid = g_value_get_int64 (value);
654       gboolean is_valid = FALSE;
655
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;
659           is_valid = TRUE;
660           break;
661         }
662       }
663
664       if (!is_valid)
665         g_warning ("%" G_GINT64_FORMAT " is not a valid adapter luid",
666             adapter_luid);
667       break;
668     }
669     case PROP_CUDA_DEVICE_ID:{
670       guint cuda_device_id = g_value_get_uint (value);
671       gboolean is_valid = FALSE;
672
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;
676           is_valid = TRUE;
677           break;
678         }
679       }
680
681       if (!is_valid)
682         g_warning ("%d is not a valid cuda device id", cuda_device_id);
683       break;
684     }
685     case PROP_PRESET:{
686       GstNvEncoderPreset preset = (GstNvEncoderPreset) g_value_get_enum (value);
687       if (preset != self->preset) {
688         self->preset = preset;
689         self->init_param_updated = TRUE;
690       }
691       break;
692     }
693     case PROP_WEIGHTED_PRED:
694       update_boolean (self, &self->weighted_pred, value, UPDATE_INIT_PARAM);
695       break;
696     case PROP_GOP_SIZE:
697       update_int (self, &self->gop_size, value, UPDATE_INIT_PARAM);
698       break;
699     case PROP_B_FRAMES:
700       update_uint (self, &self->bframes, value, UPDATE_INIT_PARAM);
701       break;
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;
707       }
708       break;
709     }
710     case PROP_QP_I:
711       update_int (self, &self->qp_i, value, UPDATE_RC_PARAM);
712       break;
713     case PROP_QP_P:
714       update_int (self, &self->qp_p, value, UPDATE_RC_PARAM);
715       break;
716     case PROP_QP_B:
717       update_int (self, &self->qp_b, value, UPDATE_RC_PARAM);
718       break;
719     case PROP_BITRATE:
720       update_uint (self, &self->bitrate, value, UPDATE_BITRATE);
721       break;
722     case PROP_MAX_BITRATE:
723       update_uint (self, &self->max_bitrate, value, UPDATE_BITRATE);
724       break;
725     case PROP_VBV_BUFFER_SIZE:
726       update_uint (self, &self->vbv_buffer_size, value, UPDATE_RC_PARAM);
727       break;
728     case PROP_RC_LOOKAHEAD:
729       /* rc-lookahead update requires pool size change */
730       update_uint (self, &self->rc_lookahead, value, UPDATE_INIT_PARAM);
731       break;
732     case PROP_I_ADAPT:
733       update_boolean (self, &self->i_adapt, value, UPDATE_RC_PARAM);
734       break;
735     case PROP_B_ADAPT:
736       update_boolean (self, &self->b_adapt, value, UPDATE_RC_PARAM);
737       break;
738     case PROP_SPATIAL_AQ:
739       update_boolean (self, &self->spatial_aq, value, UPDATE_RC_PARAM);
740       break;
741     case PROP_TEMPORAL_AQ:
742       update_boolean (self, &self->temporal_aq, value, UPDATE_RC_PARAM);
743       break;
744     case PROP_ZERO_REORDER_DELAY:
745       update_boolean (self, &self->zero_reorder_delay, value, UPDATE_RC_PARAM);
746       break;
747     case PROP_NON_REF_P:
748       update_boolean (self, &self->non_ref_p, value, UPDATE_RC_PARAM);
749       break;
750     case PROP_STRICT_GOP:
751       update_boolean (self, &self->strict_gop, value, UPDATE_RC_PARAM);
752       break;
753     case PROP_AQ_STRENGTH:
754       update_uint (self, &self->aq_strength, value, UPDATE_RC_PARAM);
755       break;
756     case PROP_MIN_QP_I:
757       update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
758       break;
759     case PROP_MIN_QP_P:
760       update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
761       break;
762     case PROP_MIN_QP_B:
763       update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
764       break;
765     case PROP_MAX_QP_I:
766       update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
767       break;
768     case PROP_MAX_QP_P:
769       update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
770       break;
771     case PROP_MAX_QP_B:
772       update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
773       break;
774     case PROP_CONST_QUALITY:
775       update_double (self, &self->const_quality, value, UPDATE_RC_PARAM);
776       break;
777     case PROP_AUD:
778       update_boolean (self, &self->aud, value, UPDATE_INIT_PARAM);
779       break;
780     case PROP_CABAC:
781       update_boolean (self, &self->cabac, value, UPDATE_INIT_PARAM);
782       break;
783     case PROP_REPEAT_SEQUENCE_HEADER:
784       update_boolean (self,
785           &self->repeat_sequence_header, value, UPDATE_INIT_PARAM);
786       break;
787     default:
788       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
789       break;
790   }
791
792   g_mutex_unlock (&self->prop_lock);
793 }
794
795 static void
796 gst_nv_h264_encoder_get_property (GObject * object, guint prop_id,
797     GValue * value, GParamSpec * pspec)
798 {
799   GstNvH264Encoder *self = GST_NV_H264_ENCODER (object);
800
801   switch (prop_id) {
802     case PROP_ADAPTER_LUID:
803       g_value_set_int64 (value, self->adapter_luid);
804       break;
805     case PROP_CUDA_DEVICE_ID:
806       g_value_set_uint (value, self->cuda_device_id);
807       break;
808     case PROP_PRESET:
809       g_value_set_enum (value, self->preset);
810       break;
811     case PROP_WEIGHTED_PRED:
812       g_value_set_boolean (value, self->weighted_pred);
813       break;
814     case PROP_GOP_SIZE:
815       g_value_set_int (value, self->gop_size);
816       break;
817     case PROP_B_FRAMES:
818       g_value_set_uint (value, self->bframes);
819       break;
820     case PROP_RATE_CONTROL:
821       g_value_set_enum (value, self->rc_mode);
822       break;
823     case PROP_QP_I:
824       g_value_set_int (value, self->qp_i);
825       break;
826     case PROP_QP_P:
827       g_value_set_int (value, self->qp_p);
828       break;
829     case PROP_QP_B:
830       g_value_set_int (value, self->qp_b);
831       break;
832     case PROP_BITRATE:
833       g_value_set_uint (value, self->bitrate);
834       break;
835     case PROP_MAX_BITRATE:
836       g_value_set_uint (value, self->max_bitrate);
837       break;
838     case PROP_VBV_BUFFER_SIZE:
839       g_value_set_uint (value, self->vbv_buffer_size);
840       break;
841     case PROP_RC_LOOKAHEAD:
842       g_value_set_uint (value, self->rc_lookahead);
843       break;
844     case PROP_I_ADAPT:
845       g_value_set_boolean (value, self->i_adapt);
846       break;
847     case PROP_B_ADAPT:
848       g_value_set_boolean (value, self->b_adapt);
849       break;
850     case PROP_SPATIAL_AQ:
851       g_value_set_boolean (value, self->spatial_aq);
852       break;
853     case PROP_TEMPORAL_AQ:
854       g_value_set_boolean (value, self->temporal_aq);
855       break;
856     case PROP_ZERO_REORDER_DELAY:
857       g_value_set_boolean (value, self->zero_reorder_delay);
858       break;
859     case PROP_NON_REF_P:
860       g_value_set_boolean (value, self->non_ref_p);
861       break;
862     case PROP_STRICT_GOP:
863       g_value_set_boolean (value, self->strict_gop);
864       break;
865     case PROP_AQ_STRENGTH:
866       g_value_set_uint (value, self->aq_strength);
867       break;
868     case PROP_MIN_QP_I:
869       g_value_set_int (value, self->min_qp_i);
870       break;
871     case PROP_MIN_QP_P:
872       g_value_set_int (value, self->min_qp_p);
873       break;
874     case PROP_MIN_QP_B:
875       g_value_set_int (value, self->min_qp_b);
876       break;
877     case PROP_MAX_QP_I:
878       g_value_set_int (value, self->max_qp_i);
879       break;
880     case PROP_MAX_QP_P:
881       g_value_set_int (value, self->max_qp_p);
882       break;
883     case PROP_MAX_QP_B:
884       g_value_set_int (value, self->max_qp_b);
885       break;
886     case PROP_CONST_QUALITY:
887       g_value_set_double (value, self->const_quality);
888       break;
889     case PROP_AUD:
890       g_value_set_boolean (value, self->aud);
891       break;
892     case PROP_CABAC:
893       g_value_set_boolean (value, self->cabac);
894       break;
895     case PROP_REPEAT_SEQUENCE_HEADER:
896       g_value_set_boolean (value, self->repeat_sequence_header);
897       break;
898     default:
899       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
900       break;
901   }
902 }
903
904 static void
905 gst_nv_h264_encoder_get_downstream_profiles_and_format (GstNvH264Encoder * self,
906     std::set < std::string > &downstream_profiles, gboolean * packetized)
907 {
908   GstCaps *allowed_caps;
909   GstStructure *s;
910   const gchar *stream_format;
911
912   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
913
914   if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
915       gst_caps_is_any (allowed_caps)) {
916     gst_clear_caps (&allowed_caps);
917
918     return;
919   }
920
921   for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
922     const GValue *profile_value;
923     const gchar *profile;
924
925     s = gst_caps_get_structure (allowed_caps, i);
926     profile_value = gst_structure_get_value (s, "profile");
927     if (!profile_value)
928       continue;
929
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);
933
934         if (!G_VALUE_HOLDS_STRING (p))
935           continue;
936
937         profile = g_value_get_string (p);
938         if (profile)
939           downstream_profiles.insert (profile);
940       }
941
942     } else if (G_VALUE_HOLDS_STRING (profile_value)) {
943       profile = g_value_get_string (profile_value);
944       if (profile)
945         downstream_profiles.insert (profile);
946     }
947   }
948
949   if (packetized) {
950     *packetized = FALSE;
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)
955       *packetized = TRUE;
956   }
957
958   gst_caps_unref (allowed_caps);
959 }
960
961 static GstCaps *
962 gst_nv_h264_encoder_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
963 {
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;
973
974   gst_nv_h264_encoder_get_downstream_profiles_and_format (self,
975       downstream_profiles, nullptr);
976
977   GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
978       downstream_profiles.size ());
979
980   if (downstream_profiles.size () == 0)
981     return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
982
983   /* *INDENT-OFF* */
984   for (const auto &iter: downstream_profiles) {
985     if (iter == "high" || iter == "main") {
986       profile_support_interlaced = TRUE;
987     }
988
989     if (iter == "high-4:4:4") {
990       profile_support_interlaced = TRUE;
991       allowed_formats.insert("Y444");
992     } else {
993       allowed_formats.insert("NV12");
994     }
995   }
996   /* *INDENT-ON* */
997
998   GST_DEBUG_OBJECT (self, "Downstream %s support interlaced format",
999       profile_support_interlaced ? "can" : "cannot");
1000
1001   template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
1002   allowed_caps = gst_caps_copy (template_caps);
1003
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);
1007   }
1008
1009   GValue formats = G_VALUE_INIT;
1010
1011   g_value_init (&formats, GST_TYPE_LIST);
1012   /* *INDENT-OFF* */
1013   for (const auto &iter: allowed_formats) {
1014     GValue val = G_VALUE_INIT;
1015     g_value_init (&val, G_TYPE_STRING);
1016
1017     g_value_set_string (&val, iter.c_str());
1018     gst_value_list_append_and_take_value (&formats, &val);
1019   }
1020   /* *INDENT-ON* */
1021
1022   gst_caps_set_value (allowed_caps, "format", &formats);
1023   g_value_unset (&formats);
1024
1025   filtered_caps = gst_caps_intersect_full (template_caps, allowed_caps,
1026       GST_CAPS_INTERSECT_FIRST);
1027
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);
1033
1034   GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
1035
1036   return supported_caps;
1037 }
1038
1039 static gboolean
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)
1043 {
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;
1049   NVENCSTATUS status;
1050   NV_ENC_PRESET_CONFIG preset_config = { 0, };
1051   gint dar_n, dar_d;
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;
1063
1064   self->packetized = FALSE;
1065
1066   gst_nv_h264_encoder_get_downstream_profiles_and_format (self,
1067       downstream_profiles, &self->packetized);
1068
1069   if (downstream_profiles.empty ()) {
1070     GST_ERROR_OBJECT (self, "Unable to get downstream profile");
1071     return FALSE;
1072   }
1073
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");
1079
1080     if (downstream_profiles.empty ()) {
1081       GST_ERROR_OBJECT (self,
1082           "None of downstream profile supports interlaced encoding");
1083       return FALSE;
1084     }
1085   }
1086
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");
1090       return FALSE;
1091     } else {
1092       selected_profile = NV_ENC_H264_PROFILE_HIGH_444_GUID;
1093       downstream_supports_bframe = TRUE;
1094     }
1095   } else {
1096     /* *INDENT-OFF* */
1097     for (const auto &iter: downstream_profiles) {
1098       if (iter == "high" || iter == "main" || iter == "progressive-high") {
1099         downstream_supports_bframe = TRUE;
1100       }
1101     }
1102     /* *INDENT-ON* */
1103   }
1104
1105   g_mutex_lock (&self->prop_lock);
1106
1107   if (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1108     GstNvEncoderDeviceCaps dev_caps;
1109
1110     gst_nv_encoder_get_encoder_caps (session,
1111         &NV_ENC_CODEC_H264_GUID, &dev_caps);
1112
1113     if (self->bframes > 0 && !dev_caps.max_bframes) {
1114       self->bframes = 0;
1115       bframe_aborted = TRUE;
1116
1117       GST_INFO_OBJECT (self, "B-frame was enabled but not support by device");
1118     }
1119
1120     if (self->weighted_pred && !dev_caps.weighted_prediction) {
1121       self->weighted_pred = FALSE;
1122       weight_pred_aborted = TRUE;
1123
1124       GST_INFO_OBJECT (self,
1125           "Weighted prediction was enabled but not support by device");
1126     }
1127
1128     if (self->vbv_buffer_size && !dev_caps.custom_vbv_buf_size) {
1129       self->vbv_buffer_size = 0;
1130       vbv_buffer_size_aborted = TRUE;
1131
1132       GST_INFO_OBJECT (self,
1133           "VBV buffer size was specified but not supported by device");
1134     }
1135
1136     if (self->rc_lookahead && !dev_caps.lookahead) {
1137       self->rc_lookahead = 0;
1138       lookahead_aborted = TRUE;
1139
1140       GST_INFO_OBJECT (self,
1141           "VBV buffer size was specified but not supported by device");
1142     }
1143
1144     if (self->temporal_aq && !dev_caps.temporal_aq) {
1145       self->temporal_aq = FALSE;
1146       temporal_aq_aborted = TRUE;
1147
1148       GST_INFO_OBJECT (self,
1149           "temporal-aq was enabled but not supported by device");
1150     }
1151   }
1152
1153   init_params->version = gst_nvenc_get_initialize_params_version ();
1154   init_params->encodeGUID = NV_ENC_CODEC_H264_GUID;
1155
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;
1166   } else {
1167     init_params->frameRateNum = 0;
1168     init_params->frameRateDen = 1;
1169   }
1170
1171   init_params->enableWeightedPrediction = self->weighted_pred;
1172
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
1176       && dar_d > 0) {
1177     init_params->darWidth = dar_n;
1178     init_params->darHeight = dar_d;
1179   }
1180
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;
1188         break;
1189       default:
1190         break;
1191     }
1192   }
1193
1194   gst_nv_encoder_preset_to_guid (self->preset, &init_params->presetGUID);
1195
1196   preset_config.version = gst_nvenc_get_preset_config_version ();
1197   preset_config.presetCfg.version = gst_nvenc_get_config_version ();
1198
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);
1205     return FALSE;
1206   }
1207
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;
1214     /* frameIntervalP
1215      * 0: All Intra frames
1216      * 1: I/P only
1217      * 2: IBP
1218      * 3: IBBP
1219      */
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;
1225       self->bframes = 0;
1226     }
1227
1228     config->frameIntervalP = self->bframes + 1;
1229   } else {
1230     /* gop size == 0 means all intra frames */
1231     config->gopLength = 1;
1232     config->frameIntervalP = 0;
1233   }
1234
1235   rc_params = &config->rcParams;
1236   rc_mode = self->rc_mode;
1237
1238   if (self->bitrate)
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;
1244
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;
1250     } else {
1251       rc_params->minQP.qpInterP = rc_params->minQP.qpIntra;
1252     }
1253     if (self->min_qp_b >= 0) {
1254       rc_params->minQP.qpInterB = self->min_qp_b;
1255     } else {
1256       rc_params->minQP.qpInterB = rc_params->minQP.qpInterP;
1257     }
1258   }
1259
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;
1265     } else {
1266       rc_params->maxQP.qpInterP = rc_params->maxQP.qpIntra;
1267     }
1268     if (self->max_qp_b >= 0) {
1269       rc_params->maxQP.qpInterB = self->max_qp_b;
1270     } else {
1271       rc_params->maxQP.qpInterB = rc_params->maxQP.qpInterP;
1272     }
1273   }
1274
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;
1282   }
1283
1284   rc_params->rateControlMode = gst_nv_encoder_rc_mode_to_native (rc_mode);
1285
1286   if (self->spatial_aq) {
1287     rc_params->enableAQ = TRUE;
1288     rc_params->aqStrength = self->aq_strength;
1289   }
1290
1291   rc_params->enableTemporalAQ = self->temporal_aq;
1292
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;
1298   }
1299
1300   rc_params->strictGOPTarget = self->strict_gop;
1301   rc_params->enableNonRefP = self->non_ref_p;
1302   rc_params->zeroReorderDelay = self->zero_reorder_delay;
1303
1304   if (self->const_quality) {
1305     guint scaled = (gint) (self->const_quality * 256.0);
1306
1307     rc_params->targetQuality = (guint8) (scaled >> 8);
1308     rc_params->targetQualityLSB = (guint8) (scaled & 0xff);
1309   }
1310   self->init_param_updated = FALSE;
1311   self->bitrate_updated = FALSE;
1312   self->rc_param_updated = FALSE;
1313
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;
1323     }
1324   }
1325
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;
1337     }
1338   }
1339
1340   config->profileGUID = selected_profile;
1341
1342   h264_config = &config->encodeCodecConfig.h264Config;
1343   vui = &h264_config->h264VUIParameters;
1344
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;
1354   } else {
1355     if (self->packetized)
1356       h264_config->disableSPSPPS = 1;
1357     else
1358       h264_config->disableSPSPPS = 0;
1359   }
1360
1361   if (dev_caps->cabac && selected_profile != NV_ENC_H264_PROFILE_BASELINE_GUID) {
1362     if (self->cabac)
1363       h264_config->entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CABAC;
1364     else
1365       h264_config->entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC;
1366   } else {
1367     h264_config->entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_AUTOSELECT;
1368   }
1369
1370   vui->videoSignalTypePresentFlag = 1;
1371   /* Unspecified */
1372   vui->videoFormat = 5;
1373   if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) {
1374     vui->videoFullRangeFlag = 1;
1375   } else {
1376     vui->videoFullRangeFlag = 0;
1377   }
1378
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);
1385
1386   g_mutex_unlock (&self->prop_lock);
1387
1388   if (bframe_aborted)
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");
1398
1399   return TRUE;
1400 }
1401
1402 static gboolean
1403 gst_nv_h264_encoder_set_output_state (GstNvEncoder * encoder,
1404     GstVideoCodecState * state, gpointer session)
1405 {
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];
1410   guint32 seq_size;
1411   GstCaps *caps;
1412   const gchar *profile_from_sps;
1413   NVENCSTATUS status;
1414   std::set < std::string > downstream_profiles;
1415   std::string caps_str;
1416   GstTagList *tags;
1417   GstBuffer *codec_data = nullptr;
1418   GstH264NalUnit sps_nalu, pps_nalu;
1419   GstH264ParserResult rst;
1420
1421   caps_str = "video/x-h264, alignment = (string) au";
1422
1423   gst_nv_h264_encoder_get_downstream_profiles_and_format (self,
1424       downstream_profiles, nullptr);
1425
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));
1434     return FALSE;
1435   }
1436
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");
1441     return FALSE;
1442   }
1443
1444   if (sps_nalu.size < 4) {
1445     GST_ERROR_OBJECT (self, "Too small sps nal size %d", sps_nalu.size);
1446     return FALSE;
1447   }
1448
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);
1453     return FALSE;
1454   }
1455
1456   if (self->packetized) {
1457     GstMapInfo info;
1458     guint8 *data;
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;
1463
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];
1468
1469     /* 5: configuration version, profile, compatibility, level, nal length
1470      * 1: num sps
1471      * 2: sps size bytes
1472      * sizeof (sps)
1473      * 1: num pps
1474      * 2: pps size bytes
1475      * sizeof (pps)
1476      *
1477      * -> 11 + sps_size + pps_size
1478      */
1479     codec_data = gst_buffer_new_and_alloc (11 + sps_nalu.size + pps_nalu.size);
1480
1481     gst_buffer_map (codec_data, &info, GST_MAP_WRITE);
1482
1483     data = (guint8 *) info.data;
1484     data[0] = 1;
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;
1490     data += 6;
1491     GST_WRITE_UINT16_BE (data, sps_nalu.size);
1492     data += 2;
1493     memcpy (data, sps_nalu.data + sps_nalu.offset, sps_nalu.size);
1494     data += sps_nalu.size;
1495
1496     data[0] = num_pps;
1497     data++;
1498
1499     GST_WRITE_UINT16_BE (data, pps_nalu.size);
1500     data += 2;
1501     memcpy (data, pps_nalu.data + pps_nalu.offset, pps_nalu.size);
1502
1503     gst_buffer_unmap (codec_data, &info);
1504   }
1505
1506   profile_from_sps =
1507       gst_codec_utils_h264_get_profile (sps_nalu.data + sps_nalu.offset +
1508       sps_nalu.header_bytes, 3);
1509
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";
1524     }
1525   } else {
1526     caps_str += ", profile = (string) " + std::string (profile_from_sps);
1527   }
1528
1529   if (self->packetized) {
1530     caps_str += ", stream-format = (string) avc";
1531   } else {
1532     caps_str += ", stream-format = (string) byte-stream";
1533   }
1534
1535   caps = gst_caps_from_string (caps_str.c_str ());
1536
1537   if (self->packetized) {
1538     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data,
1539         nullptr);
1540     gst_buffer_unref (codec_data);
1541   }
1542
1543   output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1544       caps, state);
1545
1546   GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
1547   gst_video_codec_state_unref (output_state);
1548
1549   tags = gst_tag_list_new_empty ();
1550   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1551       "nvh264encoder", nullptr);
1552
1553   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
1554       tags, GST_TAG_MERGE_REPLACE);
1555   gst_tag_list_unref (tags);
1556
1557   return TRUE;
1558 }
1559
1560 static GstBuffer *
1561 gst_nv_h264_encoder_create_output_buffer (GstNvEncoder * encoder,
1562     NV_ENC_LOCK_BITSTREAM * bitstream)
1563 {
1564   GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1565   GstBuffer *buffer;
1566   GstH264ParserResult rst;
1567   GstH264NalUnit nalu;
1568
1569   if (!self->packetized) {
1570     return gst_buffer_new_memdup (bitstream->bitstreamBufferPtr,
1571         bitstream->bitstreamSizeInBytes);
1572   }
1573
1574   buffer = gst_buffer_new ();
1575   rst = gst_h264_parser_identify_nalu (self->parser,
1576       (guint8 *) bitstream->bitstreamBufferPtr, 0,
1577       bitstream->bitstreamSizeInBytes, &nalu);
1578
1579   if (rst == GST_H264_PARSER_NO_NAL_END)
1580     rst = GST_H264_PARSER_OK;
1581
1582   while (rst == GST_H264_PARSER_OK) {
1583     GstMemory *mem;
1584     guint8 *data;
1585
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);
1589
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);
1593
1594     rst = gst_h264_parser_identify_nalu (self->parser,
1595         (guint8 *) bitstream->bitstreamBufferPtr, nalu.offset + nalu.size,
1596         bitstream->bitstreamSizeInBytes, &nalu);
1597
1598     if (rst == GST_H264_PARSER_NO_NAL_END)
1599       rst = GST_H264_PARSER_OK;
1600   }
1601
1602   return buffer;
1603 }
1604
1605 static GstNvEncoderReconfigure
1606 gst_nv_h264_encoder_check_reconfigure (GstNvEncoder * encoder,
1607     NV_ENC_CONFIG * config)
1608 {
1609   GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1610   GstNvEncoderReconfigure reconfig = GST_NV_ENCODER_RECONFIGURE_NONE;
1611
1612   /* Dynamic RC param update is not tested, do soft-reconfigure only for
1613    * bitrate update */
1614   g_mutex_lock (&self->prop_lock);
1615   if (self->init_param_updated || self->rc_param_updated) {
1616     reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1617     goto done;
1618   }
1619
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;
1626     } else {
1627       reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1628     }
1629   }
1630
1631 done:
1632   self->init_param_updated = FALSE;
1633   self->rc_param_updated = FALSE;
1634   self->bitrate_updated = FALSE;
1635   g_mutex_unlock (&self->prop_lock);
1636
1637   return reconfig;
1638 }
1639
1640 static gboolean
1641 gst_nv_h264_encoder_select_device (GstNvEncoder * encoder,
1642     const GstVideoInfo * info, GstBuffer * buffer,
1643     GstNvEncoderDeviceData * data)
1644 {
1645   GstNvH264Encoder *self = GST_NV_H264_ENCODER (encoder);
1646   GstNvH264EncoderClass *klass = GST_NV_H264_ENCODER_GET_CLASS (self);
1647   GstMemory *mem;
1648
1649   memset (data, 0, sizeof (GstNvEncoderDeviceData));
1650
1651   g_assert (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT);
1652
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;
1657     guint device_id;
1658     gboolean found = FALSE;
1659
1660     g_object_get (context, "cuda-device-id", &device_id, nullptr);
1661
1662     data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1663     self->selected_device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1664
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;
1668         found = TRUE;
1669         break;
1670       }
1671     }
1672
1673     if (!found) {
1674       GST_INFO_OBJECT (self,
1675           "Upstream CUDA device is not in supported device list");
1676       data->cuda_device_id = self->cuda_device_id;
1677     } else {
1678       data->device = (GstObject *) gst_object_ref (context);
1679     }
1680
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");
1684     }
1685
1686     return TRUE;
1687   }
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;
1694
1695     g_object_get (device, "adapter-luid", &adapter_luid, nullptr);
1696
1697     data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1698     self->selected_device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1699
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;
1703         found = TRUE;
1704         break;
1705       }
1706     }
1707
1708     if (!found) {
1709       GST_INFO_OBJECT (self,
1710           "Upstream D3D11 device is not in supported device list");
1711       data->adapter_luid = self->adapter_luid;
1712     } else {
1713       data->device = (GstObject *) gst_object_ref (device);
1714     }
1715
1716     if (data->adapter_luid != self->adapter_luid) {
1717       self->adapter_luid = data->adapter_luid;
1718       g_object_notify (G_OBJECT (self), "adapter-luid");
1719     }
1720
1721     return TRUE;
1722   }
1723 #endif
1724
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;
1730   } else {
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;
1734   }
1735
1736   self->selected_device_mode = data->device_mode;
1737
1738   return TRUE;
1739 }
1740
1741 static GstNvEncoderClassData *
1742 gst_nv_h264_encoder_create_class_data (GstObject * device, gpointer session,
1743     GstNvEncoderDeviceMode device_mode)
1744 {
1745   NVENCSTATUS status;
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;
1759   GstCaps *sink_caps;
1760   GstCaps *system_caps;
1761
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");
1766     return nullptr;
1767   }
1768
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");
1773     return nullptr;
1774   }
1775
1776   gst_nv_encoder_get_encoder_caps (session, &NV_ENC_CODEC_H264_GUID, &dev_caps);
1777
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");
1782         break;
1783       case NV_ENC_BUFFER_FORMAT_YUV444:
1784         if (dev_caps.yuv444_encode)
1785           formats.insert ("Y444");
1786         break;
1787       default:
1788         break;
1789     }
1790   }
1791
1792   if (formats.empty ()) {
1793     GST_WARNING_OBJECT (device, "Empty supported input format");
1794     return nullptr;
1795   }
1796 #define APPEND_STRING(dst,set,str) G_STMT_START { \
1797   if (set.find(str) != set.end()) { \
1798     if (!first) \
1799       dst += ", "; \
1800     dst += str; \
1801     first = false; \
1802   } \
1803 } G_STMT_END
1804
1805   if (formats.size () == 1) {
1806     format_str = "format = (string) " + *(formats.begin ());
1807   } else {
1808     bool first = true;
1809
1810     format_str = "format = (string) { ";
1811     APPEND_STRING (format_str, formats, "NV12");
1812     APPEND_STRING (format_str, formats, "Y444");
1813     format_str += " }";
1814   }
1815
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");
1830     }
1831   }
1832
1833   if (profiles.empty ()) {
1834     GST_WARNING_OBJECT (device, "Empty supported h264 profile");
1835     return nullptr;
1836   }
1837
1838   if (profiles.size () == 1) {
1839     profile_str = "profile = (string) " + *(profiles.begin ());
1840   } else {
1841     bool first = true;
1842
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 += " }";
1852   }
1853 #undef APPEND_STRING
1854
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) + " ]";
1861
1862   sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str;
1863
1864   if (dev_caps.field_encoding > 0) {
1865     sink_caps_str += ", interlace-mode = (string) { interleaved, mixed }";
1866   } else {
1867     sink_caps_str += ", interlace-mode = (string) progressive";
1868   }
1869
1870   src_caps_str = "video/x-h264, " + resolution_str + ", " + profile_str +
1871       ", stream-format = (string) { avc, byte-stream }, alignment = (string) au";
1872
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));
1879   }
1880 #endif
1881
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));
1885   }
1886
1887   gst_caps_append (sink_caps, system_caps);
1888
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;
1894
1895   /* *INDENT-OFF* */
1896   for (const auto &iter: formats)
1897     cdata->formats = g_list_append (cdata->formats, g_strdup (iter.c_str()));
1898
1899   for (const auto &iter: profiles)
1900     cdata->profiles = g_list_append (cdata->profiles, g_strdup (iter.c_str()));
1901   /* *INDENT-ON* */
1902
1903   if (device_mode == GST_NV_ENCODER_DEVICE_D3D11)
1904     g_object_get (device, "adapter-luid", &cdata->adapter_luid, nullptr);
1905
1906   if (device_mode == GST_NV_ENCODER_DEVICE_CUDA)
1907     g_object_get (device, "cuda-device-id", &cdata->cuda_device_id, nullptr);
1908
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);
1914
1915   return cdata;
1916 }
1917
1918 GstNvEncoderClassData *
1919 gst_nv_h264_encoder_register_cuda (GstPlugin * plugin, GstCudaContext * context,
1920     guint rank)
1921 {
1922   NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
1923   gpointer session;
1924   NVENCSTATUS status;
1925   GstNvEncoderClassData *cdata;
1926
1927   GST_DEBUG_CATEGORY_INIT (gst_nv_h264_encoder_debug, "nvh264encoder", 0,
1928       "nvh264encoder");
1929
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 ();
1935
1936   status = NvEncOpenEncodeSessionEx (&session_params, &session);
1937   if (status != NV_ENC_SUCCESS) {
1938     GST_WARNING_OBJECT (context, "Failed to open session");
1939     return nullptr;
1940   }
1941
1942   cdata = gst_nv_h264_encoder_create_class_data (GST_OBJECT (context), session,
1943       GST_NV_ENCODER_DEVICE_CUDA);
1944   NvEncDestroyEncoder (session);
1945
1946   if (!cdata)
1947     return nullptr;
1948
1949   gst_nv_encoder_class_data_ref (cdata);
1950
1951   GType type;
1952   gchar *type_name;
1953   gchar *feature_name;
1954   GTypeInfo type_info = {
1955     sizeof (GstNvH264EncoderClass),
1956     nullptr,
1957     nullptr,
1958     (GClassInitFunc) gst_nv_h264_encoder_class_init,
1959     nullptr,
1960     cdata,
1961     sizeof (GstNvH264Encoder),
1962     0,
1963     (GInstanceInitFunc) gst_nv_h264_encoder_init,
1964   };
1965
1966   type_name = g_strdup ("GstNvCudaH264Enc");
1967   feature_name = g_strdup ("nvcudah264enc");
1968
1969   gint index = 0;
1970   while (g_type_from_name (type_name)) {
1971     index++;
1972     g_free (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);
1976   }
1977
1978   type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
1979       &type_info, (GTypeFlags) 0);
1980
1981   if (rank > 0 && index != 0)
1982     rank--;
1983
1984   if (index != 0)
1985     gst_element_type_set_skip_documentation (type);
1986
1987   if (!gst_element_register (plugin, feature_name, rank, type))
1988     GST_WARNING ("Failed to register plugin '%s'", type_name);
1989
1990   g_free (type_name);
1991   g_free (feature_name);
1992
1993   return cdata;
1994 }
1995
1996 #ifdef GST_CUDA_HAS_D3D
1997 GstNvEncoderClassData *
1998 gst_nv_h264_encoder_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
1999     guint rank)
2000 {
2001   NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
2002   gpointer session;
2003   NVENCSTATUS status;
2004   GstNvEncoderClassData *cdata;
2005
2006   GST_DEBUG_CATEGORY_INIT (gst_nv_h264_encoder_debug, "nvh264encoder", 0,
2007       "nvh264encoder");
2008
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 ();
2014
2015   status = NvEncOpenEncodeSessionEx (&session_params, &session);
2016   if (status != NV_ENC_SUCCESS) {
2017     GST_WARNING_OBJECT (device, "Failed to open session");
2018     return nullptr;
2019   }
2020
2021   cdata = gst_nv_h264_encoder_create_class_data (GST_OBJECT (device), session,
2022       GST_NV_ENCODER_DEVICE_D3D11);
2023   NvEncDestroyEncoder (session);
2024
2025   if (!cdata)
2026     return nullptr;
2027
2028   gst_nv_encoder_class_data_ref (cdata);
2029
2030   GType type;
2031   gchar *type_name;
2032   gchar *feature_name;
2033   GTypeInfo type_info = {
2034     sizeof (GstNvH264EncoderClass),
2035     nullptr,
2036     nullptr,
2037     (GClassInitFunc) gst_nv_h264_encoder_class_init,
2038     nullptr,
2039     cdata,
2040     sizeof (GstNvH264Encoder),
2041     0,
2042     (GInstanceInitFunc) gst_nv_h264_encoder_init,
2043   };
2044
2045   type_name = g_strdup ("GstNvD3D11H264Enc");
2046   feature_name = g_strdup ("nvd3d11h264enc");
2047
2048   gint index = 0;
2049   while (g_type_from_name (type_name)) {
2050     index++;
2051     g_free (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);
2055   }
2056
2057   type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
2058       &type_info, (GTypeFlags) 0);
2059
2060   if (rank > 0 && index != 0)
2061     rank--;
2062
2063   if (index != 0)
2064     gst_element_type_set_skip_documentation (type);
2065
2066   if (!gst_element_register (plugin, feature_name, rank, type))
2067     GST_WARNING ("Failed to register plugin '%s'", type_name);
2068
2069   g_free (type_name);
2070   g_free (feature_name);
2071
2072   return cdata;
2073 }
2074 #endif
2075
2076 void
2077 gst_nv_h264_encoder_register_auto_select (GstPlugin * plugin,
2078     GList * device_caps_list, guint rank)
2079 {
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;
2087   GList *iter;
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;
2096
2097   GST_DEBUG_CATEGORY_INIT (gst_nv_h264_encoder_debug, "nvh264encoder", 0,
2098       "nvh264encoder");
2099
2100   for (iter = device_caps_list; iter; iter = g_list_next (iter)) {
2101     GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) iter->data;
2102     GList *walk;
2103
2104     for (walk = cdata->formats; walk; walk = g_list_next (walk))
2105       formats.insert ((gchar *) walk->data);
2106
2107     for (walk = cdata->profiles; walk; walk = g_list_next (walk))
2108       profiles.insert ((gchar *) walk->data);
2109
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++;
2114     }
2115
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++;
2120     }
2121
2122     if (iter == device_caps_list) {
2123       dev_caps = cdata->device_caps;
2124     } else {
2125       gst_nv_encoder_merge_device_caps (&dev_caps, &cdata->device_caps,
2126           &dev_caps);
2127     }
2128   }
2129
2130   g_list_free_full (device_caps_list,
2131       (GDestroyNotify) gst_nv_encoder_class_data_unref);
2132   if (formats.empty () || profiles.empty ())
2133     return;
2134
2135 #define APPEND_STRING(dst,set,str) G_STMT_START { \
2136   if (set.find(str) != set.end()) { \
2137     if (!first) \
2138       dst += ", "; \
2139     dst += str; \
2140     first = false; \
2141   } \
2142 } G_STMT_END
2143
2144   if (formats.size () == 1) {
2145     format_str = "format = (string) " + *(formats.begin ());
2146   } else {
2147     bool first = true;
2148
2149     format_str = "format = (string) { ";
2150     APPEND_STRING (format_str, formats, "NV12");
2151     APPEND_STRING (format_str, formats, "Y444");
2152     format_str += " }";
2153   }
2154
2155   if (profiles.size () == 1) {
2156     profile_str = "profile = (string) " + *(profiles.begin ());
2157   } else {
2158     bool first = true;
2159
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 += " }";
2169   }
2170 #undef APPEND_STRING
2171
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) + " ]";
2178
2179   sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str;
2180
2181   if (dev_caps.field_encoding > 0) {
2182     sink_caps_str += ", interlace-mode = (string) { interleaved, mixed }";
2183   } else {
2184     sink_caps_str += ", interlace-mode = (string) progressive";
2185   }
2186
2187   src_caps_str = "video/x-h264, " + resolution_str + ", " + profile_str +
2188       ", stream-format = (string) { avc, byte-stream }, alignment = (string) au";
2189
2190   system_caps = gst_caps_from_string (sink_caps_str.c_str ());
2191   sink_caps = gst_caps_new_empty ();
2192
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);
2198   }
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);
2205   }
2206 #endif
2207
2208   gst_caps_append (sink_caps, system_caps);
2209
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));
2223
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);
2229
2230   GType type;
2231   GTypeInfo type_info = {
2232     sizeof (GstNvH264EncoderClass),
2233     nullptr,
2234     nullptr,
2235     (GClassInitFunc) gst_nv_h264_encoder_class_init,
2236     nullptr,
2237     cdata,
2238     sizeof (GstNvH264Encoder),
2239     0,
2240     (GInstanceInitFunc) gst_nv_h264_encoder_init,
2241   };
2242
2243   type = g_type_register_static (GST_TYPE_NV_ENCODER, "GstNvAutoGpuH264Enc",
2244       &type_info, (GTypeFlags) 0);
2245
2246   if (!gst_element_register (plugin, "nvautogpuh264enc", rank, type))
2247     GST_WARNING ("Failed to register plugin 'GstNvAutoGpuH264Enc'");
2248 }