2 * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
3 * Copyright (C) 2022 Evgeny Pavlov <lucenticus@gmail.com>
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.
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.
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.
22 * SECTION:element-amfav1enc
24 * @short_description: An AMD AMF API based AV1 video encoder
26 * amfav1enc element encodes raw video stream into compressed AV1 bitstream
29 * ## Example launch line
31 * gst-launch-1.0 videotestsrc num-buffers=100 ! amfav1enc ! av1parse ! webmmux ! filesink location=encoded.webm
42 #include "gstamfav1enc.h"
43 #include <components/Component.h>
44 #include <components/VideoEncoderAV1.h>
45 #include <core/Factory.h>
52 GST_DEBUG_CATEGORY_STATIC (gst_amf_av1_enc_debug);
53 #define GST_CAT_DEFAULT gst_amf_av1_enc_debug
55 static GTypeClass *parent_class = nullptr;
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;
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;
75 } GstAmfAv1EncDeviceCaps;
84 #define GST_TYPE_AMF_AV1_ENC_USAGE (gst_amf_av1_enc_usage_get_type ())
86 gst_amf_av1_enc_usage_get_type (void)
88 static GType usage_type = 0;
89 static const GEnumValue usages[] = {
91 * GstAmfAv1EncUsage::transcoding:
95 {AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING, "Transcoding", "transcoding"},
98 * GstAmfAv1EncUsage::low-latency:
102 {AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY, "Low Latency", "low-latency"},
103 {0, nullptr, nullptr}
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);
115 * GstAmfAv1EncRateControl:
117 * Rate control methods
121 #define GST_TYPE_AMF_AV1_ENC_RATE_CONTROL (gst_amf_av1_enc_rate_control_get_type ())
123 gst_amf_av1_enc_rate_control_get_type (void)
125 static GType rate_control_type = 0;
126 static const GEnumValue rate_controls[] = {
128 * GstAmfAv1EncRateControl::default:
130 * Default rate control method depending on usage
132 {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_UNKNOWN,
133 "Default, depends on Usage", "default"},
136 * GstAmfAv1EncRateControl::cqp:
140 {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP, "Constant QP",
144 * GstAmfAv1EncRateControl::lcvbr:
146 * Latency Constrained Variable Bitrate
148 {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
149 "Latency Constrained VBR", "lcvbr"},
152 * GstAmfAv1EncRateControl::vbr:
154 * Peak Constrained Variable Bitrate
156 {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
157 "Peak Constrained VBR", "vbr"},
160 * GstAmfAv1EncRateControl::cbr:
164 {AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR, "Constant Bitrate", "cbr"},
165 {0, nullptr, nullptr}
168 if (g_once_init_enter (&rate_control_type)) {
170 g_enum_register_static ("GstAmfAv1EncRateControl", rate_controls);
171 g_once_init_leave (&rate_control_type, type);
174 return rate_control_type;
178 * GstAmfAv1EncPreset:
180 * Encoding quality presets
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 ())
187 gst_amf_av1_enc_preset_get_type (void)
189 static GType preset_type = 0;
190 static const GEnumValue presets[] = {
192 * GstAmfAv1EncRateControl::default:
194 * Default preset depends on usage
196 {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_UNKNOWN, "Default, depends on USAGE",
200 * GstAmfAv1EncRateControl::high-quality:
202 * High quality oriented preset
204 {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY, "High quality",
208 * GstAmfAv1EncRateControl::quality:
210 * Quality oriented preset
212 {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY, "Quality", "quality"},
216 * GstAmfAv1EncRateControl::balanced:
220 {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED, "Balanced", "balanced"},
223 * GstAmfAv1EncRateControl::speed:
225 * Speed oriented preset
227 {AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED, "Speed", "speed"},
228 {0, nullptr, nullptr}
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);
246 GstAmfAv1EncDeviceCaps dev_caps;
247 } GstAmfAv1EncClassData;
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
276 #define DOC_SINK_CAPS_COMM \
277 "format = (string) NV12, " \
278 "width = (int) [ 128, 4096 ], height = (int) [ 128, 4096 ]"
280 #define DOC_SINK_CAPS \
281 "video/x-raw(memory:D3D11Memory), " DOC_SINK_CAPS_COMM "; " \
282 "video/x-raw, " DOC_SINK_CAPS_COMM
284 #define DOC_SRC_CAPS \
285 "video/x-av1, width = (int) [ 128, 4096 ], height = (int) [ 128, 4096 ], " \
286 "profile = (string) main, alignment= (string) tu"
288 typedef struct _GstAmfAv1Enc
290 GstAmfEncoder parent;
293 gboolean property_updated;
309 typedef struct _GstAmfAv1EncClass
311 GstAmfEncoderClass parent_class;
312 GstAmfAv1EncDeviceCaps dev_caps;
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))
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);
337 gst_amf_av1_enc_class_init (GstAmfAv1EncClass * klass, gpointer data)
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;
349 parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
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;
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));
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>");
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);
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);
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);
443 klass->dev_caps = cdata->dev_caps;
444 klass->adapter_luid = cdata->adapter_luid;
446 gst_caps_unref (cdata->sink_caps);
447 gst_caps_unref (cdata->src_caps);
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);
459 gst_amf_av1_enc_init (GstAmfAv1Enc * self)
461 GstAmfAv1EncClass *klass = GST_AMF_AV1_ENC_GET_CLASS (self);
462 GstAmfAv1EncDeviceCaps *dev_caps = &klass->dev_caps;
464 gst_amf_encoder_set_subclass_data (GST_AMF_ENCODER (self),
465 klass->adapter_luid, AMFVideoEncoder_AV1);
467 g_mutex_init (&self->prop_lock);
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;
485 gst_amf_av1_enc_finalize (GObject * object)
487 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (object);
489 g_mutex_clear (&self->prop_lock);
491 G_OBJECT_CLASS (parent_class)->finalize (object);
495 update_int (GstAmfAv1Enc * self, gint * old_val, const GValue * new_val)
497 gint val = g_value_get_int (new_val);
503 self->property_updated = TRUE;
507 update_uint (GstAmfAv1Enc * self, guint * old_val, const GValue * new_val)
509 guint val = g_value_get_uint (new_val);
515 self->property_updated = TRUE;
519 update_enum (GstAmfAv1Enc * self, gint * old_val, const GValue * new_val)
521 gint val = g_value_get_enum (new_val);
527 self->property_updated = TRUE;
531 gst_amf_av1_enc_set_property (GObject * object, guint prop_id,
532 const GValue * value, GParamSpec * pspec)
534 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (object);
536 g_mutex_lock (&self->prop_lock);
539 update_enum (self, &self->usage, value);
541 case PROP_RATE_CONTROL:
542 update_enum (self, &self->rate_control, value);
545 update_enum (self, &self->preset, value);
548 update_uint (self, &self->bitrate, value);
550 case PROP_MAX_BITRATE:
551 update_uint (self, &self->max_bitrate, value);
554 update_uint (self, &self->gop_size, value);
557 update_int (self, &self->min_qp_i, value);
560 update_int (self, &self->max_qp_i, value);
563 update_int (self, &self->min_qp_p, value);
566 update_int (self, &self->max_qp_p, value);
569 update_uint (self, &self->qp_i, value);
572 update_uint (self, &self->qp_p, value);
574 case PROP_REF_FRAMES:
575 update_uint (self, &self->ref_frames, value);
578 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
581 g_mutex_unlock (&self->prop_lock);
585 gst_amf_av1_enc_get_property (GObject * object, guint prop_id,
586 GValue * value, GParamSpec * pspec)
588 GstAmfAv1EncClass *klass = GST_AMF_AV1_ENC_GET_CLASS (object);
589 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (object);
592 case PROP_ADAPTER_LUID:
593 g_value_set_int64 (value, klass->adapter_luid);
596 g_value_set_enum (value, self->usage);
598 case PROP_RATE_CONTROL:
599 g_value_set_enum (value, self->rate_control);
602 g_value_set_enum (value, self->preset);
605 g_value_set_uint (value, self->bitrate);
607 case PROP_MAX_BITRATE:
608 g_value_set_uint (value, self->max_bitrate);
611 g_value_set_uint (value, self->gop_size);
614 g_value_set_int (value, self->min_qp_i);
617 g_value_set_int (value, self->max_qp_i);
620 g_value_set_int (value, self->min_qp_p);
623 g_value_set_int (value, self->max_qp_p);
626 g_value_set_uint (value, self->qp_i);
629 g_value_set_uint (value, self->qp_p);
631 case PROP_REF_FRAMES:
632 g_value_set_uint (value, self->ref_frames);
635 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
641 gst_amf_av1_enc_set_format (GstAmfEncoder * encoder,
642 GstVideoCodecState * state, gpointer component)
644 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
645 AMFComponent *comp = (AMFComponent *) component;
646 GstVideoInfo *info = &state->info;
649 amf_int64 int64_val = 0;
650 AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_ENUM rc_mode;
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));
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));
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));
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));
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));
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));
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));
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));
720 result = comp->GetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD,
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));
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);
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);
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);
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);
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);
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);
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);
766 if (self->max_bitrate > 0) {
767 comp->SetProperty (AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE,
768 (amf_int64) self->max_bitrate * 1000);
775 /* Disable frame skip for now, need investigation the behavior */
777 comp->SetProperty (AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME,
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));
785 if (info->fps_n > 0 && info->fps_d) {
786 framerate = AMFConstructRate (info->fps_n, info->fps_d);
788 framerate = AMFConstructRate (25, 1);
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));
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));
806 self->property_updated = FALSE;
807 g_mutex_unlock (&self->prop_lock);
812 g_mutex_unlock (&self->prop_lock);
818 gst_amf_av1_enc_set_output_state (GstAmfEncoder * encoder,
819 GstVideoCodecState * state, gpointer component)
821 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
822 GstVideoCodecState *output_state;
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),
831 GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
832 gst_video_codec_state_unref (output_state);
834 tags = gst_tag_list_new_empty ();
835 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
836 "amfav1enc", nullptr);
838 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
839 tags, GST_TAG_MERGE_REPLACE);
840 gst_tag_list_unref (tags);
846 gst_amf_av1_enc_set_surface_prop (GstAmfEncoder * encoder,
847 GstVideoCodecFrame * frame, gpointer surface)
849 AMFSurface *surf = (AMFSurface *) surface;
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));
864 gst_amf_av1_enc_create_output_buffer (GstAmfEncoder * encoder,
865 gpointer data, gboolean * sync_point)
867 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
868 AMFBuffer *amf_buf = (AMFBuffer *) data;
872 amf_int64 output_type = 0;
875 data_ptr = (guint8 *) amf_buf->GetNative ();
876 data_size = amf_buf->GetSize ();
878 if (!data_ptr || data_size == 0) {
879 GST_WARNING_OBJECT (self, "Empty buffer");
883 buf = gst_buffer_new_memdup (data_ptr, data_size);
885 result = amf_buf->GetProperty (AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE,
887 if (result == AMF_OK &&
888 output_type == (amf_int64) AMF_VIDEO_ENCODER_AV1_OUTPUT_FRAME_TYPE_KEY) {
896 gst_amf_av1_enc_check_reconfigure (GstAmfEncoder * encoder)
898 GstAmfAv1Enc *self = GST_AMF_AV1_ENC (encoder);
901 g_mutex_lock (&self->prop_lock);
902 ret = self->property_updated;
903 g_mutex_unlock (&self->prop_lock);
908 static GstAmfAv1EncClassData *
909 gst_amf_av1_enc_create_class_data (GstD3D11Device * device, AMFComponent * comp)
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;
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;
926 gboolean have_nv12 = FALSE;
927 gboolean d3d11_supported = FALSE;
928 gint min_width, max_width, min_height, max_height;
930 GstCaps *system_caps;
932 result = comp->GetCaps (&amf_caps);
933 if (result != AMF_OK) {
934 GST_WARNING_OBJECT (device, "Unable to get caps");
938 result = amf_caps->GetInputCaps (&in_iocaps);
939 if (result != AMF_OK) {
940 GST_WARNING_OBJECT (device, "Unable to get input io caps");
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 ();
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,
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;
958 result = in_iocaps->GetFormatAt (i, &format, &native);
959 if (result != AMF_OK)
962 GST_INFO_OBJECT (device, "Format %d supported, native %d", format, native);
963 if (format == AMF_SURFACE_NV12)
968 GST_WARNING_OBJECT (device, "NV12 is not supported");
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;
978 result = in_iocaps->GetMemoryTypeAt (i, &type, &native);
979 if (result != AMF_OK)
982 GST_INFO_OBJECT (device,
983 "MemoryType %d supported, native %d", type, native);
984 if (type == AMF_MEMORY_DX11)
985 d3d11_supported = TRUE;
988 if (!d3d11_supported) {
989 GST_WARNING_OBJECT (device, "D3D11 is not supported");
993 result = amf_caps->GetOutputCaps (&out_iocaps);
994 if (result != AMF_OK) {
995 GST_WARNING_OBJECT (device, "Unable to get input io caps");
999 out_iocaps->GetWidthRange (&out_min_width, &out_max_width);
1000 out_iocaps->GetHeightRange (&out_min_height, &out_max_height);
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);
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; \
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,
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);
1029 #undef QUERY_CAPS_PROP
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, \
1039 dev_caps.val = default_val; \
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
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);
1058 dev_caps.default_gop_size = 30;
1059 dev_caps.min_gop_size = 0;
1060 dev_caps.max_gop_size = G_MAXINT;
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");
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");
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) + " ]";
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";
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);
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);
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);
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);
1111 gst_amf_av1_enc_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
1112 gpointer context, guint rank)
1114 GstAmfAv1EncClassData *cdata;
1115 AMFContext *amf_context = (AMFContext *) context;
1116 AMFFactory *factory = (AMFFactory *) gst_amf_get_factory ();
1117 AMFComponentPtr comp;
1120 GST_DEBUG_CATEGORY_INIT (gst_amf_av1_enc_debug, "amfav1enc", 0, "amfav1enc");
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));
1129 cdata = gst_amf_av1_enc_create_class_data (device, comp.GetPtr ());
1135 gchar *feature_name;
1136 GTypeInfo type_info = {
1137 sizeof (GstAmfAv1EncClass),
1140 (GClassInitFunc) gst_amf_av1_enc_class_init,
1143 sizeof (GstAmfAv1Enc),
1145 (GInstanceInitFunc) gst_amf_av1_enc_init,
1148 type_name = g_strdup ("GstAmfAv1Enc");
1149 feature_name = g_strdup ("amfav1enc");
1152 while (g_type_from_name (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);
1160 type = g_type_register_static (GST_TYPE_AMF_ENCODER, type_name,
1161 &type_info, (GTypeFlags) 0);
1163 if (rank > 0 && index != 0)
1167 gst_element_type_set_skip_documentation (type);
1169 if (!gst_element_register (plugin, feature_name, rank, type))
1170 GST_WARNING ("Failed to register plugin '%s'", type_name);
1173 g_free (feature_name);