2615faa8e65d4bc7e655775309fcb97062949cd5
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / amfcodec / gstamfav1enc.cpp
1 /* GStreamer
2  * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
3  * Copyright (C) 2022 Evgeny Pavlov <lucenticus@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * SECTION:element-amfav1enc
23  * @title: amfav1enc
24  * @short_description: An AMD AMF API based AV1 video encoder
25  *
26  * amfav1enc element encodes raw video stream into compressed AV1 bitstream
27  * via AMD AMF API.
28  *
29  * ## Example launch line
30  * ```
31  * gst-launch-1.0 videotestsrc num-buffers=100 ! amfav1enc ! av1parse ! webmmux ! filesink location=encoded.webm
32  * ```
33  *
34  * Since: 1.22
35  *
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include "gstamfav1enc.h"
43 #include <components/Component.h>
44 #include <components/VideoEncoderAV1.h>
45 #include <core/Factory.h>
46 #include <string>
47 #include <vector>
48 #include <string.h>
49
50 using namespace amf;
51
52 GST_DEBUG_CATEGORY_STATIC (gst_amf_av1_enc_debug);
53 #define GST_CAT_DEFAULT gst_amf_av1_enc_debug
54
55 static GTypeClass *parent_class = nullptr;
56
57 typedef struct
58 {
59   amf_int64 num_of_hw_instances;
60   amf_int64 max_throughput;
61   amf_int64 requested_throughput;
62   amf_int64 color_conversion;
63   amf_int64 pre_analysis;
64   amf_int64 max_bitrate;
65   amf_int64 max_profile;
66   amf_int64 max_level;
67   amf_int64 max_num_temporal_layers;
68   amf_int64 max_num_ltr_frames;
69   amf_int64 default_qp_i;
70   amf_int64 default_qp_p;
71   amf_int64 min_gop_size;
72   amf_int64 max_gop_size;
73   amf_int64 default_gop_size;
74   guint valign;
75 } GstAmfAv1EncDeviceCaps;
76
77 /**
78  * GstAmfAv1EncUsage:
79  *
80  * Encoder usages
81  *
82  * Since: 1.22
83  */
84 #define GST_TYPE_AMF_AV1_ENC_USAGE (gst_amf_av1_enc_usage_get_type ())
85 static GType
86 gst_amf_av1_enc_usage_get_type (void)
87 {
88   static GType usage_type = 0;
89   static const GEnumValue usages[] = {
90     /**
91      * GstAmfAv1EncUsage::transcoding:
92      *
93      * Transcoding usage
94      */
95     {AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING, "Transcoding", "transcoding"},
96
97     /**
98      * GstAmfAv1EncUsage::low-latency:
99      *
100      * Low Latency usage
101      */
102     {AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY, "Low Latency", "low-latency"},
103     {0, nullptr, nullptr}
104   };
105
106   if (g_once_init_enter (&usage_type)) {
107     GType type = g_enum_register_static ("GstAmfAv1EncUsage", usages);
108     g_once_init_leave (&usage_type, type);
109   }
110
111   return usage_type;
112 }
113
114 /**
115  * GstAmfAv1EncRateControl:
116  *
117  * Rate control methods
118  *
119  * Since: 1.22
120  */
121 #define GST_TYPE_AMF_AV1_ENC_RATE_CONTROL (gst_amf_av1_enc_rate_control_get_type ())
122 static GType
123 gst_amf_av1_enc_rate_control_get_type (void)
124 {
125   static GType rate_control_type = 0;
126   static const GEnumValue rate_controls[] = {
127     /**
128      * GstAmfAv1EncRateControl::default:
129      *
130      * Default rate control method depending on usage
131      */
132     {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN,
133         "Default, depends on Usage", "default"},
134
135     /**
136      * GstAmfAv1EncRateControl::cqp:
137      *
138      * Constant QP
139      */
140     {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP, "Constant QP",
141         "cqp"},
142
143     /**
144      * GstAmfAv1EncRateControl::lcvbr:
145      *
146      * Latency Constrained Variable Bitrate
147      */
148     {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
149         "Latency Constrained VBR", "lcvbr"},
150
151     /**
152      * GstAmfAv1EncRateControl::vbr:
153      *
154      * Peak Constrained Variable Bitrate
155      */
156     {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
157         "Peak Constrained VBR", "vbr"},
158
159     /**
160      * GstAmfAv1EncRateControl::cbr:
161      *
162      * Constant Bitrate
163      */
164     {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR, "Constant Bitrate", "cbr"},
165     {0, nullptr, nullptr}
166   };
167
168   if (g_once_init_enter (&rate_control_type)) {
169     GType type =
170         g_enum_register_static ("GstAmfAv1EncRateControl", rate_controls);
171     g_once_init_leave (&rate_control_type, type);
172   }
173
174   return rate_control_type;
175 }
176
177 /**
178  * GstAmfAv1EncPreset:
179  *
180  * Encoding quality presets
181  *
182  * Since: 1.22
183  */
184 #define AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_UNKNOWN -1
185 #define GST_TYPE_AMF_AV1_ENC_PRESET (gst_amf_av1_enc_preset_get_type ())
186 static GType
187 gst_amf_av1_enc_preset_get_type (void)
188 {
189   static GType preset_type = 0;
190   static const GEnumValue presets[] = {
191     /**
192      * GstAmfAv1EncRateControl::default:
193      *
194      * Default preset depends on usage
195      */
196     {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_UNKNOWN, "Default, depends on USAGE",
197         "default"},
198
199     /**
200      * GstAmfAv1EncRateControl::high-quality:
201      *
202      * High quality oriented preset
203      */
204     {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY, "High quality",
205         "high-quality"},
206
207     /**
208      * GstAmfAv1EncRateControl::quality:
209      *
210      * Quality oriented preset
211      */
212     {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY, "Quality", "quality"},
213
214     /**
215      *
216      * GstAmfAv1EncRateControl::balanced:
217      *
218      * Balanced preset
219      */
220     {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED, "Balanced", "balanced"},
221
222     /**
223      * GstAmfAv1EncRateControl::speed:
224      *
225      * Speed oriented preset
226      */
227     {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED, "Speed", "speed"},
228     {0, nullptr, nullptr}
229   };
230
231   if (g_once_init_enter (&preset_type)) {
232     GType type = g_enum_register_static ("GstAmfAv1EncPreset", presets);
233     g_once_init_leave (&preset_type, type);
234   }
235
236   return preset_type;
237 }
238
239 typedef struct
240 {
241   GstCaps *sink_caps;
242   GstCaps *src_caps;
243
244   gint64 adapter_luid;
245
246   GstAmfAv1EncDeviceCaps dev_caps;
247 } GstAmfAv1EncClassData;
248
249 enum
250 {
251   PROP_0,
252   PROP_ADAPTER_LUID,
253   PROP_USAGE,
254   PROP_RATE_CONTROL,
255   PROP_PRESET,
256   PROP_BITRATE,
257   PROP_MAX_BITRATE,
258   PROP_GOP_SIZE,
259   PROP_MIN_QP_I,
260   PROP_MAX_QP_I,
261   PROP_MIN_QP_P,
262   PROP_MAX_QP_P,
263   PROP_QP_I,
264   PROP_QP_P,
265   PROP_REF_FRAMES,
266 };
267
268 #define DEFAULT_USAGE AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING
269 #define DEFAULT_RATE_CONTROL AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN
270 #define DEFAULT_PRESET AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_UNKNOWN
271 #define DEFAULT_BITRATE 0
272 #define DEFAULT_MAX_BITRATE 0
273 #define DEFAULT_MIN_MAX_QP -1
274 #define DEFAULT_REF_FRAMES 1
275
276 #define DOC_SINK_CAPS_COMM \
277     "format = (string) NV12, " \
278     "width = (int) [ 128, 4096 ], height = (int) [ 128, 4096 ]"
279
280 #define DOC_SINK_CAPS \
281     "video/x-raw(memory:D3D11Memory), " DOC_SINK_CAPS_COMM "; " \
282     "video/x-raw, " DOC_SINK_CAPS_COMM
283
284 #define DOC_SRC_CAPS \
285     "video/x-av1, width = (int) [ 128, 4096 ], height = (int) [ 128, 4096 ], " \
286     "profile = (string) main, alignment= (string) tu"
287
288 typedef struct _GstAmfAv1Enc
289 {
290   GstAmfEncoder parent;
291
292   GMutex prop_lock;
293   gboolean property_updated;
294   gint usage;
295   gint rate_control;
296   gint preset;
297   guint bitrate;
298   guint max_bitrate;
299   guint gop_size;
300   gint min_qp_i;
301   gint max_qp_i;
302   gint min_qp_p;
303   gint max_qp_p;
304   guint qp_i;
305   guint qp_p;
306   guint ref_frames;
307 } GstAmfAv1Enc;
308
309 typedef struct _GstAmfAv1EncClass
310 {
311   GstAmfEncoderClass parent_class;
312   GstAmfAv1EncDeviceCaps dev_caps;
313
314   gint64 adapter_luid;
315 } GstAmfAv1EncClass;
316
317 #define GST_AMF_AV1_ENC(object) ((GstAmfAv1Enc *) (object))
318 #define GST_AMF_AV1_ENC_GET_CLASS(object) \
319     (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstAmfAv1EncClass))
320
321 static void gst_amf_av1_enc_finalize (GObject * object);
322 static void gst_amf_av1_enc_set_property (GObject * object, guint prop_id,
323     const GValue * value, GParamSpec * pspec);
324 static void gst_amf_av1_enc_get_property (GObject * object, guint prop_id,
325     GValue * value, GParamSpec * pspec);
326 static gboolean gst_amf_av1_enc_set_format (GstAmfEncoder * encoder,
327     GstVideoCodecState * state, gpointer component);
328 static gboolean gst_amf_av1_enc_set_output_state (GstAmfEncoder * encoder,
329     GstVideoCodecState * state, gpointer component);
330 static gboolean gst_amf_av1_enc_set_surface_prop (GstAmfEncoder * encoder,
331     GstVideoCodecFrame * frame, gpointer surface);
332 static GstBuffer *gst_amf_av1_enc_create_output_buffer (GstAmfEncoder *
333     encoder, gpointer data, gboolean * sync_point);
334 static gboolean gst_amf_av1_enc_check_reconfigure (GstAmfEncoder * encoder);
335
336 static void
337 gst_amf_av1_enc_class_init (GstAmfAv1EncClass * klass, gpointer data)
338 {
339   GObjectClass *object_class = G_OBJECT_CLASS (klass);
340   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
341   GstAmfEncoderClass *amf_class = GST_AMF_ENCODER_CLASS (klass);
342   GstAmfAv1EncClassData *cdata = (GstAmfAv1EncClassData *) data;
343   GstAmfAv1EncDeviceCaps *dev_caps = &cdata->dev_caps;
344   GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE |
345       GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS);
346   GstPadTemplate *pad_templ;
347   GstCaps *doc_caps;
348
349   parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
350
351   object_class->finalize = gst_amf_av1_enc_finalize;
352   object_class->set_property = gst_amf_av1_enc_set_property;
353   object_class->get_property = gst_amf_av1_enc_get_property;
354
355   g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
356       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
357           "DXGI Adapter LUID (Locally Unique Identifier) of associated GPU",
358           G_MININT64, G_MAXINT64, 0, (GParamFlags) (GST_PARAM_DOC_SHOW_DEFAULT |
359               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
360   g_object_class_install_property (object_class, PROP_USAGE,
361       g_param_spec_enum ("usage", "Usage",
362           "Target usage", GST_TYPE_AMF_AV1_ENC_USAGE,
363           DEFAULT_USAGE, param_flags));
364   g_object_class_install_property (object_class, PROP_RATE_CONTROL,
365       g_param_spec_enum ("rate-control", "Rate Control",
366           "Rate Control Method", GST_TYPE_AMF_AV1_ENC_RATE_CONTROL,
367           DEFAULT_RATE_CONTROL, param_flags));
368   g_object_class_install_property (object_class, PROP_PRESET,
369       g_param_spec_enum ("preset", "Preset",
370           "Preset", GST_TYPE_AMF_AV1_ENC_PRESET, DEFAULT_PRESET, param_flags));
371   g_object_class_install_property (object_class, PROP_BITRATE,
372       g_param_spec_uint ("bitrate", "Bitrate",
373           "Target bitrate in kbit/sec (0: USAGE default)",
374           0, G_MAXINT / 1000, DEFAULT_BITRATE, param_flags));
375   g_object_class_install_property (object_class, PROP_MAX_BITRATE,
376       g_param_spec_uint ("max-bitrate", "Max Bitrate",
377           "Maximum bitrate in kbit/sec (0: USAGE default)",
378           0, G_MAXINT / 1000, DEFAULT_MAX_BITRATE, param_flags));
379   g_object_class_install_property (object_class, PROP_GOP_SIZE,
380       g_param_spec_uint ("gop-size", "GOP Size",
381           "Number of pictures within a GOP",
382           (guint) dev_caps->min_gop_size, (guint) dev_caps->max_gop_size,
383           (guint) dev_caps->default_gop_size, 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 allowed QP value for I frames (-1: USAGE default)",
387           -1, 255, DEFAULT_MIN_MAX_QP, param_flags));
388   g_object_class_install_property (object_class, PROP_MAX_QP_I,
389       g_param_spec_int ("max-qp-i", "Max QP I",
390           "Maximum allowed QP value for I frames (-1: USAGE default)",
391           -1, 255, DEFAULT_MIN_MAX_QP, param_flags));
392   g_object_class_install_property (object_class, PROP_MIN_QP_P,
393       g_param_spec_int ("min-qp-p", "Min QP P",
394           "Minimum allowed QP value for P frames (-1: USAGE default)",
395           -1, 255, DEFAULT_MIN_MAX_QP, param_flags));
396   g_object_class_install_property (object_class, PROP_MAX_QP_P,
397       g_param_spec_int ("max-qp-p", "Max QP P",
398           "Maximum allowed QP value for P frames (-1: USAGE default)",
399           -1, 255, DEFAULT_MIN_MAX_QP, param_flags));
400   g_object_class_install_property (object_class, PROP_QP_I,
401       g_param_spec_uint ("qp-i", "QP I",
402           "Constant QP for I frames", 0, 255,
403           (guint) dev_caps->default_qp_i, param_flags));
404   g_object_class_install_property (object_class, PROP_QP_P,
405       g_param_spec_uint ("qp-p", "QP P",
406           "Constant QP for P frames", 0, 255,
407           (guint) dev_caps->default_qp_p, param_flags));
408   g_object_class_install_property (object_class, PROP_REF_FRAMES,
409       g_param_spec_uint ("ref-frames", "Reference Frames",
410           "Number of reference frames", 0, 8, DEFAULT_REF_FRAMES, param_flags));
411
412   gst_element_class_set_metadata (element_class,
413       "AMD AMF AV1 Video Encoder",
414       "Codec/Encoder/Video/Hardware",
415       "Encode AV1 video streams using AMF API",
416       "Seungha Yang <seungha@centricular.com>, "
417       "Evgeny Pavlov <lucenticus@gmail.com>");
418
419   pad_templ = gst_pad_template_new ("sink",
420       GST_PAD_SINK, GST_PAD_ALWAYS, cdata->sink_caps);
421   doc_caps = gst_caps_from_string (DOC_SINK_CAPS);
422   gst_pad_template_set_documentation_caps (pad_templ, doc_caps);
423   gst_caps_unref (doc_caps);
424   gst_element_class_add_pad_template (element_class, pad_templ);
425
426   pad_templ = gst_pad_template_new ("src",
427       GST_PAD_SRC, GST_PAD_ALWAYS, cdata->src_caps);
428   doc_caps = gst_caps_from_string (DOC_SRC_CAPS);
429   gst_pad_template_set_documentation_caps (pad_templ, doc_caps);
430   gst_caps_unref (doc_caps);
431   gst_element_class_add_pad_template (element_class, pad_templ);
432
433   amf_class->set_format = GST_DEBUG_FUNCPTR (gst_amf_av1_enc_set_format);
434   amf_class->set_output_state =
435       GST_DEBUG_FUNCPTR (gst_amf_av1_enc_set_output_state);
436   amf_class->set_surface_prop =
437       GST_DEBUG_FUNCPTR (gst_amf_av1_enc_set_surface_prop);
438   amf_class->create_output_buffer =
439       GST_DEBUG_FUNCPTR (gst_amf_av1_enc_create_output_buffer);
440   amf_class->check_reconfigure =
441       GST_DEBUG_FUNCPTR (gst_amf_av1_enc_check_reconfigure);
442
443   klass->dev_caps = cdata->dev_caps;
444   klass->adapter_luid = cdata->adapter_luid;
445
446   gst_caps_unref (cdata->sink_caps);
447   gst_caps_unref (cdata->src_caps);
448   g_free (cdata);
449
450   gst_type_mark_as_plugin_api (GST_TYPE_AMF_AV1_ENC_USAGE,
451       (GstPluginAPIFlags) 0);
452   gst_type_mark_as_plugin_api (GST_TYPE_AMF_AV1_ENC_RATE_CONTROL,
453       (GstPluginAPIFlags) 0);
454   gst_type_mark_as_plugin_api (GST_TYPE_AMF_AV1_ENC_PRESET,
455       (GstPluginAPIFlags) 0);
456 }
457
458 static void
459 gst_amf_av1_enc_init (GstAmfAv1Enc * self)
460 {
461   GstAmfAv1EncClass *klass = GST_AMF_AV1_ENC_GET_CLASS (self);
462   GstAmfAv1EncDeviceCaps *dev_caps = &klass->dev_caps;
463
464   gst_amf_encoder_set_subclass_data (GST_AMF_ENCODER (self),
465       klass->adapter_luid, AMFVideoEncoder_AV1);
466
467   g_mutex_init (&self->prop_lock);
468
469   self->usage = DEFAULT_USAGE;
470   self->rate_control = DEFAULT_RATE_CONTROL;
471   self->preset = DEFAULT_PRESET;
472   self->bitrate = DEFAULT_BITRATE;
473   self->max_bitrate = DEFAULT_MAX_BITRATE;
474   self->gop_size = (guint) dev_caps->default_gop_size;
475   self->min_qp_i = DEFAULT_MIN_MAX_QP;
476   self->max_qp_i = DEFAULT_MIN_MAX_QP;
477   self->min_qp_p = DEFAULT_MIN_MAX_QP;
478   self->max_qp_p = DEFAULT_MIN_MAX_QP;
479   self->qp_i = (guint) dev_caps->default_qp_i;
480   self->qp_p = (guint) dev_caps->default_qp_p;
481   self->ref_frames = DEFAULT_REF_FRAMES;
482 }
483
484 static void
485 gst_amf_av1_enc_finalize (GObject * object)
486 {
487   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (object);
488
489   g_mutex_clear (&self->prop_lock);
490
491   G_OBJECT_CLASS (parent_class)->finalize (object);
492 }
493
494 static void
495 update_int (GstAmfAv1Enc * self, gint * old_val, const GValue * new_val)
496 {
497   gint val = g_value_get_int (new_val);
498
499   if (*old_val == val)
500     return;
501
502   *old_val = val;
503   self->property_updated = TRUE;
504 }
505
506 static void
507 update_uint (GstAmfAv1Enc * self, guint * old_val, const GValue * new_val)
508 {
509   guint val = g_value_get_uint (new_val);
510
511   if (*old_val == val)
512     return;
513
514   *old_val = val;
515   self->property_updated = TRUE;
516 }
517
518 static void
519 update_enum (GstAmfAv1Enc * self, gint * old_val, const GValue * new_val)
520 {
521   gint val = g_value_get_enum (new_val);
522
523   if (*old_val == val)
524     return;
525
526   *old_val = val;
527   self->property_updated = TRUE;
528 }
529
530 static void
531 gst_amf_av1_enc_set_property (GObject * object, guint prop_id,
532     const GValue * value, GParamSpec * pspec)
533 {
534   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (object);
535
536   g_mutex_lock (&self->prop_lock);
537   switch (prop_id) {
538     case PROP_USAGE:
539       update_enum (self, &self->usage, value);
540       break;
541     case PROP_RATE_CONTROL:
542       update_enum (self, &self->rate_control, value);
543       break;
544     case PROP_PRESET:
545       update_enum (self, &self->preset, value);
546       break;
547     case PROP_BITRATE:
548       update_uint (self, &self->bitrate, value);
549       break;
550     case PROP_MAX_BITRATE:
551       update_uint (self, &self->max_bitrate, value);
552       break;
553     case PROP_GOP_SIZE:
554       update_uint (self, &self->gop_size, value);
555       break;
556     case PROP_MIN_QP_I:
557       update_int (self, &self->min_qp_i, value);
558       break;
559     case PROP_MAX_QP_I:
560       update_int (self, &self->max_qp_i, value);
561       break;
562     case PROP_MIN_QP_P:
563       update_int (self, &self->min_qp_p, value);
564       break;
565     case PROP_MAX_QP_P:
566       update_int (self, &self->max_qp_p, value);
567       break;
568     case PROP_QP_I:
569       update_uint (self, &self->qp_i, value);
570       break;
571     case PROP_QP_P:
572       update_uint (self, &self->qp_p, value);
573       break;
574     case PROP_REF_FRAMES:
575       update_uint (self, &self->ref_frames, value);
576       break;
577     default:
578       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
579       break;
580   }
581   g_mutex_unlock (&self->prop_lock);
582 }
583
584 static void
585 gst_amf_av1_enc_get_property (GObject * object, guint prop_id,
586     GValue * value, GParamSpec * pspec)
587 {
588   GstAmfAv1EncClass *klass = GST_AMF_AV1_ENC_GET_CLASS (object);
589   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (object);
590
591   switch (prop_id) {
592     case PROP_ADAPTER_LUID:
593       g_value_set_int64 (value, klass->adapter_luid);
594       break;
595     case PROP_USAGE:
596       g_value_set_enum (value, self->usage);
597       break;
598     case PROP_RATE_CONTROL:
599       g_value_set_enum (value, self->rate_control);
600       break;
601     case PROP_PRESET:
602       g_value_set_enum (value, self->preset);
603       break;
604     case PROP_BITRATE:
605       g_value_set_uint (value, self->bitrate);
606       break;
607     case PROP_MAX_BITRATE:
608       g_value_set_uint (value, self->max_bitrate);
609       break;
610     case PROP_GOP_SIZE:
611       g_value_set_uint (value, self->gop_size);
612       break;
613     case PROP_MIN_QP_I:
614       g_value_set_int (value, self->min_qp_i);
615       break;
616     case PROP_MAX_QP_I:
617       g_value_set_int (value, self->max_qp_i);
618       break;
619     case PROP_MIN_QP_P:
620       g_value_set_int (value, self->min_qp_p);
621       break;
622     case PROP_MAX_QP_P:
623       g_value_set_int (value, self->max_qp_p);
624       break;
625     case PROP_QP_I:
626       g_value_set_uint (value, self->qp_i);
627       break;
628     case PROP_QP_P:
629       g_value_set_uint (value, self->qp_p);
630       break;
631     case PROP_REF_FRAMES:
632       g_value_set_uint (value, self->ref_frames);
633       break;
634     default:
635       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
636       break;
637   }
638 }
639
640 static gboolean
641 gst_amf_av1_enc_set_format (GstAmfEncoder * encoder,
642     GstVideoCodecState * state, gpointer component)
643 {
644   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
645   AMFComponent *comp = (AMFComponent *) component;
646   GstVideoInfo *info = &state->info;
647   AMF_RESULT result;
648   AMFRate framerate;
649   amf_int64 int64_val = 0;
650   AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM rc_mode;
651
652   g_mutex_lock (&self->prop_lock);
653   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_FRAMESIZE,
654       AMFConstructSize (info->width, info->height));
655   if (result != AMF_OK) {
656     GST_ERROR_OBJECT (self, "Failed to set frame size, result %"
657         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
658     goto error;
659   }
660
661   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_USAGE,
662       (amf_int64) self->usage);
663   if (result != AMF_OK) {
664     GST_ERROR_OBJECT (self, "Failed to set usage, result %"
665         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
666     goto error;
667   }
668
669   if (self->preset > AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_UNKNOWN) {
670     result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET,
671         (amf_int64) self->preset);
672     if (result != AMF_OK) {
673       GST_ERROR_OBJECT (self, "Failed to set quality preset, result %"
674           GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
675       goto error;
676     }
677   }
678
679   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PROFILE,
680       (amf_int64) AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN);
681   if (result != AMF_OK) {
682     GST_ERROR_OBJECT (self, "Failed to set profile, result %"
683         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
684     goto error;
685   }
686
687   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE,
688       (amf_int64) AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS);
689   if (result != AMF_OK) {
690     GST_ERROR_OBJECT (self, "Failed to set alignment mode, result %"
691         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
692     goto error;
693   }
694
695   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_MAX_NUM_REFRAMES,
696       (amf_int64) self->ref_frames);
697   if (result != AMF_OK) {
698     GST_ERROR_OBJECT (self, "Failed to set ref-frames, result %"
699         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
700     goto error;
701   }
702
703   result = comp->Init (AMF_SURFACE_NV12, info->width, info->height);
704   if (result != AMF_OK) {
705     GST_ERROR_OBJECT (self, "Failed to init component, result %"
706         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
707     goto error;
708   }
709
710   if (self->rate_control != AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN) {
711     result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD,
712         (amf_int64) self->rate_control);
713     if (result != AMF_OK) {
714       GST_ERROR_OBJECT (self, "Failed to set rate-control, result %"
715           GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
716       goto error;
717     }
718   }
719
720   result = comp->GetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD,
721       &int64_val);
722   if (result != AMF_OK) {
723     GST_ERROR_OBJECT (self, "Failed to get rate-control method, result %"
724         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
725     goto error;
726   }
727
728   rc_mode = (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM) int64_val;
729   if (self->min_qp_i >= 0) {
730     comp->SetProperty (AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTRA,
731         (amf_int64) self->min_qp_i);
732   }
733   if (self->max_qp_i >= 0) {
734     comp->SetProperty (AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTRA,
735         (amf_int64) self->max_qp_i);
736   }
737   if (self->min_qp_p >= 0) {
738     comp->SetProperty (AMF_VIDEO_ENCODER_AV1_MIN_Q_INDEX_INTER,
739         (amf_int64) self->min_qp_p);
740   }
741   if (self->max_qp_p >= 0) {
742     comp->SetProperty (AMF_VIDEO_ENCODER_AV1_MAX_Q_INDEX_INTER,
743         (amf_int64) self->max_qp_p);
744   }
745
746   comp->SetProperty (AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTRA,
747       (amf_int64) self->qp_i);
748   comp->SetProperty (AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER,
749       (amf_int64) self->qp_p);
750
751   switch (rc_mode) {
752     case AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR:
753       if (self->bitrate > 0) {
754         comp->SetProperty (AMF_VIDEO_ENCODER_AV1_TARGET_BITRATE,
755             (amf_int64) self->bitrate * 1000);
756         comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE,
757             (amf_int64) self->bitrate * 1000);
758       }
759       break;
760     case AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR:
761     case AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR:
762       if (self->bitrate > 0) {
763         comp->SetProperty (AMF_VIDEO_ENCODER_AV1_TARGET_BITRATE,
764             (amf_int64) self->bitrate * 1000);
765       }
766       if (self->max_bitrate > 0) {
767         comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE,
768             (amf_int64) self->max_bitrate * 1000);
769       }
770       break;
771     default:
772       break;
773   }
774
775   /* Disable frame skip for now, need investigation the behavior */
776   result =
777       comp->SetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME,
778       (amf_bool) false);
779   if (result != AMF_OK) {
780     GST_ERROR_OBJECT (self, "Failed to disable skip frame, result %"
781         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
782     goto error;
783   }
784
785   if (info->fps_n > 0 && info->fps_d) {
786     framerate = AMFConstructRate (info->fps_n, info->fps_d);
787   } else {
788     framerate = AMFConstructRate (25, 1);
789   }
790
791   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_FRAMERATE, framerate);
792   if (result != AMF_OK) {
793     GST_ERROR_OBJECT (self, "Failed to set frame rate, result %"
794         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
795     goto error;
796   }
797
798   result = comp->SetProperty (AMF_VIDEO_ENCODER_AV1_GOP_SIZE,
799       (amf_int64) self->gop_size);
800   if (result != AMF_OK) {
801     GST_ERROR_OBJECT (self, "Failed to set gop-size, result %"
802         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
803     goto error;
804   }
805
806   self->property_updated = FALSE;
807   g_mutex_unlock (&self->prop_lock);
808
809   return TRUE;
810
811 error:
812   g_mutex_unlock (&self->prop_lock);
813
814   return FALSE;
815 }
816
817 static gboolean
818 gst_amf_av1_enc_set_output_state (GstAmfEncoder * encoder,
819     GstVideoCodecState * state, gpointer component)
820 {
821   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
822   GstVideoCodecState *output_state;
823   GstCaps *caps;
824   GstTagList *tags;
825
826   caps = gst_caps_from_string ("video/x-av1, profile = (string) main, "
827       "alignment = (string) tu");
828   output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
829       caps, state);
830
831   GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
832   gst_video_codec_state_unref (output_state);
833
834   tags = gst_tag_list_new_empty ();
835   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
836       "amfav1enc", nullptr);
837
838   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
839       tags, GST_TAG_MERGE_REPLACE);
840   gst_tag_list_unref (tags);
841
842   return TRUE;
843 }
844
845 static gboolean
846 gst_amf_av1_enc_set_surface_prop (GstAmfEncoder * encoder,
847     GstVideoCodecFrame * frame, gpointer surface)
848 {
849   AMFSurface *surf = (AMFSurface *) surface;
850   AMF_RESULT result;
851
852   if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
853     amf_int64 type = (amf_int64) AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_NONE;
854     result = surf->SetProperty (AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, type);
855     if (result != AMF_OK) {
856       GST_WARNING_OBJECT (encoder, "Failed to set force frame type, result %"
857           GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
858     }
859   }
860   return TRUE;
861 }
862
863 static GstBuffer *
864 gst_amf_av1_enc_create_output_buffer (GstAmfEncoder * encoder,
865     gpointer data, gboolean * sync_point)
866 {
867   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
868   AMFBuffer *amf_buf = (AMFBuffer *) data;
869   GstBuffer *buf;
870   guint8 *data_ptr;
871   gsize data_size;
872   amf_int64 output_type = 0;
873   AMF_RESULT result;
874
875   data_ptr = (guint8 *) amf_buf->GetNative ();
876   data_size = amf_buf->GetSize ();
877
878   if (!data_ptr || data_size == 0) {
879     GST_WARNING_OBJECT (self, "Empty buffer");
880     return nullptr;
881   }
882
883   buf = gst_buffer_new_memdup (data_ptr, data_size);
884
885   result = amf_buf->GetProperty (AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE,
886       &output_type);
887   if (result == AMF_OK &&
888       output_type == (amf_int64) AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY) {
889     *sync_point = TRUE;
890   }
891
892   return buf;
893 }
894
895 static gboolean
896 gst_amf_av1_enc_check_reconfigure (GstAmfEncoder * encoder)
897 {
898   GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
899   gboolean ret;
900
901   g_mutex_lock (&self->prop_lock);
902   ret = self->property_updated;
903   g_mutex_unlock (&self->prop_lock);
904
905   return ret;
906 }
907
908 static GstAmfAv1EncClassData *
909 gst_amf_av1_enc_create_class_data (GstD3D11Device * device, AMFComponent * comp)
910 {
911   AMF_RESULT result;
912   GstAmfAv1EncDeviceCaps dev_caps = { 0, };
913   std::string sink_caps_str;
914   std::string src_caps_str;
915   std::vector < std::string > profiles;
916   std::string resolution_str;
917   GstAmfAv1EncClassData *cdata;
918   AMFCapsPtr amf_caps;
919   AMFIOCapsPtr in_iocaps;
920   AMFIOCapsPtr out_iocaps;
921   amf_int32 in_min_width = 0, in_max_width = 0;
922   amf_int32 in_min_height = 0, in_max_height = 0;
923   amf_int32 out_min_width = 0, out_max_width = 0;
924   amf_int32 out_min_height = 0, out_max_height = 0;
925   amf_int32 num_val;
926   gboolean have_nv12 = FALSE;
927   gboolean d3d11_supported = FALSE;
928   gint min_width, max_width, min_height, max_height;
929   GstCaps *sink_caps;
930   GstCaps *system_caps;
931
932   result = comp->GetCaps (&amf_caps);
933   if (result != AMF_OK) {
934     GST_WARNING_OBJECT (device, "Unable to get caps");
935     return nullptr;
936   }
937
938   result = amf_caps->GetInputCaps (&in_iocaps);
939   if (result != AMF_OK) {
940     GST_WARNING_OBJECT (device, "Unable to get input io caps");
941     return nullptr;
942   }
943
944   in_iocaps->GetWidthRange (&in_min_width, &in_max_width);
945   in_iocaps->GetHeightRange (&in_min_height, &in_max_height);
946   dev_caps.valign = in_iocaps->GetVertAlign ();
947
948   GST_INFO_OBJECT (device, "Input width: [%d, %d], height: [%d, %d], "
949       "valign: %d", in_min_width, in_max_width, in_min_height, in_max_height,
950       dev_caps.valign);
951
952   num_val = in_iocaps->GetNumOfFormats ();
953   GST_LOG_OBJECT (device, "Input format count: %d", num_val);
954   for (amf_int32 i = 0; i < num_val; i++) {
955     AMF_SURFACE_FORMAT format;
956     amf_bool native;
957
958     result = in_iocaps->GetFormatAt (i, &format, &native);
959     if (result != AMF_OK)
960       continue;
961
962     GST_INFO_OBJECT (device, "Format %d supported, native %d", format, native);
963     if (format == AMF_SURFACE_NV12)
964       have_nv12 = TRUE;
965   }
966
967   if (!have_nv12) {
968     GST_WARNING_OBJECT (device, "NV12 is not supported");
969     return nullptr;
970   }
971
972   num_val = in_iocaps->GetNumOfMemoryTypes ();
973   GST_LOG_OBJECT (device, "Input memory type count: %d", num_val);
974   for (amf_int32 i = 0; i < num_val; i++) {
975     AMF_MEMORY_TYPE type;
976     amf_bool native;
977
978     result = in_iocaps->GetMemoryTypeAt (i, &type, &native);
979     if (result != AMF_OK)
980       continue;
981
982     GST_INFO_OBJECT (device,
983         "MemoryType %d supported, native %d", type, native);
984     if (type == AMF_MEMORY_DX11)
985       d3d11_supported = TRUE;
986   }
987
988   if (!d3d11_supported) {
989     GST_WARNING_OBJECT (device, "D3D11 is not supported");
990     return nullptr;
991   }
992
993   result = amf_caps->GetOutputCaps (&out_iocaps);
994   if (result != AMF_OK) {
995     GST_WARNING_OBJECT (device, "Unable to get input io caps");
996     return nullptr;
997   }
998
999   out_iocaps->GetWidthRange (&out_min_width, &out_max_width);
1000   out_iocaps->GetHeightRange (&out_min_height, &out_max_height);
1001
1002   GST_INFO_OBJECT (device, "Output width: [%d, %d], height: [%d, %d]",
1003       in_min_width, in_max_width, in_min_height, in_max_height);
1004
1005 #define QUERY_CAPS_PROP(prop,val) G_STMT_START { \
1006   amf_int64 _val = 0; \
1007   result = amf_caps->GetProperty (prop, &_val); \
1008   if (result == AMF_OK) { \
1009     GST_INFO_OBJECT (device, G_STRINGIFY (val) ": %" G_GINT64_FORMAT, _val); \
1010     dev_caps.val = _val; \
1011   } \
1012 } G_STMT_END
1013   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_NUM_OF_HW_INSTANCES,
1014       num_of_hw_instances);
1015   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_MAX_THROUGHPUT, max_throughput);
1016   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_REQUESTED_THROUGHPUT,
1017       requested_throughput);
1018   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_COLOR_CONVERSION,
1019       color_conversion);
1020   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_PRE_ANALYSIS, pre_analysis);
1021   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_MAX_BITRATE, max_bitrate);
1022   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_MAX_PROFILE, max_profile);
1023   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_MAX_LEVEL, max_level);
1024   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_TEMPORAL_LAYERS,
1025       max_num_temporal_layers);
1026   QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_AV1_CAP_MAX_NUM_LTR_FRAMES,
1027       max_num_ltr_frames);
1028
1029 #undef QUERY_CAPS_PROP
1030
1031 #define QUERY_DEFAULT_PROP(prop,val,default_val) G_STMT_START { \
1032   const AMFPropertyInfo *pinfo = nullptr; \
1033   result = comp->GetPropertyInfo (prop, &pinfo); \
1034   if (result == AMF_OK && pinfo) { \
1035     dev_caps.val = AMFVariantGetInt64 (&pinfo->defaultValue); \
1036     GST_INFO_OBJECT (device, G_STRINGIFY (val) ": %" G_GINT64_FORMAT, \
1037         dev_caps.val); \
1038   } else { \
1039     dev_caps.val = default_val; \
1040   } \
1041 } G_STMT_END
1042
1043   QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTRA, default_qp_i, 26);
1044   QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_AV1_Q_INDEX_INTER, default_qp_p, 26);
1045 #undef QUERY_DEFAULT_PROP
1046
1047   {
1048     const AMFPropertyInfo *pinfo = nullptr;
1049     result = comp->GetPropertyInfo (AMF_VIDEO_ENCODER_AV1_GOP_SIZE, &pinfo);
1050     if (result == AMF_OK && pinfo) {
1051       dev_caps.default_gop_size = AMFVariantGetInt64 (&pinfo->defaultValue);
1052       dev_caps.min_gop_size = AMFVariantGetInt64 (&pinfo->minValue);
1053       dev_caps.max_gop_size = AMFVariantGetInt64 (&pinfo->maxValue);
1054       GST_INFO_OBJECT (device, "gop-size: default %d, min %d, max %d",
1055           (guint) dev_caps.default_gop_size,
1056           (guint) dev_caps.min_gop_size, (guint) dev_caps.max_gop_size);
1057     } else {
1058       dev_caps.default_gop_size = 30;
1059       dev_caps.min_gop_size = 0;
1060       dev_caps.max_gop_size = G_MAXINT;
1061     }
1062   }
1063
1064   min_width = MAX (in_min_width, 1);
1065   max_width = in_max_width;
1066   if (max_width == 0) {
1067     GST_WARNING_OBJECT (device, "Unknown max width, assuming 4096");
1068     max_width = 4096;
1069   }
1070
1071   min_height = MAX (in_min_height, 1);
1072   max_height = in_max_height;
1073   if (max_height == 0) {
1074     GST_WARNING_OBJECT (device, "Unknown max height, assuming 4096");
1075     max_height = 4096;
1076   }
1077
1078   resolution_str = "width = (int) [ " + std::to_string (min_width)
1079       + ", " + std::to_string (max_width) + " ]";
1080   resolution_str += ", height = (int) [ " + std::to_string (min_height)
1081       + ", " + std::to_string (max_height) + " ]";
1082
1083   sink_caps_str = "video/x-raw, format = (string) NV12, " + resolution_str;
1084   src_caps_str = "video/x-av1, " + resolution_str + ", profile = (string) main, "
1085       "alignment = (string) tu";
1086
1087   system_caps = gst_caps_from_string (sink_caps_str.c_str ());
1088   sink_caps = gst_caps_copy (system_caps);
1089   gst_caps_set_features (sink_caps, 0,
1090       gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
1091   gst_caps_append (sink_caps, system_caps);
1092
1093   cdata = g_new0 (GstAmfAv1EncClassData, 1);
1094   cdata->sink_caps = sink_caps;
1095   cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
1096   cdata->dev_caps = dev_caps;
1097   g_object_get (device, "adapter-luid", &cdata->adapter_luid, nullptr);
1098
1099   GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1100       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1101   GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
1102       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1103
1104   GST_DEBUG_OBJECT (device, "Sink caps %" GST_PTR_FORMAT, cdata->sink_caps);
1105   GST_DEBUG_OBJECT (device, "Src caps %" GST_PTR_FORMAT, cdata->src_caps);
1106
1107   return cdata;
1108 }
1109
1110 void
1111 gst_amf_av1_enc_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
1112     gpointer context, guint rank)
1113 {
1114   GstAmfAv1EncClassData *cdata;
1115   AMFContext *amf_context = (AMFContext *) context;
1116   AMFFactory *factory = (AMFFactory *) gst_amf_get_factory ();
1117   AMFComponentPtr comp;
1118   AMF_RESULT result;
1119
1120   GST_DEBUG_CATEGORY_INIT (gst_amf_av1_enc_debug, "amfav1enc", 0, "amfav1enc");
1121
1122   result = factory->CreateComponent (amf_context, AMFVideoEncoder_AV1, &comp);
1123   if (result != AMF_OK) {
1124     GST_WARNING_OBJECT (device, "Failed to create component, result %"
1125         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1126     return;
1127   }
1128
1129   cdata = gst_amf_av1_enc_create_class_data (device, comp.GetPtr ());
1130   if (!cdata)
1131     return;
1132
1133   GType type;
1134   gchar *type_name;
1135   gchar *feature_name;
1136   GTypeInfo type_info = {
1137     sizeof (GstAmfAv1EncClass),
1138     nullptr,
1139     nullptr,
1140     (GClassInitFunc) gst_amf_av1_enc_class_init,
1141     nullptr,
1142     cdata,
1143     sizeof (GstAmfAv1Enc),
1144     0,
1145     (GInstanceInitFunc) gst_amf_av1_enc_init,
1146   };
1147
1148   type_name = g_strdup ("GstAmfAv1Enc");
1149   feature_name = g_strdup ("amfav1enc");
1150
1151   gint index = 0;
1152   while (g_type_from_name (type_name)) {
1153     index++;
1154     g_free (type_name);
1155     g_free (feature_name);
1156     type_name = g_strdup_printf ("GstAmfAv1Device%dEnc", index);
1157     feature_name = g_strdup_printf ("amfav1device%denc", index);
1158   }
1159
1160   type = g_type_register_static (GST_TYPE_AMF_ENCODER, type_name,
1161       &type_info, (GTypeFlags) 0);
1162
1163   if (rank > 0 && index != 0)
1164     rank--;
1165
1166   if (index != 0)
1167     gst_element_type_set_skip_documentation (type);
1168
1169   if (!gst_element_register (plugin, feature_name, rank, type))
1170     GST_WARNING ("Failed to register plugin '%s'", type_name);
1171
1172   g_free (type_name);
1173   g_free (feature_name);
1174 }