nvcodec: Update for documentation
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / nvcodec / gstnvh265encoder.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-nvcudah265enc:
22  *
23  * NVIDIA CUDA mode H.265 encoder
24  *
25  * Since: 1.22
26  */
27
28 /**
29  * element-nvd3d11h265enc:
30  *
31  * NVIDIA Direct3D11 mode H.265 encoder
32  *
33  * Since: 1.22
34  */
35
36 /**
37  * element-nvautogpuh265enc:
38  *
39  * NVIDIA auto GPU select mode H.265 encoder
40  *
41  * Since: 1.22
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "gstnvh265encoder.h"
49 #include <gst/codecparsers/gsth265parser.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_h265_encoder_debug);
56 #define GST_CAT_DEFAULT gst_nv_h265_encoder_debug
57
58 static GTypeClass *parent_class = NULL;
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   /* h265 specific */
106   PROP_AUD,
107   PROP_REPEAT_SEQUENCE_HEADER,
108 };
109
110 #define DEFAULT_PRESET            GST_NV_ENCODER_PRESET_DEFAULT
111 #define DEFAULT_WEIGHTED_PRED     FALSE
112 #define DEFAULT_GOP_SIZE          30
113 #define DEFAULT_B_FRAMES          0
114 #define DEFAULT_RATE_CONTROL      GST_NV_ENCODER_RC_MODE_VBR
115 #define DEFAULT_QP                -1
116 #define DEFAULT_BITRATE           0
117 #define DEFAULT_MAX_BITRATE       0
118 #define DEFAULT_VBV_BUFFER_SIZE   0
119 #define DEFAULT_RC_LOOKAHEAD      0
120 #define DEFAULT_I_ADAPT           FALSE
121 #define DEFAULT_B_ADAPT           FALSE
122 #define DEFAULT_SPATIAL_AQ        FALSE
123 #define DEFAULT_TEMPORAL_AQ       FALSE
124 #define DEFAULT_ZERO_REORDER_DELAY FALSE
125 #define DEFAULT_NON_REF_P         FALSE
126 #define DEFAULT_STRICT_GOP        FALSE
127 #define DEFAULT_AQ_STRENGTH       FALSE
128 #define DEFAULT_CONST_QUALITY     0
129 #define DEFAULT_AUD               TRUE
130 #define DEFAULT_REPEAT_SEQUENCE_HEADER FALSE
131
132 typedef enum
133 {
134   GST_NV_H265_ENCODER_BYTE_STREAM,
135   GST_NV_H265_ENCODER_HVC1,
136   GST_NV_H265_ENCODER_HEV1,
137 } GstNvH265EncoderStreamFormat;
138
139 typedef struct _GstNvH265Encoder
140 {
141   GstNvEncoder parent;
142   GMutex prop_lock;
143
144   gboolean init_param_updated;
145   gboolean rc_param_updated;
146   gboolean bitrate_updated;
147
148   GstNvH265EncoderStreamFormat stream_format;
149   GstH265Parser *parser;
150
151   GstNvEncoderDeviceMode selected_device_mode;
152
153   /* Properties */
154   guint cuda_device_id;
155   gint64 adapter_luid;
156
157   GstNvEncoderPreset preset;
158   gboolean weighted_pred;
159
160   gint gop_size;
161   guint bframes;
162
163   GstNvEncoderRCMode rc_mode;
164   gint qp_i;
165   gint qp_p;
166   gint qp_b;
167   guint bitrate;
168   guint max_bitrate;
169   guint vbv_buffer_size;
170   guint rc_lookahead;
171   gboolean i_adapt;
172   gboolean b_adapt;
173   gboolean spatial_aq;
174   gboolean temporal_aq;
175   gboolean zero_reorder_delay;
176   gboolean non_ref_p;
177   gboolean strict_gop;
178   guint aq_strength;
179   gint min_qp_i;
180   gint min_qp_p;
181   gint min_qp_b;
182   gint max_qp_i;
183   gint max_qp_p;
184   gint max_qp_b;
185   gdouble const_quality;
186
187   gboolean aud;
188   gboolean repeat_sequence_header;
189 } GstNvH265Encoder;
190
191 typedef struct _GstNvH265EncoderClass
192 {
193   GstNvEncoderClass parent_class;
194
195   guint cuda_device_id;
196   gint64 adapter_luid;
197
198   GstNvEncoderDeviceMode device_mode;
199
200   /* representative device caps */
201   GstNvEncoderDeviceCaps device_caps;
202
203   /* auto gpu select mode */
204   guint cuda_device_id_list[8];
205   guint cuda_device_id_size;
206
207   gint64 adapter_luid_list[8];
208   guint adapter_luid_size;
209 } GstNvH265EncoderClass;
210
211 #define GST_NV_H265_ENCODER(object) ((GstNvH265Encoder *) (object))
212 #define GST_NV_H265_ENCODER_GET_CLASS(object) \
213     (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstNvH265EncoderClass))
214
215 static void gst_nv_h265_encoder_finalize (GObject * object);
216 static void gst_nv_h265_encoder_set_property (GObject * object, guint prop_id,
217     const GValue * value, GParamSpec * pspec);
218 static void gst_nv_h265_encoder_get_property (GObject * object, guint prop_id,
219     GValue * value, GParamSpec * pspec);
220 static GstCaps *gst_nv_h265_encoder_getcaps (GstVideoEncoder * encoder,
221     GstCaps * filter);
222 static gboolean gst_nv_h265_encoder_set_format (GstNvEncoder * encoder,
223     GstVideoCodecState * state, gpointer session,
224     NV_ENC_INITIALIZE_PARAMS * init_params, NV_ENC_CONFIG * config);
225 static gboolean gst_nv_h265_encoder_set_output_state (GstNvEncoder * encoder,
226     GstVideoCodecState * state, gpointer session);
227 static GstBuffer *gst_nv_h265_encoder_create_output_buffer (GstNvEncoder *
228     encoder, NV_ENC_LOCK_BITSTREAM * bitstream);
229 static GstNvEncoderReconfigure
230 gst_nv_h265_encoder_check_reconfigure (GstNvEncoder * encoder,
231     NV_ENC_CONFIG * config);
232 static gboolean gst_nv_h265_encoder_select_device (GstNvEncoder * encoder,
233     const GstVideoInfo * info, GstBuffer * buffer,
234     GstNvEncoderDeviceData * data);
235
236 static void
237 gst_nv_h265_encoder_class_init (GstNvH265EncoderClass * klass, gpointer data)
238 {
239   GObjectClass *object_class = G_OBJECT_CLASS (klass);
240   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
241   GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
242   GstNvEncoderClass *nvenc_class = GST_NV_ENCODER_CLASS (klass);
243   GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) data;
244   GstNvEncoderDeviceCaps *dev_caps = &cdata->device_caps;
245   GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE |
246       GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS);
247   GParamFlags conditional_param_flags = (GParamFlags) (G_PARAM_READWRITE |
248       GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_PLAYING |
249       G_PARAM_STATIC_STRINGS);
250
251   parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
252
253   object_class->finalize = gst_nv_h265_encoder_finalize;
254   object_class->set_property = gst_nv_h265_encoder_set_property;
255   object_class->get_property = gst_nv_h265_encoder_get_property;
256
257   switch (cdata->device_mode) {
258     case GST_NV_ENCODER_DEVICE_CUDA:
259       g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
260           g_param_spec_uint ("cuda-device-id", "CUDA Device ID",
261               "CUDA device ID of associated GPU",
262               0, G_MAXINT, 0,
263               (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
264                   G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
265       break;
266     case GST_NV_ENCODER_DEVICE_D3D11:
267       g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
268           g_param_spec_int64 ("adapter-luid", "Adapter LUID",
269               "DXGI Adapter LUID (Locally Unique Identifier) of associated GPU",
270               G_MININT64, G_MAXINT64, 0,
271               (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
272                   G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
273       break;
274     case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
275       if (cdata->cuda_device_id_size > 0) {
276         g_object_class_install_property (object_class, PROP_CUDA_DEVICE_ID,
277             g_param_spec_uint ("cuda-device-id", "CUDA Device ID",
278                 "CUDA device ID to use",
279                 0, G_MAXINT, 0,
280                 (GParamFlags) (conditional_param_flags |
281                     GST_PARAM_DOC_SHOW_DEFAULT)));
282       }
283       if (cdata->adapter_luid_size > 0) {
284         g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
285             g_param_spec_int64 ("adapter-luid", "Adapter LUID",
286                 "DXGI Adapter LUID (Locally Unique Identifier) to use",
287                 G_MININT64, G_MAXINT64, 0,
288                 (GParamFlags) (conditional_param_flags |
289                     GST_PARAM_DOC_SHOW_DEFAULT)));
290       }
291       break;
292     default:
293       g_assert_not_reached ();
294       break;
295   }
296
297   g_object_class_install_property (object_class, PROP_PRESET,
298       g_param_spec_enum ("preset", "Encoding Preset",
299           "Encoding Preset", GST_TYPE_NV_ENCODER_PRESET,
300           DEFAULT_PRESET, param_flags));
301   if (dev_caps->weighted_prediction) {
302     g_object_class_install_property (object_class, PROP_WEIGHTED_PRED,
303         g_param_spec_boolean ("weighted-pred", "Weighted Pred",
304             "Enables Weighted Prediction", DEFAULT_WEIGHTED_PRED,
305             conditional_param_flags));
306   }
307   g_object_class_install_property (object_class, PROP_GOP_SIZE,
308       g_param_spec_int ("gop-size", "GOP size",
309           "Number of frames between intra frames (-1 = infinite)",
310           -1, G_MAXINT, DEFAULT_GOP_SIZE, param_flags));
311   if (dev_caps->max_bframes > 0) {
312     g_object_class_install_property (object_class, PROP_B_FRAMES,
313         g_param_spec_uint ("b-frames", "B-Frames",
314             "Number of B-frames between I and P", 0, dev_caps->max_bframes,
315             DEFAULT_B_FRAMES, conditional_param_flags));
316   }
317   g_object_class_install_property (object_class, PROP_RATE_CONTROL,
318       g_param_spec_enum ("rate-control", "Rate Control", "Rate Control Method",
319           GST_TYPE_NV_ENCODER_RC_MODE, DEFAULT_RATE_CONTROL, param_flags));
320   g_object_class_install_property (object_class, PROP_QP_I,
321       g_param_spec_int ("qp-i", "QP I",
322           "Constant QP value for I frame (-1 = default)", -1, 51,
323           DEFAULT_QP, param_flags));
324   g_object_class_install_property (object_class, PROP_QP_P,
325       g_param_spec_int ("qp-p", "QP P",
326           "Constant QP value for P frame (-1 = default)", -1, 51,
327           DEFAULT_QP, param_flags));
328   g_object_class_install_property (object_class, PROP_QP_B,
329       g_param_spec_int ("qp-b", "QP B",
330           "Constant QP value for B frame (-1 = default)", -1, 51,
331           DEFAULT_QP, param_flags));
332   g_object_class_install_property (object_class, PROP_BITRATE,
333       g_param_spec_uint ("bitrate", "Bitrate",
334           "Bitrate in kbit/sec (0 = automatic)", 0, 2000 * 1024,
335           DEFAULT_BITRATE, param_flags));
336   g_object_class_install_property (object_class, PROP_MAX_BITRATE,
337       g_param_spec_uint ("max-bitrate", "Max Bitrate",
338           "Maximum Bitrate in kbit/sec (ignored in CBR mode)", 0, 2000 * 1024,
339           DEFAULT_MAX_BITRATE, param_flags));
340   if (dev_caps->custom_vbv_buf_size) {
341     g_object_class_install_property (object_class,
342         PROP_VBV_BUFFER_SIZE,
343         g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
344             "VBV(HRD) Buffer Size in kbits (0 = NVENC default)",
345             0, G_MAXUINT, DEFAULT_VBV_BUFFER_SIZE, conditional_param_flags));
346   }
347   if (dev_caps->lookahead) {
348     g_object_class_install_property (object_class, PROP_RC_LOOKAHEAD,
349         g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead",
350             "Number of frames for frame type lookahead",
351             0, 32, DEFAULT_RC_LOOKAHEAD, conditional_param_flags));
352     g_object_class_install_property (object_class, PROP_I_ADAPT,
353         g_param_spec_boolean ("i-adapt", "I Adapt",
354             "Enable adaptive I-frame insert when lookahead is enabled",
355             DEFAULT_I_ADAPT, conditional_param_flags));
356     if (dev_caps->max_bframes > 0) {
357       g_object_class_install_property (object_class, PROP_B_ADAPT,
358           g_param_spec_boolean ("b-adapt", "B Adapt",
359               "Enable adaptive B-frame insert when lookahead is enabled",
360               DEFAULT_B_ADAPT, conditional_param_flags));
361     }
362   }
363   g_object_class_install_property (object_class, PROP_SPATIAL_AQ,
364       g_param_spec_boolean ("spatial-aq", "Spatial AQ",
365           "Spatial Adaptive Quantization", DEFAULT_SPATIAL_AQ, param_flags));
366   if (dev_caps->temporal_aq) {
367     g_object_class_install_property (object_class, PROP_TEMPORAL_AQ,
368         g_param_spec_boolean ("temporal-aq", "Temporal AQ",
369             "Temporal Adaptive Quantization", DEFAULT_TEMPORAL_AQ,
370             conditional_param_flags));
371   }
372   g_object_class_install_property (object_class, PROP_ZERO_REORDER_DELAY,
373       g_param_spec_boolean ("zero-reorder-delay", "Zero Reorder Delay",
374           "Zero latency operation (i.e., num_reorder_frames = 0)",
375           DEFAULT_ZERO_REORDER_DELAY, param_flags));
376   g_object_class_install_property (object_class, PROP_NON_REF_P,
377       g_param_spec_boolean ("nonref-p", "Nonref P",
378           "Automatic insertion of non-reference P-frames", DEFAULT_NON_REF_P,
379           param_flags));
380   g_object_class_install_property (object_class, PROP_STRICT_GOP,
381       g_param_spec_boolean ("strict-gop", "Strict GOP",
382           "Minimize GOP-to-GOP rate fluctuations", DEFAULT_STRICT_GOP,
383           param_flags));
384   g_object_class_install_property (object_class, PROP_AQ_STRENGTH,
385       g_param_spec_uint ("aq-strength", "AQ Strength",
386           "Adaptive Quantization Strength when spatial-aq is enabled"
387           " from 1 (low) to 15 (aggressive), (0 = autoselect)",
388           0, 15, DEFAULT_AQ_STRENGTH, param_flags));
389   g_object_class_install_property (object_class, PROP_MIN_QP_I,
390       g_param_spec_int ("min-qp-i", "Min QP I",
391           "Minimum QP value for I frame, (-1 = disabled)", -1, 51,
392           DEFAULT_QP, param_flags));
393   g_object_class_install_property (object_class, PROP_MIN_QP_P,
394       g_param_spec_int ("min-qp-p", "Min QP P",
395           "Minimum QP value for P frame, (-1 = automatic)", -1, 51,
396           DEFAULT_QP, param_flags));
397   g_object_class_install_property (object_class, PROP_MIN_QP_B,
398       g_param_spec_int ("min-qp-b", "Min QP B",
399           "Minimum QP value for B frame, (-1 = automatic)", -1, 51,
400           DEFAULT_QP, param_flags));
401   g_object_class_install_property (object_class, PROP_MAX_QP_I,
402       g_param_spec_int ("max-qp-i", "Max QP I",
403           "Maximum QP value for I frame, (-1 = disabled)", -1, 51,
404           DEFAULT_QP, param_flags));
405   g_object_class_install_property (object_class, PROP_MAX_QP_P,
406       g_param_spec_int ("max-qp-p", "Max QP P",
407           "Maximum QP value for P frame, (-1 = automatic)", -1, 51,
408           DEFAULT_QP, param_flags));
409   g_object_class_install_property (object_class, PROP_MAX_QP_B,
410       g_param_spec_int ("max-qp-b", "Max QP B",
411           "Maximum QP value for B frame, (-1 = automatic)", -1, 51,
412           DEFAULT_QP, param_flags));
413   g_object_class_install_property (object_class, PROP_CONST_QUALITY,
414       g_param_spec_double ("const-quality", "Constant Quality",
415           "Target Constant Quality level for VBR mode (0 = automatic)",
416           0, 51, DEFAULT_CONST_QUALITY, param_flags));
417   g_object_class_install_property (object_class, PROP_AUD,
418       g_param_spec_boolean ("aud", "AUD",
419           "Use AU (Access Unit) delimiter", DEFAULT_AUD, param_flags));
420   g_object_class_install_property (object_class, PROP_REPEAT_SEQUENCE_HEADER,
421       g_param_spec_boolean ("repeat-sequence-header", "Repeat Sequence Header",
422           "Insert sequence headers (SPS/PPS) per IDR, "
423           "ignored if negotiated stream-format is \"hvc1\"",
424           DEFAULT_REPEAT_SEQUENCE_HEADER, param_flags));
425
426   switch (cdata->device_mode) {
427     case GST_NV_ENCODER_DEVICE_CUDA:
428       gst_element_class_set_static_metadata (element_class,
429           "NVENC H.265 Video Encoder CUDA Mode",
430           "Codec/Encoder/Video/Hardware",
431           "Encode H.265 video streams using NVCODEC API CUDA Mode",
432           "Seungha Yang <seungha@centricular.com>");
433       break;
434     case GST_NV_ENCODER_DEVICE_D3D11:
435       gst_element_class_set_static_metadata (element_class,
436           "NVENC H.265 Video Encoder Direct3D11 Mode",
437           "Codec/Encoder/Video/Hardware",
438           "Encode H.265 video streams using NVCODEC API Direct3D11 Mode",
439           "Seungha Yang <seungha@centricular.com>");
440       break;
441     case GST_NV_ENCODER_DEVICE_AUTO_SELECT:
442       gst_element_class_set_static_metadata (element_class,
443           "NVENC H.265 Video Encoder Auto GPU select Mode",
444           "Codec/Encoder/Video/Hardware",
445           "Encode H.265 video streams using NVCODEC API auto GPU select Mode",
446           "Seungha Yang <seungha@centricular.com>");
447       break;
448     default:
449       g_assert_not_reached ();
450       break;
451   }
452
453   gst_element_class_add_pad_template (element_class,
454       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
455           cdata->sink_caps));
456   gst_element_class_add_pad_template (element_class,
457       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
458           cdata->src_caps));
459
460   videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_getcaps);
461
462   nvenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_set_format);
463   nvenc_class->set_output_state =
464       GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_set_output_state);
465   nvenc_class->create_output_buffer =
466       GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_create_output_buffer);
467   nvenc_class->check_reconfigure =
468       GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_check_reconfigure);
469   nvenc_class->select_device =
470       GST_DEBUG_FUNCPTR (gst_nv_h265_encoder_select_device);
471
472   klass->device_caps = cdata->device_caps;
473   klass->cuda_device_id = cdata->cuda_device_id;
474   klass->adapter_luid = cdata->adapter_luid;
475   klass->device_mode = cdata->device_mode;
476   klass->cuda_device_id_size = cdata->cuda_device_id_size;
477   klass->adapter_luid_size = cdata->adapter_luid_size;
478   memcpy (klass->cuda_device_id_list, cdata->cuda_device_id_list,
479       sizeof (klass->cuda_device_id_list));
480   memcpy (klass->adapter_luid_list, cdata->adapter_luid_list,
481       sizeof (klass->adapter_luid_list));
482
483   gst_nv_encoder_class_data_unref (cdata);
484 }
485
486 static void
487 gst_nv_h265_encoder_init (GstNvH265Encoder * self)
488 {
489   GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
490
491   g_mutex_init (&self->prop_lock);
492
493   self->selected_device_mode = klass->device_mode;
494   self->cuda_device_id = klass->cuda_device_id;
495   self->adapter_luid = klass->adapter_luid;
496   self->preset = DEFAULT_PRESET;
497   self->weighted_pred = DEFAULT_WEIGHTED_PRED;
498   self->gop_size = DEFAULT_GOP_SIZE;
499   self->bframes = DEFAULT_B_FRAMES;
500   self->rc_mode = DEFAULT_RATE_CONTROL;
501   self->qp_i = DEFAULT_QP;
502   self->qp_p = DEFAULT_QP;
503   self->qp_b = DEFAULT_QP;
504   self->bitrate = DEFAULT_BITRATE;
505   self->max_bitrate = DEFAULT_MAX_BITRATE;
506   self->vbv_buffer_size = DEFAULT_VBV_BUFFER_SIZE;
507   self->rc_lookahead = DEFAULT_RC_LOOKAHEAD;
508   self->i_adapt = DEFAULT_I_ADAPT;
509   self->b_adapt = DEFAULT_B_ADAPT;
510   self->spatial_aq = DEFAULT_SPATIAL_AQ;
511   self->temporal_aq = DEFAULT_TEMPORAL_AQ;
512   self->zero_reorder_delay = DEFAULT_ZERO_REORDER_DELAY;
513   self->non_ref_p = DEFAULT_NON_REF_P;
514   self->strict_gop = DEFAULT_STRICT_GOP;
515   self->aq_strength = DEFAULT_AQ_STRENGTH;
516   self->min_qp_i = DEFAULT_QP;
517   self->min_qp_p = DEFAULT_QP;
518   self->min_qp_b = DEFAULT_QP;
519   self->max_qp_i = DEFAULT_QP;
520   self->max_qp_p = DEFAULT_QP;
521   self->max_qp_b = DEFAULT_QP;
522   self->const_quality = DEFAULT_CONST_QUALITY;
523   self->aud = DEFAULT_AUD;
524   self->repeat_sequence_header = DEFAULT_REPEAT_SEQUENCE_HEADER;
525
526   self->parser = gst_h265_parser_new ();
527
528   gst_nv_encoder_set_device_mode (GST_NV_ENCODER (self), klass->device_mode,
529       klass->cuda_device_id, klass->adapter_luid);
530 }
531
532 static void
533 gst_nv_h265_encoder_finalize (GObject * object)
534 {
535   GstNvH265Encoder *self = GST_NV_H265_ENCODER (object);
536
537   g_mutex_clear (&self->prop_lock);
538   gst_h265_parser_free (self->parser);
539
540   G_OBJECT_CLASS (parent_class)->finalize (object);
541 }
542
543 typedef enum
544 {
545   UPDATE_INIT_PARAM,
546   UPDATE_RC_PARAM,
547   UPDATE_BITRATE,
548 } PropUpdateLevel;
549
550 static void
551 update_boolean (GstNvH265Encoder * self, gboolean * old_val,
552     const GValue * new_val, PropUpdateLevel level)
553 {
554   gboolean val = g_value_get_boolean (new_val);
555
556   if (*old_val == val)
557     return;
558
559   *old_val = val;
560   switch (level) {
561     case UPDATE_INIT_PARAM:
562       self->init_param_updated = TRUE;
563       break;
564     case UPDATE_RC_PARAM:
565       self->rc_param_updated = TRUE;
566       break;
567     case UPDATE_BITRATE:
568       self->bitrate_updated = TRUE;
569       break;
570   }
571 }
572
573 static void
574 update_int (GstNvH265Encoder * self, gint * old_val,
575     const GValue * new_val, PropUpdateLevel level)
576 {
577   gint val = g_value_get_int (new_val);
578
579   if (*old_val == val)
580     return;
581
582   *old_val = val;
583   switch (level) {
584     case UPDATE_INIT_PARAM:
585       self->init_param_updated = TRUE;
586       break;
587     case UPDATE_RC_PARAM:
588       self->rc_param_updated = TRUE;
589       break;
590     case UPDATE_BITRATE:
591       self->bitrate_updated = TRUE;
592       break;
593   }
594 }
595
596 static void
597 update_uint (GstNvH265Encoder * self, guint * old_val,
598     const GValue * new_val, PropUpdateLevel level)
599 {
600   guint val = g_value_get_uint (new_val);
601
602   if (*old_val == val)
603     return;
604
605   *old_val = val;
606   switch (level) {
607     case UPDATE_INIT_PARAM:
608       self->init_param_updated = TRUE;
609       break;
610     case UPDATE_RC_PARAM:
611       self->rc_param_updated = TRUE;
612       break;
613     case UPDATE_BITRATE:
614       self->bitrate_updated = TRUE;
615       break;
616   }
617 }
618
619 static void
620 update_double (GstNvH265Encoder * self, gdouble * old_val,
621     const GValue * new_val, PropUpdateLevel level)
622 {
623   gdouble val = g_value_get_double (new_val);
624
625   if (*old_val == val)
626     return;
627
628   *old_val = val;
629   switch (level) {
630     case UPDATE_INIT_PARAM:
631       self->init_param_updated = TRUE;
632       break;
633     case UPDATE_RC_PARAM:
634       self->rc_param_updated = TRUE;
635       break;
636     case UPDATE_BITRATE:
637       self->bitrate_updated = TRUE;
638       break;
639   }
640 }
641
642 static void
643 gst_nv_h265_encoder_set_property (GObject * object, guint prop_id,
644     const GValue * value, GParamSpec * pspec)
645 {
646   GstNvH265Encoder *self = GST_NV_H265_ENCODER (object);
647   GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
648
649   g_mutex_lock (&self->prop_lock);
650   switch (prop_id) {
651     case PROP_ADAPTER_LUID:{
652       gint64 adapter_luid = g_value_get_int64 (value);
653       gboolean is_valid = FALSE;
654
655       for (guint i = 0; i < klass->adapter_luid_size; i++) {
656         if (klass->adapter_luid_list[i] == adapter_luid) {
657           self->adapter_luid = adapter_luid;
658           is_valid = TRUE;
659           break;
660         }
661       }
662
663       if (!is_valid)
664         g_warning ("%" G_GINT64_FORMAT " is not a valid adapter luid",
665             adapter_luid);
666       break;
667     }
668     case PROP_CUDA_DEVICE_ID:{
669       guint cuda_device_id = g_value_get_uint (value);
670       gboolean is_valid = FALSE;
671
672       for (guint i = 0; i < klass->cuda_device_id_size; i++) {
673         if (klass->cuda_device_id_list[i] == cuda_device_id) {
674           self->cuda_device_id = cuda_device_id;
675           is_valid = TRUE;
676           break;
677         }
678       }
679
680       if (!is_valid)
681         g_warning ("%d is not a valid cuda device id", cuda_device_id);
682       break;
683     }
684     case PROP_PRESET:{
685       GstNvEncoderPreset preset = (GstNvEncoderPreset) g_value_get_enum (value);
686       if (preset != self->preset) {
687         self->preset = preset;
688         self->init_param_updated = TRUE;
689       }
690       break;
691     }
692     case PROP_WEIGHTED_PRED:
693       update_boolean (self, &self->weighted_pred, value, UPDATE_INIT_PARAM);
694       break;
695     case PROP_GOP_SIZE:
696       update_int (self, &self->gop_size, value, UPDATE_INIT_PARAM);
697       break;
698     case PROP_B_FRAMES:
699       update_uint (self, &self->bframes, value, UPDATE_INIT_PARAM);
700       break;
701     case PROP_RATE_CONTROL:{
702       GstNvEncoderRCMode mode = (GstNvEncoderRCMode) g_value_get_enum (value);
703       if (mode != self->rc_mode) {
704         self->rc_mode = mode;
705         self->rc_param_updated = TRUE;
706       }
707       break;
708     }
709     case PROP_QP_I:
710       update_int (self, &self->qp_i, value, UPDATE_RC_PARAM);
711       break;
712     case PROP_QP_P:
713       update_int (self, &self->qp_p, value, UPDATE_RC_PARAM);
714       break;
715     case PROP_QP_B:
716       update_int (self, &self->qp_b, value, UPDATE_RC_PARAM);
717       break;
718     case PROP_BITRATE:
719       update_uint (self, &self->bitrate, value, UPDATE_BITRATE);
720       break;
721     case PROP_MAX_BITRATE:
722       update_uint (self, &self->max_bitrate, value, UPDATE_BITRATE);
723       break;
724     case PROP_VBV_BUFFER_SIZE:
725       update_uint (self, &self->vbv_buffer_size, value, UPDATE_RC_PARAM);
726       break;
727     case PROP_RC_LOOKAHEAD:
728       /* rc-lookahead update requires pool size change */
729       update_uint (self, &self->rc_lookahead, value, UPDATE_INIT_PARAM);
730       break;
731     case PROP_I_ADAPT:
732       update_boolean (self, &self->i_adapt, value, UPDATE_RC_PARAM);
733       break;
734     case PROP_B_ADAPT:
735       update_boolean (self, &self->b_adapt, value, UPDATE_RC_PARAM);
736       break;
737     case PROP_SPATIAL_AQ:
738       update_boolean (self, &self->spatial_aq, value, UPDATE_RC_PARAM);
739       break;
740     case PROP_TEMPORAL_AQ:
741       update_boolean (self, &self->temporal_aq, value, UPDATE_RC_PARAM);
742       break;
743     case PROP_ZERO_REORDER_DELAY:
744       update_boolean (self, &self->zero_reorder_delay, value, UPDATE_RC_PARAM);
745       break;
746     case PROP_NON_REF_P:
747       update_boolean (self, &self->non_ref_p, value, UPDATE_RC_PARAM);
748       break;
749     case PROP_STRICT_GOP:
750       update_boolean (self, &self->strict_gop, value, UPDATE_RC_PARAM);
751       break;
752     case PROP_AQ_STRENGTH:
753       update_uint (self, &self->aq_strength, value, UPDATE_RC_PARAM);
754       break;
755     case PROP_MIN_QP_I:
756       update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
757       break;
758     case PROP_MIN_QP_P:
759       update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
760       break;
761     case PROP_MIN_QP_B:
762       update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
763       break;
764     case PROP_MAX_QP_I:
765       update_int (self, &self->min_qp_i, value, UPDATE_RC_PARAM);
766       break;
767     case PROP_MAX_QP_P:
768       update_int (self, &self->min_qp_p, value, UPDATE_RC_PARAM);
769       break;
770     case PROP_MAX_QP_B:
771       update_int (self, &self->min_qp_b, value, UPDATE_RC_PARAM);
772       break;
773     case PROP_CONST_QUALITY:
774       update_double (self, &self->const_quality, value, UPDATE_RC_PARAM);
775       break;
776     case PROP_AUD:
777       update_boolean (self, &self->aud, value, UPDATE_INIT_PARAM);
778       break;
779     case PROP_REPEAT_SEQUENCE_HEADER:
780       update_boolean (self,
781           &self->repeat_sequence_header, value, UPDATE_INIT_PARAM);
782       break;
783     default:
784       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
785       break;
786   }
787
788   g_mutex_unlock (&self->prop_lock);
789 }
790
791 static void
792 gst_nv_h265_encoder_get_property (GObject * object, guint prop_id,
793     GValue * value, GParamSpec * pspec)
794 {
795   GstNvH265Encoder *self = GST_NV_H265_ENCODER (object);
796
797   switch (prop_id) {
798     case PROP_ADAPTER_LUID:
799       g_value_set_int64 (value, self->adapter_luid);
800       break;
801     case PROP_CUDA_DEVICE_ID:
802       g_value_set_uint (value, self->cuda_device_id);
803       break;
804     case PROP_PRESET:
805       g_value_set_enum (value, self->preset);
806       break;
807     case PROP_WEIGHTED_PRED:
808       g_value_set_boolean (value, self->weighted_pred);
809       break;
810     case PROP_GOP_SIZE:
811       g_value_set_int (value, self->gop_size);
812       break;
813     case PROP_B_FRAMES:
814       g_value_set_uint (value, self->bframes);
815       break;
816     case PROP_RATE_CONTROL:
817       g_value_set_enum (value, self->rc_mode);
818       break;
819     case PROP_QP_I:
820       g_value_set_int (value, self->qp_i);
821       break;
822     case PROP_QP_P:
823       g_value_set_int (value, self->qp_p);
824       break;
825     case PROP_QP_B:
826       g_value_set_int (value, self->qp_b);
827       break;
828     case PROP_BITRATE:
829       g_value_set_uint (value, self->bitrate);
830       break;
831     case PROP_MAX_BITRATE:
832       g_value_set_uint (value, self->max_bitrate);
833       break;
834     case PROP_VBV_BUFFER_SIZE:
835       g_value_set_uint (value, self->vbv_buffer_size);
836       break;
837     case PROP_RC_LOOKAHEAD:
838       g_value_set_uint (value, self->rc_lookahead);
839       break;
840     case PROP_I_ADAPT:
841       g_value_set_boolean (value, self->i_adapt);
842       break;
843     case PROP_B_ADAPT:
844       g_value_set_boolean (value, self->b_adapt);
845       break;
846     case PROP_SPATIAL_AQ:
847       g_value_set_boolean (value, self->spatial_aq);
848       break;
849     case PROP_TEMPORAL_AQ:
850       g_value_set_boolean (value, self->temporal_aq);
851       break;
852     case PROP_ZERO_REORDER_DELAY:
853       g_value_set_boolean (value, self->zero_reorder_delay);
854       break;
855     case PROP_NON_REF_P:
856       g_value_set_boolean (value, self->non_ref_p);
857       break;
858     case PROP_STRICT_GOP:
859       g_value_set_boolean (value, self->strict_gop);
860       break;
861     case PROP_AQ_STRENGTH:
862       g_value_set_uint (value, self->aq_strength);
863       break;
864     case PROP_MIN_QP_I:
865       g_value_set_int (value, self->min_qp_i);
866       break;
867     case PROP_MIN_QP_P:
868       g_value_set_int (value, self->min_qp_p);
869       break;
870     case PROP_MIN_QP_B:
871       g_value_set_int (value, self->min_qp_b);
872       break;
873     case PROP_MAX_QP_I:
874       g_value_set_int (value, self->max_qp_i);
875       break;
876     case PROP_MAX_QP_P:
877       g_value_set_int (value, self->max_qp_p);
878       break;
879     case PROP_MAX_QP_B:
880       g_value_set_int (value, self->max_qp_b);
881       break;
882     case PROP_CONST_QUALITY:
883       g_value_set_double (value, self->const_quality);
884       break;
885     case PROP_AUD:
886       g_value_set_boolean (value, self->aud);
887       break;
888     case PROP_REPEAT_SEQUENCE_HEADER:
889       g_value_set_boolean (value, self->repeat_sequence_header);
890       break;
891     default:
892       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
893       break;
894   }
895 }
896
897 static void
898 gst_nv_h265_encoder_get_downstream_profiles_and_format (GstNvH265Encoder * self,
899     std::set < std::string > &downstream_profiles,
900     GstNvH265EncoderStreamFormat * format)
901 {
902   GstCaps *allowed_caps;
903   GstStructure *s;
904   const gchar *stream_format;
905
906   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
907
908   if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
909       gst_caps_is_any (allowed_caps)) {
910     gst_clear_caps (&allowed_caps);
911
912     return;
913   }
914
915   for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
916     const GValue *profile_value;
917     const gchar *profile;
918
919     s = gst_caps_get_structure (allowed_caps, i);
920     profile_value = gst_structure_get_value (s, "profile");
921     if (!profile_value)
922       continue;
923
924     if (GST_VALUE_HOLDS_LIST (profile_value)) {
925       for (guint j = 0; j < gst_value_list_get_size (profile_value); j++) {
926         const GValue *p = gst_value_list_get_value (profile_value, j);
927
928         if (!G_VALUE_HOLDS_STRING (p))
929           continue;
930
931         profile = g_value_get_string (p);
932         if (profile)
933           downstream_profiles.insert (profile);
934       }
935
936     } else if (G_VALUE_HOLDS_STRING (profile_value)) {
937       profile = g_value_get_string (profile_value);
938       if (profile)
939         downstream_profiles.insert (profile);
940     }
941   }
942
943   if (format) {
944     *format = GST_NV_H265_ENCODER_BYTE_STREAM;
945
946     allowed_caps = gst_caps_fixate (allowed_caps);
947     s = gst_caps_get_structure (allowed_caps, 0);
948     stream_format = gst_structure_get_string (s, "stream-format");
949     if (g_strcmp0 (stream_format, "hvc1") == 0)
950       *format = GST_NV_H265_ENCODER_HVC1;
951     else if (g_strcmp0 (stream_format, "hev1") == 0)
952       *format = GST_NV_H265_ENCODER_HEV1;
953   }
954
955   gst_caps_unref (allowed_caps);
956 }
957
958 static GstCaps *
959 gst_nv_h265_encoder_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
960 {
961   GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
962   GstCaps *template_caps;
963   GstCaps *supported_caps;
964   std::set < std::string > downstream_profiles;
965   std::set < std::string > allowed_formats;
966
967   gst_nv_h265_encoder_get_downstream_profiles_and_format (self,
968       downstream_profiles, NULL);
969
970   GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
971       downstream_profiles.size ());
972
973   if (downstream_profiles.size () == 0)
974     return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
975
976   /* *INDENT-OFF* */
977   for (const auto &iter: downstream_profiles) {
978     if (iter == "main") {
979       allowed_formats.insert("NV12");
980     } else if (iter == "main-10") {
981       allowed_formats.insert("P010_10LE");
982     } else if (iter == "main-444") {
983       allowed_formats.insert("Y444");
984     } else if (iter == "main-444-10") {
985       allowed_formats.insert("Y444_16LE");
986     }
987   }
988   /* *INDENT-ON* */
989
990   template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
991   template_caps = gst_caps_make_writable (template_caps);
992
993   GValue formats = G_VALUE_INIT;
994
995   g_value_init (&formats, GST_TYPE_LIST);
996   /* *INDENT-OFF* */
997   for (const auto &iter: allowed_formats) {
998     GValue val = G_VALUE_INIT;
999     g_value_init (&val, G_TYPE_STRING);
1000
1001     g_value_set_string (&val, iter.c_str());
1002     gst_value_list_append_and_take_value (&formats, &val);
1003   }
1004   /* *INDENT-ON* */
1005
1006   gst_caps_set_value (template_caps, "format", &formats);
1007   g_value_unset (&formats);
1008
1009   supported_caps = gst_video_encoder_proxy_getcaps (encoder,
1010       template_caps, filter);
1011   gst_caps_unref (template_caps);
1012
1013   GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
1014
1015   return supported_caps;
1016 }
1017
1018 static gboolean
1019 gst_nv_h265_encoder_set_format (GstNvEncoder * encoder,
1020     GstVideoCodecState * state, gpointer session,
1021     NV_ENC_INITIALIZE_PARAMS * init_params, NV_ENC_CONFIG * config)
1022 {
1023   GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1024   GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
1025   GstNvEncoderDeviceCaps *dev_caps = &klass->device_caps;
1026   NV_ENC_RC_PARAMS *rc_params;
1027   GstVideoInfo *info = &state->info;
1028   NVENCSTATUS status;
1029   NV_ENC_PRESET_CONFIG preset_config = { 0, };
1030   gint dar_n, dar_d;
1031   GstNvEncoderRCMode rc_mode;
1032   NV_ENC_CONFIG_HEVC *hevc_config;
1033   NV_ENC_CONFIG_HEVC_VUI_PARAMETERS *vui;
1034   std::set < std::string > downstream_profiles;
1035   GUID selected_profile = NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID;
1036   guint chroma_format_index = 1;
1037   guint bitdepth_minus8 = 0;
1038   gboolean bframe_aborted = FALSE;
1039   gboolean weight_pred_aborted = FALSE;
1040   gboolean vbv_buffer_size_aborted = FALSE;
1041   gboolean lookahead_aborted = FALSE;
1042   gboolean temporal_aq_aborted = FALSE;
1043
1044   self->stream_format = GST_NV_H265_ENCODER_BYTE_STREAM;
1045
1046   gst_nv_h265_encoder_get_downstream_profiles_and_format (self,
1047       downstream_profiles, &self->stream_format);
1048
1049   if (downstream_profiles.empty ()) {
1050     GST_ERROR_OBJECT (self, "Unable to get downstream profile");
1051     return FALSE;
1052   }
1053
1054   /* XXX: we may need to relax condition a little */
1055   switch (GST_VIDEO_INFO_FORMAT (info)) {
1056     case GST_VIDEO_FORMAT_NV12:
1057       if (downstream_profiles.find ("main") == downstream_profiles.end ()) {
1058         GST_ERROR_OBJECT (self, "Downstream does not support main profile");
1059         return FALSE;
1060       } else {
1061         selected_profile = NV_ENC_HEVC_PROFILE_MAIN_GUID;
1062       }
1063       break;
1064     case GST_VIDEO_FORMAT_P010_10LE:
1065       if (downstream_profiles.find ("main-10") == downstream_profiles.end ()) {
1066         GST_ERROR_OBJECT (self, "Downstream does not support main profile");
1067         return FALSE;
1068       } else {
1069         selected_profile = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
1070         bitdepth_minus8 = 2;
1071       }
1072       break;
1073     case GST_VIDEO_FORMAT_Y444:
1074       if (downstream_profiles.find ("main-444") == downstream_profiles.end ()) {
1075         GST_ERROR_OBJECT (self, "Downstream does not support 4:4:4 profile");
1076         return FALSE;
1077       } else {
1078         selected_profile = NV_ENC_HEVC_PROFILE_FREXT_GUID;
1079         chroma_format_index = 3;
1080       }
1081       break;
1082     case GST_VIDEO_FORMAT_Y444_16LE:
1083       if (downstream_profiles.find ("main-444-10") ==
1084           downstream_profiles.end ()) {
1085         GST_ERROR_OBJECT (self,
1086             "Downstream does not support 4:4:4 10bits profile");
1087         return FALSE;
1088       } else {
1089         selected_profile = NV_ENC_HEVC_PROFILE_FREXT_GUID;
1090         chroma_format_index = 3;
1091         bitdepth_minus8 = 2;
1092       }
1093       break;
1094     default:
1095       GST_ERROR_OBJECT (self, "Unexpected format %s",
1096           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
1097       g_assert_not_reached ();
1098       return FALSE;
1099   }
1100
1101   g_mutex_lock (&self->prop_lock);
1102
1103   if (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT) {
1104     GstNvEncoderDeviceCaps dev_caps;
1105
1106     gst_nv_encoder_get_encoder_caps (session,
1107         &NV_ENC_CODEC_HEVC_GUID, &dev_caps);
1108
1109     if (self->bframes > 0 && !dev_caps.max_bframes) {
1110       self->bframes = 0;
1111       bframe_aborted = TRUE;
1112
1113       GST_INFO_OBJECT (self, "B-frame was enabled but not support by device");
1114     }
1115
1116     if (self->weighted_pred && !dev_caps.weighted_prediction) {
1117       self->weighted_pred = FALSE;
1118       weight_pred_aborted = TRUE;
1119
1120       GST_INFO_OBJECT (self,
1121           "Weighted prediction was enabled but not support by device");
1122     }
1123
1124     if (self->vbv_buffer_size && !dev_caps.custom_vbv_buf_size) {
1125       self->vbv_buffer_size = 0;
1126       vbv_buffer_size_aborted = TRUE;
1127
1128       GST_INFO_OBJECT (self,
1129           "VBV buffer size was specified but not supported by device");
1130     }
1131
1132     if (self->rc_lookahead && !dev_caps.lookahead) {
1133       self->rc_lookahead = 0;
1134       lookahead_aborted = TRUE;
1135
1136       GST_INFO_OBJECT (self,
1137           "VBV buffer size was specified but not supported by device");
1138     }
1139
1140     if (self->temporal_aq && !dev_caps.temporal_aq) {
1141       self->temporal_aq = FALSE;
1142       temporal_aq_aborted = TRUE;
1143
1144       GST_INFO_OBJECT (self,
1145           "temporal-aq was enabled but not supported by device");
1146     }
1147   }
1148
1149   init_params->version = gst_nvenc_get_initialize_params_version ();
1150   init_params->encodeGUID = NV_ENC_CODEC_HEVC_GUID;
1151
1152   init_params->encodeWidth = GST_VIDEO_INFO_WIDTH (info);
1153   init_params->maxEncodeWidth = GST_VIDEO_INFO_WIDTH (info);
1154   init_params->encodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1155   init_params->maxEncodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1156   init_params->enablePTD = TRUE;
1157   if (dev_caps->async_encoding_support)
1158     init_params->enableEncodeAsync = 1;
1159   if (info->fps_d > 0 && info->fps_n > 0) {
1160     init_params->frameRateNum = info->fps_n;
1161     init_params->frameRateDen = info->fps_d;
1162   } else {
1163     init_params->frameRateNum = 0;
1164     init_params->frameRateDen = 1;
1165   }
1166
1167   init_params->enableWeightedPrediction = self->weighted_pred;
1168
1169   if (gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (info),
1170           GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_PAR_N (info),
1171           GST_VIDEO_INFO_PAR_D (info), &dar_n, &dar_d) && dar_n > 0
1172       && dar_d > 0) {
1173     init_params->darWidth = dar_n;
1174     init_params->darHeight = dar_d;
1175   }
1176
1177   gst_nv_encoder_preset_to_guid (self->preset, &init_params->presetGUID);
1178
1179   preset_config.version = gst_nvenc_get_preset_config_version ();
1180   preset_config.presetCfg.version = gst_nvenc_get_config_version ();
1181
1182   status = NvEncGetEncodePresetConfig (session, NV_ENC_CODEC_HEVC_GUID,
1183       init_params->presetGUID, &preset_config);
1184   if (status != NV_ENC_SUCCESS) {
1185     GST_ERROR_OBJECT (self, "Failed to get preset config %"
1186         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1187     g_mutex_unlock (&self->prop_lock);
1188     return FALSE;
1189   }
1190
1191   *config = preset_config.presetCfg;
1192   if (self->gop_size < 0) {
1193     config->gopLength = NVENC_INFINITE_GOPLENGTH;
1194     config->frameIntervalP = 1;
1195   } else if (self->gop_size > 0) {
1196     config->gopLength = self->gop_size;
1197     /* frameIntervalP
1198      * 0: All Intra frames
1199      * 1: I/P only
1200      * 2: IBP
1201      * 3: IBBP
1202      */
1203     config->frameIntervalP = self->bframes + 1;
1204   } else {
1205     /* gop size == 0 means all intra frames */
1206     config->gopLength = 1;
1207     config->frameIntervalP = 0;
1208   }
1209
1210   rc_params = &config->rcParams;
1211   rc_mode = self->rc_mode;
1212
1213   if (self->bitrate)
1214     rc_params->averageBitRate = self->bitrate * 1024;
1215   if (self->max_bitrate)
1216     rc_params->maxBitRate = self->max_bitrate * 1024;
1217   if (self->vbv_buffer_size)
1218     rc_params->vbvBufferSize = self->vbv_buffer_size * 1024;
1219
1220   if (self->min_qp_i >= 0) {
1221     rc_params->enableMinQP = TRUE;
1222     rc_params->minQP.qpIntra = self->min_qp_i;
1223     if (self->min_qp_p >= 0) {
1224       rc_params->minQP.qpInterP = self->min_qp_p;
1225     } else {
1226       rc_params->minQP.qpInterP = rc_params->minQP.qpIntra;
1227     }
1228     if (self->min_qp_b >= 0) {
1229       rc_params->minQP.qpInterB = self->min_qp_b;
1230     } else {
1231       rc_params->minQP.qpInterB = rc_params->minQP.qpInterP;
1232     }
1233   }
1234
1235   if (self->max_qp_i >= 0) {
1236     rc_params->enableMaxQP = TRUE;
1237     rc_params->maxQP.qpIntra = self->max_qp_i;
1238     if (self->max_qp_p >= 0) {
1239       rc_params->maxQP.qpInterP = self->max_qp_p;
1240     } else {
1241       rc_params->maxQP.qpInterP = rc_params->maxQP.qpIntra;
1242     }
1243     if (self->max_qp_b >= 0) {
1244       rc_params->maxQP.qpInterB = self->max_qp_b;
1245     } else {
1246       rc_params->maxQP.qpInterB = rc_params->maxQP.qpInterP;
1247     }
1248   }
1249
1250   if (rc_mode == GST_NV_ENCODER_RC_MODE_CONSTQP) {
1251     if (self->qp_i >= 0)
1252       rc_params->constQP.qpIntra = self->qp_i;
1253     if (self->qp_p >= 0)
1254       rc_params->constQP.qpInterP = self->qp_p;
1255     if (self->qp_p >= 0)
1256       rc_params->constQP.qpInterB = self->qp_b;
1257   }
1258
1259   rc_params->rateControlMode = gst_nv_encoder_rc_mode_to_native (rc_mode);
1260
1261   if (self->spatial_aq) {
1262     rc_params->enableAQ = TRUE;
1263     rc_params->aqStrength = self->aq_strength;
1264   }
1265
1266   rc_params->enableTemporalAQ = self->temporal_aq;
1267
1268   if (self->rc_lookahead) {
1269     rc_params->enableLookahead = 1;
1270     rc_params->lookaheadDepth = self->rc_lookahead;
1271     rc_params->disableIadapt = !self->i_adapt;
1272     rc_params->disableBadapt = !self->b_adapt;
1273   }
1274
1275   rc_params->strictGOPTarget = self->strict_gop;
1276   rc_params->enableNonRefP = self->non_ref_p;
1277   rc_params->zeroReorderDelay = self->zero_reorder_delay;
1278
1279   if (self->const_quality) {
1280     guint scaled = (gint) (self->const_quality * 256.0);
1281
1282     rc_params->targetQuality = (guint8) (scaled >> 8);
1283     rc_params->targetQualityLSB = (guint8) (scaled & 0xff);
1284   }
1285   self->init_param_updated = FALSE;
1286   self->bitrate_updated = FALSE;
1287   self->rc_param_updated = FALSE;
1288
1289   config->profileGUID = selected_profile;
1290
1291   hevc_config = &config->encodeCodecConfig.hevcConfig;
1292   vui = &hevc_config->hevcVUIParameters;
1293
1294   hevc_config->level = NV_ENC_LEVEL_AUTOSELECT;
1295   hevc_config->chromaFormatIDC = chroma_format_index;
1296   hevc_config->pixelBitDepthMinus8 = bitdepth_minus8;
1297   hevc_config->idrPeriod = config->gopLength;
1298   hevc_config->outputAUD = self->aud;
1299   if (self->stream_format == GST_NV_H265_ENCODER_HVC1) {
1300     hevc_config->disableSPSPPS = 1;
1301     hevc_config->repeatSPSPPS = 0;
1302   } else if (self->repeat_sequence_header) {
1303     hevc_config->disableSPSPPS = 0;
1304     hevc_config->repeatSPSPPS = 1;
1305   } else {
1306     hevc_config->disableSPSPPS = 0;
1307     hevc_config->repeatSPSPPS = 0;
1308   }
1309
1310   vui->videoSignalTypePresentFlag = 1;
1311   /* Unspecified */
1312   vui->videoFormat = 5;
1313   if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) {
1314     vui->videoFullRangeFlag = 1;
1315   } else {
1316     vui->videoFullRangeFlag = 0;
1317   }
1318
1319   vui->colourDescriptionPresentFlag = 1;
1320   vui->colourMatrix = gst_video_color_matrix_to_iso (info->colorimetry.matrix);
1321   vui->colourPrimaries =
1322       gst_video_color_primaries_to_iso (info->colorimetry.primaries);
1323   vui->transferCharacteristics =
1324       gst_video_transfer_function_to_iso (info->colorimetry.transfer);
1325
1326   g_mutex_unlock (&self->prop_lock);
1327
1328   if (bframe_aborted)
1329     g_object_notify (G_OBJECT (self), "b-frames");
1330   if (weight_pred_aborted)
1331     g_object_notify (G_OBJECT (self), "weighted-pred");
1332   if (vbv_buffer_size_aborted)
1333     g_object_notify (G_OBJECT (self), "vbv-buffer-size");
1334   if (lookahead_aborted)
1335     g_object_notify (G_OBJECT (self), "rc-lookahead");
1336   if (temporal_aq_aborted)
1337     g_object_notify (G_OBJECT (self), "temporal-aq");
1338
1339   return TRUE;
1340 }
1341
1342 static gboolean
1343 gst_nv_h265_encoder_set_output_state (GstNvEncoder * encoder,
1344     GstVideoCodecState * state, gpointer session)
1345 {
1346   GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1347   GstVideoCodecState *output_state;
1348   NV_ENC_SEQUENCE_PARAM_PAYLOAD seq_params = { 0, };
1349   guint8 vpsspspps[1024];
1350   guint32 seq_size;
1351   GstCaps *caps;
1352   const gchar *profile_from_vps;
1353   NVENCSTATUS status;
1354   std::set < std::string > downstream_profiles;
1355   std::string caps_str;
1356   GstTagList *tags;
1357   GstBuffer *codec_data = NULL;
1358   GstH265NalUnit vps_nalu, sps_nalu, pps_nalu;
1359   GstH265ParserResult rst;
1360   gboolean packetized = FALSE;
1361   GstH265VPS vps;
1362   GstH265SPS sps;
1363   gint i, j, k = 0;
1364
1365   if (self->stream_format != GST_NV_H265_ENCODER_BYTE_STREAM)
1366     packetized = TRUE;
1367
1368   caps_str = "video/x-h265, alignment = (string) au";
1369
1370   gst_nv_h265_encoder_get_downstream_profiles_and_format (self,
1371       downstream_profiles, NULL);
1372
1373   seq_params.version = gst_nvenc_get_sequence_param_payload_version ();
1374   seq_params.inBufferSize = sizeof (vpsspspps);
1375   seq_params.spsppsBuffer = &vpsspspps;
1376   seq_params.outSPSPPSPayloadSize = &seq_size;
1377   status = NvEncGetSequenceParams (session, &seq_params);
1378   if (status != NV_ENC_SUCCESS) {
1379     GST_ERROR_OBJECT (self, "Failed to get sequence header, status %"
1380         GST_NVENC_STATUS_FORMAT, GST_NVENC_STATUS_ARGS (status));
1381     return FALSE;
1382   }
1383
1384   rst = gst_h265_parser_identify_nalu (self->parser,
1385       vpsspspps, 0, seq_size, &vps_nalu);
1386   if (rst != GST_H265_PARSER_OK) {
1387     GST_ERROR_OBJECT (self, "Failed to identify VPS nal");
1388     return FALSE;
1389   }
1390
1391   rst = gst_h265_parser_parse_vps (self->parser, &vps_nalu, &vps);
1392   if (rst != GST_H265_PARSER_OK) {
1393     GST_ERROR_OBJECT (self, "Failed to parse VPS");
1394     return FALSE;
1395   }
1396
1397   rst = gst_h265_parser_identify_nalu (self->parser,
1398       vpsspspps, vps_nalu.offset + vps_nalu.size, seq_size, &sps_nalu);
1399   if (rst != GST_H265_PARSER_OK && packetized) {
1400     GST_ERROR_OBJECT (self, "Failed to identify SPS nal, %d", rst);
1401     return FALSE;
1402   }
1403
1404   if (packetized) {
1405     rst = gst_h265_parser_parse_sps (self->parser, &sps_nalu, &sps, TRUE);
1406     if (rst != GST_H265_PARSER_OK) {
1407       GST_ERROR_OBJECT (self, "Failed to parse SPS");
1408       return FALSE;
1409     }
1410   }
1411
1412   rst = gst_h265_parser_identify_nalu_unchecked (self->parser,
1413       vpsspspps, sps_nalu.offset + sps_nalu.size, seq_size, &pps_nalu);
1414   if (rst != GST_H265_PARSER_OK && packetized) {
1415     GST_ERROR_OBJECT (self, "Failed to identify PPS nal, %d", rst);
1416     return FALSE;
1417   }
1418
1419   if (packetized) {
1420     GstMapInfo info;
1421     guint8 *data;
1422     guint16 min_spatial_segmentation_idc = 0;
1423     GstH265ProfileTierLevel *ptl;
1424
1425     codec_data = gst_buffer_new_and_alloc (38 +
1426         vps_nalu.size + sps_nalu.size + pps_nalu.size);
1427
1428     gst_buffer_map (codec_data, &info, GST_MAP_WRITE);
1429     data = (guint8 *) info.data;
1430
1431     memset (data, 0, info.size);
1432
1433     ptl = &sps.profile_tier_level;
1434     if (sps.vui_parameters_present_flag) {
1435       min_spatial_segmentation_idc =
1436           sps.vui_params.min_spatial_segmentation_idc;
1437     }
1438
1439     data[0] = 1;
1440     data[1] =
1441         (ptl->profile_space << 5) | (ptl->tier_flag << 5) | ptl->profile_idc;
1442     for (i = 2; i < 6; i++) {
1443       for (j = 7; j >= 0; j--) {
1444         data[i] |= (ptl->profile_compatibility_flag[k] << j);
1445         k++;
1446       }
1447     }
1448
1449     data[6] =
1450         (ptl->progressive_source_flag << 7) |
1451         (ptl->interlaced_source_flag << 6) |
1452         (ptl->non_packed_constraint_flag << 5) |
1453         (ptl->frame_only_constraint_flag << 4) |
1454         (ptl->max_12bit_constraint_flag << 3) |
1455         (ptl->max_10bit_constraint_flag << 2) |
1456         (ptl->max_8bit_constraint_flag << 1) |
1457         (ptl->max_422chroma_constraint_flag);
1458
1459     data[7] =
1460         (ptl->max_420chroma_constraint_flag << 7) |
1461         (ptl->max_monochrome_constraint_flag << 6) |
1462         (ptl->intra_constraint_flag << 5) |
1463         (ptl->one_picture_only_constraint_flag << 4) |
1464         (ptl->lower_bit_rate_constraint_flag << 3) |
1465         (ptl->max_14bit_constraint_flag << 2);
1466
1467     data[12] = ptl->level_idc;
1468
1469     GST_WRITE_UINT16_BE (data + 13, min_spatial_segmentation_idc);
1470     data[13] |= 0xf0;
1471     data[15] = 0xfc;
1472     data[16] = 0xfc | sps.chroma_format_idc;
1473     data[17] = 0xf8 | sps.bit_depth_luma_minus8;
1474     data[18] = 0xf8 | sps.bit_depth_chroma_minus8;
1475     data[19] = 0x00;
1476     data[20] = 0x00;
1477     data[21] =
1478         0x00 | ((sps.max_sub_layers_minus1 +
1479             1) << 3) | (sps.temporal_id_nesting_flag << 2) | 3;
1480     GST_WRITE_UINT8 (data + 22, 3);     /* numOfArrays */
1481
1482     data += 23;
1483
1484     /* vps */
1485     data[0] = 0x00 | 0x20;
1486     data++;
1487     GST_WRITE_UINT16_BE (data, 1);
1488     data += 2;
1489     GST_WRITE_UINT16_BE (data, vps_nalu.size);
1490     data += 2;
1491     memcpy (data, vps_nalu.data + vps_nalu.offset, vps_nalu.size);
1492     data += vps_nalu.size;
1493
1494     /* sps */
1495     data[0] = 0x00 | 0x21;
1496     data++;
1497     GST_WRITE_UINT16_BE (data, 1);
1498     data += 2;
1499     GST_WRITE_UINT16_BE (data, sps_nalu.size);
1500     data += 2;
1501     memcpy (data, sps_nalu.data + sps_nalu.offset, sps_nalu.size);
1502     data += sps_nalu.size;
1503
1504     /* pps */
1505     data[0] = 0x00 | 0x22;
1506     data++;
1507     GST_WRITE_UINT16_BE (data, 1);
1508     data += 2;
1509     GST_WRITE_UINT16_BE (data, pps_nalu.size);
1510     data += 2;
1511     memcpy (data, pps_nalu.data + pps_nalu.offset, pps_nalu.size);
1512     gst_buffer_unmap (codec_data, &info);
1513   }
1514
1515   profile_from_vps =
1516       gst_codec_utils_h265_get_profile (vps_nalu.data + vps_nalu.offset +
1517       vps_nalu.header_bytes + 4, vps_nalu.size - vps_nalu.header_bytes - 4);
1518   if (!profile_from_vps) {
1519     GST_WARNING_OBJECT (self, "Failed to parse profile from SPS");
1520   } else if (!downstream_profiles.empty ()) {
1521     if (downstream_profiles.find (profile_from_vps) !=
1522         downstream_profiles.end ()) {
1523       caps_str += ", profile = (string) " + std::string (profile_from_vps);
1524     } else if (downstream_profiles.find ("main-10") !=
1525         downstream_profiles.end () && strcmp (profile_from_vps, "main") == 0) {
1526       caps_str += ", profile = (string) main-10";
1527     } else if (downstream_profiles.find ("main-444-10") !=
1528         downstream_profiles.end () &&
1529         strcmp (profile_from_vps, "main-444") == 0) {
1530       caps_str += ", profile = (string) main-444-10";
1531     }
1532   } else {
1533     caps_str += ", profile = (string) " + std::string (profile_from_vps);
1534   }
1535
1536   switch (self->stream_format) {
1537     case GST_NV_H265_ENCODER_HVC1:
1538       caps_str += ", stream-format = (string) hvc1";
1539       break;
1540     case GST_NV_H265_ENCODER_HEV1:
1541       caps_str += ", stream-format = (string) hev1";
1542       break;
1543     default:
1544       caps_str += ", stream-format = (string) byte-stream";
1545       break;
1546   }
1547
1548   caps = gst_caps_from_string (caps_str.c_str ());
1549
1550   if (packetized) {
1551     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
1552     gst_buffer_unref (codec_data);
1553   }
1554
1555   output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1556       caps, state);
1557
1558   GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
1559   gst_video_codec_state_unref (output_state);
1560
1561   tags = gst_tag_list_new_empty ();
1562   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1563       "nvh265encoder", NULL);
1564
1565   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
1566       tags, GST_TAG_MERGE_REPLACE);
1567   gst_tag_list_unref (tags);
1568
1569   return TRUE;
1570 }
1571
1572 static GstBuffer *
1573 gst_nv_h265_encoder_create_output_buffer (GstNvEncoder *
1574     encoder, NV_ENC_LOCK_BITSTREAM * bitstream)
1575 {
1576   GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1577   GstBuffer *buffer;
1578   GstH265ParserResult rst;
1579   GstH265NalUnit nalu;
1580
1581   if (self->stream_format == GST_NV_H265_ENCODER_BYTE_STREAM) {
1582     return gst_buffer_new_memdup (bitstream->bitstreamBufferPtr,
1583         bitstream->bitstreamSizeInBytes);
1584   }
1585
1586   buffer = gst_buffer_new ();
1587   rst = gst_h265_parser_identify_nalu (self->parser,
1588       (guint8 *) bitstream->bitstreamBufferPtr, 0,
1589       bitstream->bitstreamSizeInBytes, &nalu);
1590
1591   if (rst == GST_H265_PARSER_NO_NAL_END)
1592     rst = GST_H265_PARSER_OK;
1593
1594   while (rst == GST_H265_PARSER_OK) {
1595     GstMemory *mem;
1596     guint8 *data;
1597
1598     data = (guint8 *) g_malloc0 (nalu.size + 4);
1599     GST_WRITE_UINT32_BE (data, nalu.size);
1600     memcpy (data + 4, nalu.data + nalu.offset, nalu.size);
1601
1602     mem = gst_memory_new_wrapped ((GstMemoryFlags) 0, data, nalu.size + 4,
1603         0, nalu.size + 4, data, (GDestroyNotify) g_free);
1604     gst_buffer_append_memory (buffer, mem);
1605
1606     rst = gst_h265_parser_identify_nalu (self->parser,
1607         (guint8 *) bitstream->bitstreamBufferPtr, nalu.offset + nalu.size,
1608         bitstream->bitstreamSizeInBytes, &nalu);
1609
1610     if (rst == GST_H265_PARSER_NO_NAL_END)
1611       rst = GST_H265_PARSER_OK;
1612   }
1613
1614   return buffer;
1615 }
1616
1617 static GstNvEncoderReconfigure
1618 gst_nv_h265_encoder_check_reconfigure (GstNvEncoder * encoder,
1619     NV_ENC_CONFIG * config)
1620 {
1621   GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1622   GstNvEncoderReconfigure reconfig = GST_NV_ENCODER_RECONFIGURE_NONE;
1623
1624   /* Dynamic RC param update is not tested, do soft-reconfigure only for
1625    * bitrate update */
1626   g_mutex_lock (&self->prop_lock);
1627   if (self->init_param_updated || self->rc_param_updated) {
1628     reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1629     goto done;
1630   }
1631
1632   if (self->bitrate_updated) {
1633     GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
1634     if (klass->device_caps.dyn_bitrate_change > 0) {
1635       config->rcParams.averageBitRate = self->bitrate * 1024;
1636       config->rcParams.maxBitRate = self->max_bitrate * 1024;
1637       reconfig = GST_NV_ENCODER_RECONFIGURE_BITRATE;
1638     } else {
1639       reconfig = GST_NV_ENCODER_RECONFIGURE_FULL;
1640     }
1641   }
1642
1643 done:
1644   self->init_param_updated = FALSE;
1645   self->rc_param_updated = FALSE;
1646   self->bitrate_updated = FALSE;
1647   g_mutex_unlock (&self->prop_lock);
1648
1649   return reconfig;
1650 }
1651
1652 static gboolean
1653 gst_nv_h265_encoder_select_device (GstNvEncoder * encoder,
1654     const GstVideoInfo * info, GstBuffer * buffer,
1655     GstNvEncoderDeviceData * data)
1656 {
1657   GstNvH265Encoder *self = GST_NV_H265_ENCODER (encoder);
1658   GstNvH265EncoderClass *klass = GST_NV_H265_ENCODER_GET_CLASS (self);
1659   GstMemory *mem;
1660
1661   memset (data, 0, sizeof (GstNvEncoderDeviceData));
1662
1663   g_assert (klass->device_mode == GST_NV_ENCODER_DEVICE_AUTO_SELECT);
1664
1665   mem = gst_buffer_peek_memory (buffer, 0);
1666   if (klass->cuda_device_id_size > 0 && gst_is_cuda_memory (mem)) {
1667     GstCudaMemory *cmem = GST_CUDA_MEMORY_CAST (mem);
1668     GstCudaContext *context = cmem->context;
1669     guint device_id;
1670     gboolean found = FALSE;
1671
1672     g_object_get (context, "cuda-device-id", &device_id, nullptr);
1673
1674     data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1675     self->selected_device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1676
1677     for (guint i = 0; i < klass->cuda_device_id_size; i++) {
1678       if (klass->cuda_device_id_list[i] == device_id) {
1679         data->cuda_device_id = device_id;
1680         found = TRUE;
1681         break;
1682       }
1683     }
1684
1685     if (!found) {
1686       GST_INFO_OBJECT (self,
1687           "Upstream CUDA device is not in supported device list");
1688       data->cuda_device_id = self->cuda_device_id;
1689     } else {
1690       data->device = (GstObject *) gst_object_ref (context);
1691     }
1692
1693     if (data->cuda_device_id != self->cuda_device_id) {
1694       self->cuda_device_id = data->cuda_device_id;
1695       g_object_notify (G_OBJECT (self), "cuda-device-id");
1696     }
1697
1698     return TRUE;
1699   }
1700 #ifdef GST_CUDA_HAS_D3D
1701   if (klass->adapter_luid_size > 0 && gst_is_d3d11_memory (mem)) {
1702     GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
1703     GstD3D11Device *device = dmem->device;
1704     gint64 adapter_luid;
1705     gboolean found = FALSE;
1706
1707     g_object_get (device, "adapter-luid", &adapter_luid, nullptr);
1708
1709     data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1710     self->selected_device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1711
1712     for (guint i = 0; i < klass->cuda_device_id_size; i++) {
1713       if (klass->adapter_luid_list[i] == adapter_luid) {
1714         data->adapter_luid = adapter_luid;
1715         found = TRUE;
1716         break;
1717       }
1718     }
1719
1720     if (!found) {
1721       GST_INFO_OBJECT (self,
1722           "Upstream D3D11 device is not in supported device list");
1723       data->adapter_luid = self->adapter_luid;
1724     } else {
1725       data->device = (GstObject *) gst_object_ref (device);
1726     }
1727
1728     if (data->adapter_luid != self->adapter_luid) {
1729       self->adapter_luid = data->adapter_luid;
1730       g_object_notify (G_OBJECT (self), "adapter-luid");
1731     }
1732
1733     return TRUE;
1734   }
1735 #endif
1736
1737   if (klass->cuda_device_id_size > 0 &&
1738       (self->selected_device_mode != GST_NV_ENCODER_DEVICE_D3D11)) {
1739     GST_INFO_OBJECT (self, "Upstream is system memory, use CUDA mode");
1740     data->device_mode = GST_NV_ENCODER_DEVICE_CUDA;
1741     data->cuda_device_id = self->cuda_device_id;
1742   } else {
1743     GST_INFO_OBJECT (self, "Upstream is system memory, use CUDA mode");
1744     data->device_mode = GST_NV_ENCODER_DEVICE_D3D11;
1745     data->adapter_luid = self->adapter_luid;
1746   }
1747
1748   self->selected_device_mode = data->device_mode;
1749
1750   return TRUE;
1751 }
1752
1753 static GstNvEncoderClassData *
1754 gst_nv_h265_encoder_create_class_data (GstObject * device, gpointer session,
1755     GstNvEncoderDeviceMode device_mode)
1756 {
1757   NVENCSTATUS status;
1758   GstNvEncoderDeviceCaps dev_caps = { 0, };
1759   GUID profile_guids[16];
1760   NV_ENC_BUFFER_FORMAT input_formats[16];
1761   guint32 profile_guid_count = 0;
1762   guint32 input_format_count = 0;
1763   std::string sink_caps_str;
1764   std::string src_caps_str;
1765   std::string format_str;
1766   std::set < std::string > formats;
1767   std::set < std::string > profiles;
1768   std::string profile_str;
1769   std::string resolution_str;
1770   GstNvEncoderClassData *cdata;
1771   GstCaps *sink_caps;
1772   GstCaps *system_caps;
1773
1774   status = NvEncGetEncodeProfileGUIDs (session, NV_ENC_CODEC_HEVC_GUID,
1775       profile_guids, G_N_ELEMENTS (profile_guids), &profile_guid_count);
1776   if (status != NV_ENC_SUCCESS || profile_guid_count == 0) {
1777     GST_WARNING_OBJECT (device, "Unable to get supported profiles");
1778     return NULL;
1779   }
1780
1781   status = NvEncGetInputFormats (session, NV_ENC_CODEC_HEVC_GUID, input_formats,
1782       G_N_ELEMENTS (input_formats), &input_format_count);
1783   if (status != NV_ENC_SUCCESS || input_format_count == 0) {
1784     GST_WARNING_OBJECT (device, "Unable to get supported input formats");
1785     return NULL;
1786   }
1787
1788   gst_nv_encoder_get_encoder_caps (session, &NV_ENC_CODEC_HEVC_GUID, &dev_caps);
1789
1790   for (guint32 i = 0; i < input_format_count; i++) {
1791     switch (input_formats[i]) {
1792       case NV_ENC_BUFFER_FORMAT_NV12:
1793         formats.insert ("NV12");
1794         break;
1795       case NV_ENC_BUFFER_FORMAT_YUV444:
1796         if (dev_caps.yuv444_encode)
1797           formats.insert ("Y444");
1798         break;
1799       case NV_ENC_BUFFER_FORMAT_YUV420_10BIT:
1800         if (dev_caps.supports_10bit_encode)
1801           formats.insert ("P010_10LE");
1802         break;
1803       case NV_ENC_BUFFER_FORMAT_YUV444_10BIT:
1804         if (dev_caps.supports_10bit_encode && dev_caps.yuv444_encode)
1805           formats.insert ("Y444_16LE");
1806         break;
1807       default:
1808         break;
1809     }
1810   }
1811
1812   if (formats.empty ()) {
1813     GST_WARNING_OBJECT (device, "Empty supported input format");
1814     return NULL;
1815   }
1816 #define APPEND_STRING(dst,set,str) G_STMT_START { \
1817   if (set.find(str) != set.end()) { \
1818     if (!first) \
1819       dst += ", "; \
1820     dst += str; \
1821     first = false; \
1822   } \
1823 } G_STMT_END
1824
1825   if (formats.size () == 1) {
1826     format_str = "format = (string) " + *(formats.begin ());
1827   } else {
1828     bool first = true;
1829
1830     format_str = "format = (string) { ";
1831     APPEND_STRING (format_str, formats, "NV12");
1832     APPEND_STRING (format_str, formats, "P010_10LE");
1833     APPEND_STRING (format_str, formats, "Y444");
1834     APPEND_STRING (format_str, formats, "Y444_16LE");
1835     format_str += " }";
1836   }
1837
1838   for (guint32 i = 0; i < profile_guid_count; i++) {
1839     if (profile_guids[i] == NV_ENC_HEVC_PROFILE_MAIN_GUID) {
1840       profiles.insert ("main");
1841     } else if (profile_guids[i] == NV_ENC_HEVC_PROFILE_MAIN10_GUID) {
1842       profiles.insert ("main-10");
1843     } else if (profile_guids[i] == NV_ENC_HEVC_PROFILE_FREXT_GUID) {
1844       if (formats.find ("Y444") != formats.end ())
1845         profiles.insert ("main-444");
1846       if (formats.find ("Y444_16LE") != formats.end ())
1847         profiles.insert ("main-444-10");
1848     }
1849   }
1850
1851   if (profiles.empty ()) {
1852     GST_WARNING_OBJECT (device, "Empty supported h265 profile");
1853     return NULL;
1854   }
1855
1856   if (profiles.size () == 1) {
1857     profile_str = "profile = (string) " + *(profiles.begin ());
1858   } else {
1859     bool first = true;
1860
1861     profile_str = "profile = (string) { ";
1862     APPEND_STRING (profile_str, profiles, "main");
1863     APPEND_STRING (profile_str, profiles, "main-10");
1864     APPEND_STRING (profile_str, profiles, "main-444");
1865     APPEND_STRING (profile_str, profiles, "main-444-10");
1866     profile_str += " }";
1867   }
1868 #undef APPEND_STRING
1869
1870   resolution_str = "width = (int) [ " +
1871       std::to_string (GST_ROUND_UP_16 (dev_caps.width_min))
1872       + ", " + std::to_string (dev_caps.width_max) + " ]";
1873   resolution_str += ", height = (int) [ " +
1874       std::to_string (GST_ROUND_UP_16 (dev_caps.height_min))
1875       + ", " + std::to_string (dev_caps.height_max) + " ]";
1876
1877   sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str
1878       + ", interlace-mode = (string) progressive";
1879
1880   src_caps_str = "video/x-h265, " + resolution_str + ", " + profile_str +
1881       ", stream-format = (string) { hvc1, hev1, byte-stream }" +
1882       ", alignment = (string) au";
1883
1884   system_caps = gst_caps_from_string (sink_caps_str.c_str ());
1885   sink_caps = gst_caps_copy (system_caps);
1886 #ifdef GST_CUDA_HAS_D3D
1887   if (device_mode == GST_NV_ENCODER_DEVICE_D3D11) {
1888     gst_caps_set_features (sink_caps, 0,
1889         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
1890   }
1891 #endif
1892
1893   if (device_mode == GST_NV_ENCODER_DEVICE_CUDA) {
1894     gst_caps_set_features (sink_caps, 0,
1895         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr));
1896   }
1897
1898   gst_caps_append (sink_caps, system_caps);
1899
1900   cdata = gst_nv_encoder_class_data_new ();
1901   cdata->sink_caps = sink_caps;
1902   cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
1903   cdata->device_caps = dev_caps;
1904   cdata->device_mode = device_mode;
1905
1906   /* *INDENT-OFF* */
1907   for (const auto &iter: formats)
1908     cdata->formats = g_list_append (cdata->formats, g_strdup (iter.c_str()));
1909
1910   for (const auto &iter: profiles)
1911     cdata->profiles = g_list_append (cdata->profiles, g_strdup (iter.c_str()));
1912   /* *INDENT-ON* */
1913
1914   if (device_mode == GST_NV_ENCODER_DEVICE_D3D11)
1915     g_object_get (device, "adapter-luid", &cdata->adapter_luid, nullptr);
1916
1917   if (device_mode == GST_NV_ENCODER_DEVICE_CUDA)
1918     g_object_get (device, "cuda-device-id", &cdata->cuda_device_id, nullptr);
1919
1920   /* class data will be leaked if the element never gets instantiated */
1921   GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1922       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1923   GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
1924       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1925
1926   return cdata;
1927 }
1928
1929 GstNvEncoderClassData *
1930 gst_nv_h265_encoder_register_cuda (GstPlugin * plugin, GstCudaContext * context,
1931     guint rank)
1932 {
1933   NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
1934   gpointer session;
1935   NVENCSTATUS status;
1936   GstNvEncoderClassData *cdata;
1937
1938   GST_DEBUG_CATEGORY_INIT (gst_nv_h265_encoder_debug, "nvh265encoder", 0,
1939       "nvh265encoder");
1940
1941   session_params.version =
1942       gst_nvenc_get_open_encode_session_ex_params_version ();
1943   session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
1944   session_params.device = gst_cuda_context_get_handle (context);
1945   session_params.apiVersion = gst_nvenc_get_api_version ();
1946
1947   status = NvEncOpenEncodeSessionEx (&session_params, &session);
1948   if (status != NV_ENC_SUCCESS) {
1949     GST_WARNING_OBJECT (context, "Failed to open session");
1950     return nullptr;
1951   }
1952
1953   cdata = gst_nv_h265_encoder_create_class_data (GST_OBJECT (context), session,
1954       GST_NV_ENCODER_DEVICE_CUDA);
1955   NvEncDestroyEncoder (session);
1956
1957   if (!cdata)
1958     return nullptr;
1959
1960   gst_nv_encoder_class_data_ref (cdata);
1961
1962   GType type;
1963   gchar *type_name;
1964   gchar *feature_name;
1965   GTypeInfo type_info = {
1966     sizeof (GstNvH265EncoderClass),
1967     NULL,
1968     NULL,
1969     (GClassInitFunc) gst_nv_h265_encoder_class_init,
1970     NULL,
1971     cdata,
1972     sizeof (GstNvH265Encoder),
1973     0,
1974     (GInstanceInitFunc) gst_nv_h265_encoder_init,
1975   };
1976
1977   type_name = g_strdup ("GstNvCudaH265Enc");
1978   feature_name = g_strdup ("nvcudah265enc");
1979
1980   gint index = 0;
1981   while (g_type_from_name (type_name)) {
1982     index++;
1983     g_free (type_name);
1984     g_free (feature_name);
1985     type_name = g_strdup_printf ("GstNvCudaH265Device%dEnc", index);
1986     feature_name = g_strdup_printf ("nvcudah265device%denc", index);
1987   }
1988
1989   type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
1990       &type_info, (GTypeFlags) 0);
1991
1992   if (rank > 0 && index != 0)
1993     rank--;
1994
1995   if (index != 0)
1996     gst_element_type_set_skip_documentation (type);
1997
1998   if (!gst_element_register (plugin, feature_name, rank, type))
1999     GST_WARNING ("Failed to register plugin '%s'", type_name);
2000
2001   g_free (type_name);
2002   g_free (feature_name);
2003
2004   return cdata;
2005 }
2006
2007 #ifdef GST_CUDA_HAS_D3D
2008 GstNvEncoderClassData *
2009 gst_nv_h265_encoder_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
2010     guint rank)
2011 {
2012   NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS session_params = { 0, };
2013   gpointer session;
2014   NVENCSTATUS status;
2015   GstNvEncoderClassData *cdata;
2016
2017   GST_DEBUG_CATEGORY_INIT (gst_nv_h265_encoder_debug, "nvh265encoder", 0,
2018       "nvh265encoder");
2019
2020   session_params.version =
2021       gst_nvenc_get_open_encode_session_ex_params_version ();
2022   session_params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
2023   session_params.device = gst_d3d11_device_get_device_handle (device);
2024   session_params.apiVersion = gst_nvenc_get_api_version ();
2025
2026   status = NvEncOpenEncodeSessionEx (&session_params, &session);
2027   if (status != NV_ENC_SUCCESS) {
2028     GST_WARNING_OBJECT (device, "Failed to open session");
2029     return nullptr;
2030   }
2031
2032   cdata = gst_nv_h265_encoder_create_class_data (GST_OBJECT (device), session,
2033       GST_NV_ENCODER_DEVICE_D3D11);
2034   NvEncDestroyEncoder (session);
2035
2036   if (!cdata)
2037     return nullptr;
2038
2039   gst_nv_encoder_class_data_ref (cdata);
2040
2041   GType type;
2042   gchar *type_name;
2043   gchar *feature_name;
2044   GTypeInfo type_info = {
2045     sizeof (GstNvH265EncoderClass),
2046     NULL,
2047     NULL,
2048     (GClassInitFunc) gst_nv_h265_encoder_class_init,
2049     NULL,
2050     cdata,
2051     sizeof (GstNvH265Encoder),
2052     0,
2053     (GInstanceInitFunc) gst_nv_h265_encoder_init,
2054   };
2055
2056   type_name = g_strdup ("GstNvD3D11H265Enc");
2057   feature_name = g_strdup ("nvd3d11h265enc");
2058
2059   gint index = 0;
2060   while (g_type_from_name (type_name)) {
2061     index++;
2062     g_free (type_name);
2063     g_free (feature_name);
2064     type_name = g_strdup_printf ("GstNvD3D11H265Device%dEnc", index);
2065     feature_name = g_strdup_printf ("nvd3d11h265device%denc", index);
2066   }
2067
2068   type = g_type_register_static (GST_TYPE_NV_ENCODER, type_name,
2069       &type_info, (GTypeFlags) 0);
2070
2071   if (rank > 0 && index != 0)
2072     rank--;
2073
2074   if (index != 0)
2075     gst_element_type_set_skip_documentation (type);
2076
2077   if (!gst_element_register (plugin, feature_name, rank, type))
2078     GST_WARNING ("Failed to register plugin '%s'", type_name);
2079
2080   g_free (type_name);
2081   g_free (feature_name);
2082
2083   return cdata;
2084 }
2085 #endif
2086
2087 void
2088 gst_nv_h265_encoder_register_auto_select (GstPlugin * plugin,
2089     GList * device_caps_list, guint rank)
2090 {
2091   std::set < std::string > formats;
2092   std::set < std::string > profiles;
2093   std::string sink_caps_str;
2094   std::string src_caps_str;
2095   std::string format_str;
2096   std::string profile_str;
2097   std::string resolution_str;
2098   GList *iter;
2099   guint adapter_luid_size = 0;
2100   gint64 adapter_luid_list[8];
2101   guint cuda_device_id_size = 0;
2102   guint cuda_device_id_list[8];
2103   GstNvEncoderDeviceCaps dev_caps;
2104   GstNvEncoderClassData *cdata;
2105   GstCaps *sink_caps = nullptr;
2106   GstCaps *system_caps;
2107
2108   GST_DEBUG_CATEGORY_INIT (gst_nv_h265_encoder_debug, "nvh265encoder", 0,
2109       "nvh265encoder");
2110
2111   for (iter = device_caps_list; iter; iter = g_list_next (iter)) {
2112     GstNvEncoderClassData *cdata = (GstNvEncoderClassData *) iter->data;
2113     GList *walk;
2114
2115     for (walk = cdata->formats; walk; walk = g_list_next (walk))
2116       formats.insert ((gchar *) walk->data);
2117
2118     for (walk = cdata->profiles; walk; walk = g_list_next (walk))
2119       profiles.insert ((gchar *) walk->data);
2120
2121     if (cdata->device_mode == GST_NV_ENCODER_DEVICE_D3D11 &&
2122         adapter_luid_size < G_N_ELEMENTS (adapter_luid_list) - 1) {
2123       adapter_luid_list[adapter_luid_size] = cdata->adapter_luid;
2124       adapter_luid_size++;
2125     }
2126
2127     if (cdata->device_mode == GST_NV_ENCODER_DEVICE_CUDA &&
2128         cuda_device_id_size < G_N_ELEMENTS (cuda_device_id_list) - 1) {
2129       cuda_device_id_list[cuda_device_id_size] = cdata->cuda_device_id;
2130       cuda_device_id_size++;
2131     }
2132
2133     if (iter == device_caps_list) {
2134       dev_caps = cdata->device_caps;
2135     } else {
2136       gst_nv_encoder_merge_device_caps (&dev_caps, &cdata->device_caps,
2137           &dev_caps);
2138     }
2139   }
2140
2141   g_list_free_full (device_caps_list,
2142       (GDestroyNotify) gst_nv_encoder_class_data_unref);
2143   if (formats.empty () || profiles.empty ())
2144     return;
2145
2146 #define APPEND_STRING(dst,set,str) G_STMT_START { \
2147   if (set.find(str) != set.end()) { \
2148     if (!first) \
2149       dst += ", "; \
2150     dst += str; \
2151     first = false; \
2152   } \
2153 } G_STMT_END
2154
2155   if (formats.size () == 1) {
2156     format_str = "format = (string) " + *(formats.begin ());
2157   } else {
2158     bool first = true;
2159
2160     format_str = "format = (string) { ";
2161     APPEND_STRING (format_str, formats, "NV12");
2162     APPEND_STRING (format_str, formats, "P010_10LE");
2163     APPEND_STRING (format_str, formats, "Y444");
2164     APPEND_STRING (format_str, formats, "Y444_16LE");
2165     format_str += " }";
2166   }
2167
2168   if (profiles.size () == 1) {
2169     profile_str = "profile = (string) " + *(profiles.begin ());
2170   } else {
2171     bool first = true;
2172
2173     profile_str = "profile = (string) { ";
2174     APPEND_STRING (profile_str, profiles, "main");
2175     APPEND_STRING (profile_str, profiles, "main-10");
2176     APPEND_STRING (profile_str, profiles, "main-444");
2177     APPEND_STRING (profile_str, profiles, "main-444-10");
2178     profile_str += " }";
2179   }
2180 #undef APPEND_STRING
2181
2182   resolution_str = "width = (int) [ " +
2183       std::to_string (GST_ROUND_UP_16 (dev_caps.width_min))
2184       + ", " + std::to_string (dev_caps.width_max) + " ]";
2185   resolution_str += ", height = (int) [ " +
2186       std::to_string (GST_ROUND_UP_16 (dev_caps.height_min))
2187       + ", " + std::to_string (dev_caps.height_max) + " ]";
2188
2189   sink_caps_str = "video/x-raw, " + format_str + ", " + resolution_str
2190       + ", interlace-mode = (string) progressive";
2191
2192   src_caps_str = "video/x-h265, " + resolution_str + ", " + profile_str +
2193       ", stream-format = (string) { hvc1, hev1, byte-stream }" +
2194       ", alignment = (string) au";
2195
2196   system_caps = gst_caps_from_string (sink_caps_str.c_str ());
2197   sink_caps = gst_caps_new_empty ();
2198
2199   if (cuda_device_id_size > 0) {
2200     GstCaps *cuda_caps = gst_caps_copy (system_caps);
2201     gst_caps_set_features (cuda_caps, 0,
2202         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr));
2203     gst_caps_append (sink_caps, cuda_caps);
2204   }
2205 #ifdef GST_CUDA_HAS_D3D
2206   if (adapter_luid_size > 0) {
2207     GstCaps *d3d11_caps = gst_caps_copy (system_caps);
2208     gst_caps_set_features (d3d11_caps, 0,
2209         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
2210     gst_caps_append (sink_caps, d3d11_caps);
2211   }
2212 #endif
2213
2214   gst_caps_append (sink_caps, system_caps);
2215
2216   cdata = gst_nv_encoder_class_data_new ();
2217   cdata->sink_caps = sink_caps;
2218   cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
2219   cdata->device_caps = dev_caps;
2220   cdata->device_mode = GST_NV_ENCODER_DEVICE_AUTO_SELECT;
2221   cdata->adapter_luid = adapter_luid_list[0];
2222   cdata->adapter_luid_size = adapter_luid_size;
2223   memcpy (&cdata->adapter_luid_list,
2224       adapter_luid_list, sizeof (adapter_luid_list));
2225   cdata->cuda_device_id = cuda_device_id_list[0];
2226   cdata->cuda_device_id_size = cuda_device_id_size;
2227   memcpy (&cdata->cuda_device_id_list,
2228       cuda_device_id_list, sizeof (cuda_device_id_list));
2229
2230   /* class data will be leaked if the element never gets instantiated */
2231   GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
2232       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2233   GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
2234       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2235
2236   GType type;
2237   GTypeInfo type_info = {
2238     sizeof (GstNvH265EncoderClass),
2239     nullptr,
2240     nullptr,
2241     (GClassInitFunc) gst_nv_h265_encoder_class_init,
2242     nullptr,
2243     cdata,
2244     sizeof (GstNvH265Encoder),
2245     0,
2246     (GInstanceInitFunc) gst_nv_h265_encoder_init,
2247   };
2248
2249   type = g_type_register_static (GST_TYPE_NV_ENCODER, "GstNvAutoGpuH265Enc",
2250       &type_info, (GTypeFlags) 0);
2251
2252   if (!gst_element_register (plugin, "nvautogpuh265enc", rank, type))
2253     GST_WARNING ("Failed to register plugin 'GstNvAutoGpuH265Enc'");
2254 }