2 * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * SECTION:element-amfh264enc
23 * @short_description: An AMD AMF API based H.264 video encoder
25 * amfh264enc element encodes raw video stream into compressed H.264 bitstream
28 * ## Example launch line
30 * gst-launch-1.0 videotestsrc num-buffers=100 ! amfh264enc ! h264parse ! mp4mux ! filesink location=encoded.mp4
41 #include "gstamfh264enc.h"
42 #include <components/Component.h>
43 #include <components/VideoEncoderVCE.h>
44 #include <core/Factory.h>
45 #include <gst/codecparsers/gsth264parser.h>
46 #include <gst/pbutils/codec-utils.h>
53 GST_DEBUG_CATEGORY_STATIC (gst_amf_h264_enc_debug);
54 #define GST_CAT_DEFAULT gst_amf_h264_enc_debug
56 static GTypeClass *parent_class = nullptr;
60 amf_int64 max_bitrate;
61 amf_int64 num_of_streams;
62 amf_int64 max_profile;
65 amf_int64 min_ref_frames;
66 amf_int64 max_ref_frames;
67 amf_int64 max_temporal_layers;
68 amf_int64 fixed_slice_mode;
69 amf_int64 num_of_hw_instances;
70 amf_int64 color_conversion;
71 amf_int64 pre_analysis;
73 amf_int64 max_throughput;
74 amf_int64 query_timeout_support;
75 amf_int64 default_qp_i;
76 amf_int64 default_qp_p;
77 amf_int64 default_qp_b;
78 gboolean interlace_supported;
80 } GstAmfH264EncDeviceCaps;
89 #define GST_TYPE_AMF_H264_ENC_USAGE (gst_amf_h264_enc_usage_get_type ())
91 gst_amf_h264_enc_usage_get_type (void)
93 static GType usage_type = 0;
94 static const GEnumValue usages[] = {
96 * GstAmfH264EncUsage::transcoding:
100 {AMF_VIDEO_ENCODER_USAGE_TRANSCODING, "Transcoding", "transcoding"},
103 * GstAmfH264EncUsage::ultra-low-latency:
105 * Ultra Low Latency usage
107 {AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY, "Ultra Low Latency",
108 "ultra-low-latency"},
111 * GstAmfH264EncUsage::low-latency:
115 {AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY, "Low Latency", "low-latency"},
118 * GstAmfH264EncUsage::webcam:
122 {AMF_VIDEO_ENCODER_USAGE_WEBCAM, "Webcam", "webcam"},
123 {0, nullptr, nullptr}
126 if (g_once_init_enter (&usage_type)) {
127 GType type = g_enum_register_static ("GstAmfH264EncUsage", usages);
128 g_once_init_leave (&usage_type, type);
135 * GstAmfH264EncRateControl:
137 * Rate control methods
141 #define GST_TYPE_AMF_H264_ENC_RATE_CONTROL (gst_amf_h264_enc_rate_control_get_type ())
143 gst_amf_h264_enc_rate_control_get_type (void)
145 static GType rate_control_type = 0;
146 static const GEnumValue rate_controls[] = {
148 * GstAmfH264EncRateControl::default:
150 * Default rate control method depending on usage
152 {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN, "Default, depends on Usage",
156 * GstAmfH264EncRateControl::cqp:
160 {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP, "Constant QP", "cqp"},
163 * GstAmfH264EncRateControl::cbr:
167 {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR, "Constant Bitrate", "cbr"},
170 * GstAmfH264EncRateControl::vbr:
172 * Peak Constrained Variable Bitrate
174 {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
175 "Peak Constrained VBR", "vbr"},
178 * GstAmfH264EncRateControl::lcvbr:
180 * Latency Constrained Variable Bitrate
182 {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
183 "Latency Constrained VBR", "lcvbr"},
184 {0, nullptr, nullptr}
187 if (g_once_init_enter (&rate_control_type)) {
189 g_enum_register_static ("GstAmfH264EncRateControl", rate_controls);
190 g_once_init_leave (&rate_control_type, type);
193 return rate_control_type;
197 * GstAmfH264EncPreset:
199 * Encoding quality presets
203 #define AMF_VIDEO_ENCODER_QUALITY_PRESET_UNKNOWN -1
204 #define GST_TYPE_AMF_H264_ENC_PRESET (gst_amf_h264_enc_preset_get_type ())
206 gst_amf_h264_enc_preset_get_type (void)
208 static GType preset_type = 0;
209 static const GEnumValue presets[] = {
211 * GstAmfH264EncRateControl::default:
213 * Default preset depends on usage
215 {AMF_VIDEO_ENCODER_QUALITY_PRESET_UNKNOWN, "Default, depends on USAGE",
219 * GstAmfH264EncRateControl::balanced:
223 {AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, "Balanced", "balanced"},
226 * GstAmfH264EncRateControl::speed:
228 * Speed oriented preset
230 {AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED, "Speed", "speed"},
233 * GstAmfH264EncRateControl::quality:
235 * Quality oriented preset
237 {AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, "Quality", "quality"},
238 {0, nullptr, nullptr}
241 if (g_once_init_enter (&preset_type)) {
242 GType type = g_enum_register_static ("GstAmfH264EncPreset", presets);
243 g_once_init_leave (&preset_type, type);
256 GstAmfH264EncDeviceCaps dev_caps;
257 } GstAmfH264EncClassData;
278 #define DEFAULT_USAGE AMF_VIDEO_ENCODER_USAGE_TRANSCODING
279 #define DEFAULT_RATE_CONTROL AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN
280 #define DEFAULT_PRESET AMF_VIDEO_ENCODER_QUALITY_PRESET_UNKNOWN
281 #define DEFAULT_BITRATE 0
282 #define DEFAULT_MAX_BITRATE 0
283 #define DEFAULT_GOP_SIZE -1
284 #define DEFAULT_MIN_MAX_QP -1
285 #define DEFAULT_AUD TRUE
286 #define DEFAULT_CABAC TRUE
288 typedef struct _GstAmfH264Enc
290 GstAmfEncoder parent;
293 GstH264NalParser *parser;
296 gboolean property_updated;
314 typedef struct _GstAmfH264EncClass
316 GstAmfEncoderClass parent_class;
317 GstAmfH264EncDeviceCaps dev_caps;
320 } GstAmfH264EncClass;
322 #define GST_AMF_H264_ENC(object) ((GstAmfH264Enc *) (object))
323 #define GST_AMF_H264_ENC_GET_CLASS(object) \
324 (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstAmfH264EncClass))
326 static void gst_amf_h264_enc_finalize (GObject * object);
327 static void gst_amf_h264_enc_set_property (GObject * object, guint prop_id,
328 const GValue * value, GParamSpec * pspec);
329 static void gst_amf_h264_enc_get_property (GObject * object, guint prop_id,
330 GValue * value, GParamSpec * pspec);
331 static GstCaps *gst_amf_h264_enc_getcaps (GstVideoEncoder * encoder,
333 static gboolean gst_amf_h264_enc_set_format (GstAmfEncoder * encoder,
334 GstVideoCodecState * state, gpointer component);
335 static gboolean gst_amf_h264_enc_set_output_state (GstAmfEncoder * encoder,
336 GstVideoCodecState * state, gpointer component);
337 static gboolean gst_amf_h264_enc_set_surfrace_prop (GstAmfEncoder * encoder,
338 GstVideoCodecFrame * frame, gpointer surface);
339 static GstBuffer *gst_amf_h264_enc_create_output_buffer (GstAmfEncoder *
340 encoder, gpointer data, gboolean * sync_point);
341 static gboolean gst_amf_h264_enc_check_reconfigure (GstAmfEncoder * encoder);
344 gst_amf_h264_enc_class_init (GstAmfH264EncClass * klass, gpointer data)
346 GObjectClass *object_class = G_OBJECT_CLASS (klass);
347 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
348 GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
349 GstAmfEncoderClass *amf_class = GST_AMF_ENCODER_CLASS (klass);
350 GstAmfH264EncClassData *cdata = (GstAmfH264EncClassData *) data;
351 GstAmfH264EncDeviceCaps *dev_caps = &cdata->dev_caps;
352 GParamFlags param_flags = (GParamFlags) (G_PARAM_READWRITE |
353 GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS);
355 parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
357 object_class->finalize = gst_amf_h264_enc_finalize;
358 object_class->set_property = gst_amf_h264_enc_set_property;
359 object_class->get_property = gst_amf_h264_enc_get_property;
361 g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
362 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
363 "DXGI Adapter LUID (Locally Unique Identifier) of associated GPU",
364 G_MININT64, G_MAXINT64, cdata->adapter_luid, param_flags));
365 g_object_class_install_property (object_class, PROP_USAGE,
366 g_param_spec_enum ("usage", "Usage",
367 "Target usage", GST_TYPE_AMF_H264_ENC_USAGE,
368 DEFAULT_USAGE, param_flags));
369 g_object_class_install_property (object_class, PROP_RATE_CONTROL,
370 g_param_spec_enum ("rate-control", "Rate Control",
371 "Rate Control Method", GST_TYPE_AMF_H264_ENC_RATE_CONTROL,
372 DEFAULT_RATE_CONTROL, param_flags));
373 g_object_class_install_property (object_class, PROP_PRESET,
374 g_param_spec_enum ("preset", "Preset",
375 "Preset", GST_TYPE_AMF_H264_ENC_PRESET, DEFAULT_PRESET, param_flags));
376 g_object_class_install_property (object_class, PROP_BITRATE,
377 g_param_spec_uint ("bitrate", "Bitrate",
378 "Target bitrate in kbit/sec (0: USAGE default)",
379 0, G_MAXINT / 1000, DEFAULT_BITRATE, param_flags));
380 g_object_class_install_property (object_class, PROP_MAX_BITRATE,
381 g_param_spec_uint ("max-bitrate", "Max Bitrate",
382 "Maximum bitrate in kbit/sec (0: USAGE default)",
383 0, G_MAXINT / 1000, DEFAULT_MAX_BITRATE, param_flags));
384 g_object_class_install_property (object_class, PROP_GOP_SIZE,
385 g_param_spec_int ("gop-size", "GOP Size",
386 "Number of pictures within a GOP (-1: USAGE default)",
387 -1, G_MAXINT, DEFAULT_GOP_SIZE, param_flags));
388 g_object_class_install_property (object_class, PROP_MIN_QP,
389 g_param_spec_int ("min-qp", "Min QP",
390 "Minimum allowed QP value (-1: USAGE default)",
391 -1, 51, DEFAULT_MIN_MAX_QP, param_flags));
392 g_object_class_install_property (object_class, PROP_MAX_QP,
393 g_param_spec_int ("max-qp", "Max QP",
394 "Maximum allowed QP value (-1: USAGE default)",
395 -1, 51, DEFAULT_MIN_MAX_QP, param_flags));
396 g_object_class_install_property (object_class, PROP_QP_I,
397 g_param_spec_uint ("qp-i", "QP I",
398 "Constant QP for I frames", 0, 51,
399 (guint) dev_caps->default_qp_i, param_flags));
400 g_object_class_install_property (object_class, PROP_QP_P,
401 g_param_spec_uint ("qp-p", "QP P",
402 "Constant QP for P frames", 0, 51,
403 (guint) dev_caps->default_qp_p, param_flags));
404 g_object_class_install_property (object_class, PROP_REF_FRAMES,
405 g_param_spec_uint ("ref-frames", "Reference Frames",
406 "Number of reference frames", (guint) dev_caps->min_ref_frames,
407 (guint) dev_caps->max_ref_frames,
408 (guint) dev_caps->min_ref_frames, param_flags));
409 g_object_class_install_property (object_class, PROP_AUD,
410 g_param_spec_boolean ("aud", "AUD",
411 "Use AU (Access Unit) delimiter", DEFAULT_AUD, param_flags));
412 g_object_class_install_property (object_class, PROP_CABAC,
413 g_param_spec_boolean ("cabac", "CABAC",
414 "Enable CABAC entropy coding", TRUE, param_flags));
416 gst_element_class_set_metadata (element_class,
417 "AMD AMF H.264 Video Encoder",
418 "Codec/Encoder/Video/Hardware",
419 "Encode H.264 video streams using AMF API",
420 "Seungha Yang <seungha@centricular.com>");
422 gst_element_class_add_pad_template (element_class,
423 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
425 gst_element_class_add_pad_template (element_class,
426 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
429 videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_amf_h264_enc_getcaps);
431 amf_class->set_format = GST_DEBUG_FUNCPTR (gst_amf_h264_enc_set_format);
432 amf_class->set_output_state =
433 GST_DEBUG_FUNCPTR (gst_amf_h264_enc_set_output_state);
434 amf_class->set_surface_prop =
435 GST_DEBUG_FUNCPTR (gst_amf_h264_enc_set_surfrace_prop);
436 amf_class->create_output_buffer =
437 GST_DEBUG_FUNCPTR (gst_amf_h264_enc_create_output_buffer);
438 amf_class->check_reconfigure =
439 GST_DEBUG_FUNCPTR (gst_amf_h264_enc_check_reconfigure);
441 klass->dev_caps = cdata->dev_caps;
442 klass->adapter_luid = cdata->adapter_luid;
444 gst_caps_unref (cdata->sink_caps);
445 gst_caps_unref (cdata->src_caps);
448 gst_type_mark_as_plugin_api (GST_TYPE_AMF_H264_ENC_USAGE,
449 (GstPluginAPIFlags) 0);
450 gst_type_mark_as_plugin_api (GST_TYPE_AMF_H264_ENC_RATE_CONTROL,
451 (GstPluginAPIFlags) 0);
452 gst_type_mark_as_plugin_api (GST_TYPE_AMF_H264_ENC_PRESET,
453 (GstPluginAPIFlags) 0);
457 gst_amf_h264_enc_init (GstAmfH264Enc * self)
459 GstAmfH264EncClass *klass = GST_AMF_H264_ENC_GET_CLASS (self);
460 GstAmfH264EncDeviceCaps *dev_caps = &klass->dev_caps;
462 gst_amf_encoder_set_subclass_data (GST_AMF_ENCODER (self),
463 klass->adapter_luid, AMFVideoEncoderVCE_AVC);
465 self->parser = gst_h264_nal_parser_new ();
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 = DEFAULT_GOP_SIZE;
475 self->min_qp = DEFAULT_MIN_MAX_QP;
476 self->max_qp = DEFAULT_MIN_MAX_QP;
477 self->qp_i = (guint) dev_caps->default_qp_i;
478 self->qp_p = (guint) dev_caps->default_qp_p;
479 self->ref_frames = (guint) dev_caps->min_ref_frames;
480 self->aud = DEFAULT_AUD;
481 self->cabac = DEFAULT_CABAC;
485 gst_amf_h264_enc_finalize (GObject * object)
487 GstAmfH264Enc *self = GST_AMF_H264_ENC (object);
489 gst_h264_nal_parser_free (self->parser);
490 g_mutex_clear (&self->prop_lock);
492 G_OBJECT_CLASS (parent_class)->finalize (object);
496 update_int (GstAmfH264Enc * self, gint * old_val, const GValue * new_val)
498 gint val = g_value_get_int (new_val);
504 self->property_updated = TRUE;
508 update_uint (GstAmfH264Enc * self, guint * old_val, const GValue * new_val)
510 guint val = g_value_get_uint (new_val);
516 self->property_updated = TRUE;
520 update_enum (GstAmfH264Enc * self, gint * old_val, const GValue * new_val)
522 gint val = g_value_get_enum (new_val);
528 self->property_updated = TRUE;
532 update_bool (GstAmfH264Enc * self, gboolean * old_val, const GValue * new_val)
534 gboolean val = g_value_get_boolean (new_val);
540 self->property_updated = TRUE;
544 gst_amf_h264_enc_set_property (GObject * object, guint prop_id,
545 const GValue * value, GParamSpec * pspec)
547 GstAmfH264Enc *self = GST_AMF_H264_ENC (object);
549 g_mutex_lock (&self->prop_lock);
552 update_enum (self, &self->usage, value);
554 case PROP_RATE_CONTROL:
555 update_enum (self, &self->rate_control, value);
558 update_enum (self, &self->preset, value);
561 update_uint (self, &self->bitrate, value);
563 case PROP_MAX_BITRATE:
564 update_uint (self, &self->max_bitrate, value);
567 update_int (self, &self->gop_size, value);
570 update_int (self, &self->min_qp, value);
573 update_int (self, &self->max_qp, value);
576 update_uint (self, &self->qp_i, value);
579 update_uint (self, &self->qp_p, value);
581 case PROP_REF_FRAMES:
582 update_uint (self, &self->ref_frames, value);
585 /* This is per frame property, don't need to reset encoder */
586 self->aud = g_value_get_boolean (value);
589 update_bool (self, &self->cabac, value);
592 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
595 g_mutex_unlock (&self->prop_lock);
599 gst_amf_h264_enc_get_property (GObject * object, guint prop_id,
600 GValue * value, GParamSpec * pspec)
602 GstAmfH264EncClass *klass = GST_AMF_H264_ENC_GET_CLASS (object);
603 GstAmfH264Enc *self = GST_AMF_H264_ENC (object);
606 case PROP_ADAPTER_LUID:
607 g_value_set_int64 (value, klass->adapter_luid);
610 g_value_set_enum (value, self->usage);
612 case PROP_RATE_CONTROL:
613 g_value_set_enum (value, self->rate_control);
616 g_value_set_enum (value, self->preset);
619 g_value_set_uint (value, self->bitrate);
621 case PROP_MAX_BITRATE:
622 g_value_set_uint (value, self->max_bitrate);
625 g_value_set_int (value, self->gop_size);
628 g_value_set_int (value, self->min_qp);
631 g_value_set_int (value, self->max_qp);
634 g_value_set_uint (value, self->qp_i);
637 g_value_set_uint (value, self->qp_p);
639 case PROP_REF_FRAMES:
640 g_value_set_uint (value, self->ref_frames);
643 g_value_set_boolean (value, self->aud);
646 g_value_set_boolean (value, self->cabac);
649 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
655 gst_amf_h264_enc_get_downstream_profiles_and_format (GstAmfH264Enc * self,
656 std::set < std::string > &downstream_profiles, gboolean * packetized)
658 GstCaps *allowed_caps;
660 const gchar *stream_format;
662 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
664 if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
665 gst_caps_is_any (allowed_caps)) {
666 gst_clear_caps (&allowed_caps);
671 for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
672 const GValue *profile_value;
673 const gchar *profile;
675 s = gst_caps_get_structure (allowed_caps, i);
676 profile_value = gst_structure_get_value (s, "profile");
680 if (GST_VALUE_HOLDS_LIST (profile_value)) {
681 for (guint j = 0; j < gst_value_list_get_size (profile_value); j++) {
682 const GValue *p = gst_value_list_get_value (profile_value, j);
684 if (!G_VALUE_HOLDS_STRING (p))
687 profile = g_value_get_string (p);
689 downstream_profiles.insert (profile);
692 } else if (G_VALUE_HOLDS_STRING (profile_value)) {
693 profile = g_value_get_string (profile_value);
695 downstream_profiles.insert (profile);
701 allowed_caps = gst_caps_fixate (allowed_caps);
702 s = gst_caps_get_structure (allowed_caps, 0);
703 stream_format = gst_structure_get_string (s, "stream-format");
704 if (g_strcmp0 (stream_format, "avc") == 0)
708 gst_caps_unref (allowed_caps);
712 gst_amf_h264_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
714 GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
715 GstAmfH264EncClass *klass = GST_AMF_H264_ENC_GET_CLASS (self);
716 GstCaps *template_caps;
717 GstCaps *supported_caps;
718 std::set < std::string > downstream_profiles;
720 if (!klass->dev_caps.interlace_supported)
721 return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
723 gst_amf_h264_enc_get_downstream_profiles_and_format (self,
724 downstream_profiles, nullptr);
726 GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
727 downstream_profiles.size ());
729 if (downstream_profiles.size () == 0)
730 return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
732 /* Profile allows interlaced? */
734 gboolean can_support_interlaced = FALSE;
735 for (const auto &iter: downstream_profiles) {
736 if (iter == "high" || iter == "main" || iter == "constrained-high") {
737 can_support_interlaced = TRUE;
743 GST_DEBUG_OBJECT (self, "Downstream %s support interlaced format",
744 can_support_interlaced ? "can" : "cannot");
746 if (can_support_interlaced) {
747 /* No special handling is needed */
748 return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
751 template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
752 template_caps = gst_caps_make_writable (template_caps);
754 gst_caps_set_simple (template_caps, "interlace-mode", G_TYPE_STRING,
755 "progressive", nullptr);
757 supported_caps = gst_video_encoder_proxy_getcaps (encoder,
758 template_caps, filter);
759 gst_caps_unref (template_caps);
761 GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
763 return supported_caps;
767 gst_amf_h264_enc_set_format (GstAmfEncoder * encoder,
768 GstVideoCodecState * state, gpointer component)
770 GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
771 GstAmfH264EncClass *klass = GST_AMF_H264_ENC_GET_CLASS (self);
772 GstAmfH264EncDeviceCaps *dev_caps = &klass->dev_caps;
773 AMFComponent *comp = (AMFComponent *) component;
774 GstVideoInfo *info = &state->info;
775 std::set < std::string > downstream_profiles;
776 AMF_VIDEO_ENCODER_PROFILE_ENUM profile = AMF_VIDEO_ENCODER_PROFILE_UNKNOWN;
779 AMFRatio aspect_ratio;
781 amf_bool boolean_val;
782 AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_ENUM rc_mode;
783 AMF_VIDEO_ENCODER_CODING_ENUM cabac = AMF_VIDEO_ENCODER_UNDEFINED;
785 self->packetized = FALSE;
787 gst_amf_h264_enc_get_downstream_profiles_and_format (self,
788 downstream_profiles, &self->packetized);
790 if (downstream_profiles.empty ()) {
791 GST_ERROR_OBJECT (self, "Unable to get downstream profile");
795 if (GST_VIDEO_INFO_IS_INTERLACED (info)) {
796 downstream_profiles.erase ("constrained-high");
797 downstream_profiles.erase ("constrained-baseline");
798 downstream_profiles.erase ("baseline");
800 if (downstream_profiles.empty ()) {
801 GST_ERROR_OBJECT (self,
802 "None of downstream profile supports interlaced encoding");
807 if (downstream_profiles.find ("main") != downstream_profiles.end ()) {
808 profile = AMF_VIDEO_ENCODER_PROFILE_MAIN;
809 } else if (downstream_profiles.find ("high") != downstream_profiles.end ()) {
810 profile = AMF_VIDEO_ENCODER_PROFILE_HIGH;
811 } else if (downstream_profiles.find ("constrained-high") !=
812 downstream_profiles.end ()) {
813 if (dev_caps->max_profile >=
814 (gint64) AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH) {
815 profile = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH;
817 profile = AMF_VIDEO_ENCODER_PROFILE_HIGH;
819 } else if (downstream_profiles.find ("constrained-baseline") !=
820 downstream_profiles.end ()) {
821 if (dev_caps->max_profile >=
822 (gint64) AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE) {
823 profile = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE;
825 profile = AMF_VIDEO_ENCODER_PROFILE_BASELINE;
827 } else if (downstream_profiles.find ("baseline") !=
828 downstream_profiles.end ()) {
829 profile = AMF_VIDEO_ENCODER_PROFILE_BASELINE;
831 GST_ERROR_OBJECT (self, "Failed to determine profile");
835 g_mutex_lock (&self->prop_lock);
836 /* Configure static properties first before Init() */
837 result = comp->SetProperty (AMF_VIDEO_ENCODER_FRAMESIZE,
838 AMFConstructSize (info->width, info->height));
839 if (result != AMF_OK) {
840 GST_ERROR_OBJECT (self, "Failed to set frame size, result %"
841 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
845 result = comp->SetProperty (AMF_VIDEO_ENCODER_USAGE, (amf_int64) self->usage);
846 if (result != AMF_OK) {
847 GST_ERROR_OBJECT (self, "Failed to set usage, result %"
848 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
852 if (self->preset > AMF_VIDEO_ENCODER_QUALITY_PRESET_UNKNOWN) {
853 result = comp->SetProperty (AMF_VIDEO_ENCODER_QUALITY_PRESET,
854 (amf_int64) self->preset);
855 if (result != AMF_OK) {
856 GST_ERROR_OBJECT (self, "Failed to set quality preset, result %"
857 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
862 result = comp->SetProperty (AMF_VIDEO_ENCODER_PROFILE, (amf_int64) profile);
863 if (result != AMF_OK) {
864 GST_ERROR_OBJECT (self, "Failed to set profile, result %"
865 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
869 result = comp->SetProperty (AMF_VIDEO_ENCODER_MAX_NUM_REFRAMES,
870 (amf_int64) self->ref_frames);
871 if (result != AMF_OK) {
872 GST_ERROR_OBJECT (self, "Failed to set ref-frames, result %"
873 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
877 aspect_ratio = AMFConstructRatio (info->par_n, info->par_d);
878 result = comp->SetProperty (AMF_VIDEO_ENCODER_ASPECT_RATIO, aspect_ratio);
879 if (result != AMF_OK) {
880 GST_ERROR_OBJECT (self, "Failed to set aspect ratio, result %"
881 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
885 if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255)
890 result = comp->SetProperty (AMF_VIDEO_ENCODER_FULL_RANGE_COLOR, boolean_val);
891 if (result != AMF_OK) {
892 GST_ERROR_OBJECT (self, "Failed to set full-range-color, result %"
893 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
897 if (self->rate_control != AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN) {
898 result = comp->SetProperty (AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD,
899 (amf_int64) self->rate_control);
900 if (result != AMF_OK) {
901 GST_ERROR_OBJECT (self, "Failed to set rate-control, result %"
902 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
907 result = comp->Init (AMF_SURFACE_NV12, info->width, info->height);
908 if (result != AMF_OK) {
909 GST_ERROR_OBJECT (self, "Failed to init component, result %"
910 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
914 /* dynamic properties */
915 result = comp->GetProperty (AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD,
917 if (result != AMF_OK) {
918 GST_ERROR_OBJECT (self, "Failed to get rate-control method, result %"
919 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
923 rc_mode = (AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_ENUM) int64_val;
924 if (self->min_qp >= 0)
925 comp->SetProperty (AMF_VIDEO_ENCODER_MIN_QP, (amf_int64) self->min_qp);
926 if (self->max_qp >= 0)
927 comp->SetProperty (AMF_VIDEO_ENCODER_MAX_QP, (amf_int64) self->max_qp);
929 comp->SetProperty (AMF_VIDEO_ENCODER_QP_I, (amf_int64) self->qp_i);
930 comp->SetProperty (AMF_VIDEO_ENCODER_QP_P, (amf_int64) self->qp_p);
933 case AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR:
934 if (self->bitrate > 0) {
935 comp->SetProperty (AMF_VIDEO_ENCODER_TARGET_BITRATE,
936 (amf_int64) self->bitrate * 1000);
937 comp->SetProperty (AMF_VIDEO_ENCODER_PEAK_BITRATE,
938 (amf_int64) self->bitrate * 1000);
941 case AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR:
942 case AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR:
943 if (self->bitrate > 0) {
944 comp->SetProperty (AMF_VIDEO_ENCODER_TARGET_BITRATE,
945 (amf_int64) self->bitrate * 1000);
947 if (self->max_bitrate > 0) {
948 comp->SetProperty (AMF_VIDEO_ENCODER_PEAK_BITRATE,
949 (amf_int64) self->max_bitrate * 1000);
956 /* Disable frame skip for now, need investigation the behavior */
957 result = comp->SetProperty (AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE,
959 if (result != AMF_OK) {
960 GST_ERROR_OBJECT (self, "Failed to disable skip frame, result %"
961 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
965 if (info->fps_n > 0 && info->fps_d) {
966 framerate = AMFConstructRate (info->fps_n, info->fps_d);
968 framerate = AMFConstructRate (25, 1);
971 result = comp->SetProperty (AMF_VIDEO_ENCODER_FRAMERATE, framerate);
972 if (result != AMF_OK) {
973 GST_ERROR_OBJECT (self, "Failed to set frame rate, result %"
974 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
978 if (self->gop_size >= 0) {
979 result = comp->SetProperty (AMF_VIDEO_ENCODER_IDR_PERIOD,
980 (amf_int64) self->gop_size);
981 if (result != AMF_OK) {
982 GST_ERROR_OBJECT (self, "Failed to set IDR period, result %"
983 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
988 if (profile != AMF_VIDEO_ENCODER_PROFILE_BASELINE &&
989 profile != AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE) {
991 cabac = AMF_VIDEO_ENCODER_CABAC;
993 cabac = AMF_VIDEO_ENCODER_CALV;
996 result = comp->SetProperty (AMF_VIDEO_ENCODER_CABAC_ENABLE,
998 if (result != AMF_OK) {
999 GST_ERROR_OBJECT (self, "Failed to set cabac, result %"
1000 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1004 self->property_updated = FALSE;
1005 g_mutex_unlock (&self->prop_lock);
1010 g_mutex_unlock (&self->prop_lock);
1016 gst_amf_h264_enc_set_output_state (GstAmfEncoder * encoder,
1017 GstVideoCodecState * state, gpointer component)
1019 GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1020 AMFComponent *comp = (AMFComponent *) component;
1021 GstVideoCodecState *output_state;
1023 const gchar *profile_from_sps;
1024 std::set < std::string > downstream_profiles;
1025 std::string caps_str;
1027 GstBuffer *codec_data = nullptr;
1028 GstH264NalUnit sps_nalu, pps_nalu;
1029 GstH264ParserResult rst;
1031 AMFInterfacePtr iface;
1032 AMFBufferPtr spspps_buf;
1034 amf_size spspps_size;
1036 result = comp->GetProperty (AMF_VIDEO_ENCODER_EXTRADATA, &iface);
1037 if (result != AMF_OK) {
1038 GST_ERROR_OBJECT (self, "Failed to get extra data, result %"
1039 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1043 spspps_buf = AMFBufferPtr (iface);
1045 GST_ERROR_OBJECT (self, "Failed to set get AMFBuffer interface, result %"
1046 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1050 spspps_size = spspps_buf->GetSize ();
1051 if (spspps_size < 4) {
1052 GST_ERROR_OBJECT (self, "Too small spspps size %d", (guint) spspps_size);
1056 spspps = (guint8 *) spspps_buf->GetNative ();
1058 GST_ERROR_OBJECT (self, "Null SPS/PPS");
1062 caps_str = "video/x-h264, alignment = (string) au";
1063 gst_amf_h264_enc_get_downstream_profiles_and_format (self,
1064 downstream_profiles, nullptr);
1066 rst = gst_h264_parser_identify_nalu (self->parser,
1067 spspps, 0, spspps_size, &sps_nalu);
1068 if (rst != GST_H264_PARSER_OK) {
1069 GST_ERROR_OBJECT (self, "Failed to identify SPS nal");
1073 if (sps_nalu.size < 4) {
1074 GST_ERROR_OBJECT (self, "Too small sps nal size %d", sps_nalu.size);
1078 rst = gst_h264_parser_identify_nalu_unchecked (self->parser,
1079 spspps, sps_nalu.offset + sps_nalu.size, spspps_size, &pps_nalu);
1080 if (rst != GST_H264_PARSER_OK && self->packetized) {
1081 GST_ERROR_OBJECT (self, "Failed to identify PPS nal, %d", rst);
1085 if (self->packetized) {
1088 guint8 profile_idc, profile_comp, level_idc;
1089 const guint nal_length_size = 4;
1090 const guint num_sps = 1;
1091 const guint num_pps = 1;
1093 data = sps_nalu.data + sps_nalu.offset + sps_nalu.header_bytes;
1094 profile_idc = data[0];
1095 profile_comp = data[1];
1096 level_idc = data[2];
1098 /* 5: configuration version, profile, compatibility, level, nal length
1106 * -> 11 + sps_size + pps_size
1108 codec_data = gst_buffer_new_and_alloc (11 + sps_nalu.size + pps_nalu.size);
1110 gst_buffer_map (codec_data, &info, GST_MAP_WRITE);
1112 data = (guint8 *) info.data;
1114 data[1] = profile_idc;
1115 data[2] = profile_comp;
1116 data[3] = level_idc;
1117 data[4] = 0xfc | (nal_length_size - 1);
1118 data[5] = 0xe0 | num_sps;
1120 GST_WRITE_UINT16_BE (data, sps_nalu.size);
1122 memcpy (data, sps_nalu.data + sps_nalu.offset, sps_nalu.size);
1123 data += sps_nalu.size;
1128 GST_WRITE_UINT16_BE (data, pps_nalu.size);
1130 memcpy (data, pps_nalu.data + pps_nalu.offset, pps_nalu.size);
1132 gst_buffer_unmap (codec_data, &info);
1136 gst_codec_utils_h264_get_profile (sps_nalu.data + sps_nalu.offset +
1137 sps_nalu.header_bytes, 3);
1139 if (!profile_from_sps) {
1140 GST_WARNING_OBJECT (self, "Failed to parse profile from SPS");
1141 } else if (!downstream_profiles.empty ()) {
1142 if (downstream_profiles.find (profile_from_sps) !=
1143 downstream_profiles.end ()) {
1144 caps_str += ", profile = (string) " + std::string (profile_from_sps);
1145 } else if (downstream_profiles.find ("baseline") !=
1146 downstream_profiles.end () &&
1147 strcmp (profile_from_sps, "constrained-baseline") == 0) {
1148 caps_str += ", profile = (string) baseline";
1149 } else if (downstream_profiles.find ("constrained-baseline") !=
1150 downstream_profiles.end () &&
1151 strcmp (profile_from_sps, "constrained-baseline") == 0) {
1152 caps_str += ", profile = (string) constrained-baseline";
1155 caps_str += ", profile = (string) " + std::string (profile_from_sps);
1158 if (self->packetized) {
1159 caps_str += ", stream-format = (string) avc";
1161 caps_str += ", stream-format = (string) byte-stream";
1164 caps = gst_caps_from_string (caps_str.c_str ());
1166 if (self->packetized) {
1167 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data,
1169 gst_buffer_unref (codec_data);
1172 output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1175 GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
1176 gst_video_codec_state_unref (output_state);
1178 tags = gst_tag_list_new_empty ();
1179 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1180 "amfh264enc", nullptr);
1182 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
1183 tags, GST_TAG_MERGE_REPLACE);
1184 gst_tag_list_unref (tags);
1190 gst_amf_h264_enc_set_surfrace_prop (GstAmfEncoder * encoder,
1191 GstVideoCodecFrame * frame, gpointer surface)
1193 GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1194 AMFSurface *surf = (AMFSurface *) surface;
1196 amf_bool insert_aud = self->aud ? true : false;
1198 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1199 amf_int64 type = (amf_int64) AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR;
1200 result = surf->SetProperty (AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, type);
1201 if (result != AMF_OK) {
1202 GST_WARNING_OBJECT (encoder, "Failed to set force idr, result %"
1203 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1207 result = surf->SetProperty (AMF_VIDEO_ENCODER_INSERT_AUD, &insert_aud);
1208 if (result != AMF_OK) {
1209 GST_WARNING_OBJECT (encoder, "Failed to set AUD, result %"
1210 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1217 gst_amf_h264_enc_create_output_buffer (GstAmfEncoder * encoder,
1218 gpointer data, gboolean * sync_point)
1220 GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1221 AMFBuffer *amf_buf = (AMFBuffer *) data;
1223 GstH264ParserResult rst;
1224 GstH264NalUnit nalu;
1227 amf_int64 output_type = 0;
1230 data_ptr = (guint8 *) amf_buf->GetNative ();
1231 data_size = amf_buf->GetSize ();
1233 if (!data_ptr || data_size == 0) {
1234 GST_WARNING_OBJECT (self, "Empty buffer");
1238 if (!self->packetized) {
1239 buf = gst_buffer_new_memdup (data_ptr, data_size);
1241 buf = gst_buffer_new ();
1242 rst = gst_h264_parser_identify_nalu (self->parser,
1243 data_ptr, 0, data_size, &nalu);
1244 if (rst == GST_H264_PARSER_NO_NAL_END)
1245 rst = GST_H264_PARSER_OK;
1247 while (rst == GST_H264_PARSER_OK) {
1251 data = (guint8 *) g_malloc0 (nalu.size + 4);
1252 GST_WRITE_UINT32_BE (data, nalu.size);
1253 memcpy (data + 4, nalu.data + nalu.offset, nalu.size);
1255 mem = gst_memory_new_wrapped ((GstMemoryFlags) 0, data, nalu.size + 4,
1256 0, nalu.size + 4, data, (GDestroyNotify) g_free);
1257 gst_buffer_append_memory (buf, mem);
1259 rst = gst_h264_parser_identify_nalu (self->parser,
1260 data_ptr, nalu.offset + nalu.size, data_size, &nalu);
1262 if (rst == GST_H264_PARSER_NO_NAL_END)
1263 rst = GST_H264_PARSER_OK;
1267 result = amf_buf->GetProperty (AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE,
1269 if (result == AMF_OK &&
1270 output_type == (amf_int64) AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
1278 gst_amf_h264_enc_check_reconfigure (GstAmfEncoder * encoder)
1280 GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1283 g_mutex_lock (&self->prop_lock);
1284 ret = self->property_updated;
1285 g_mutex_unlock (&self->prop_lock);
1290 static GstAmfH264EncClassData *
1291 gst_amf_h264_enc_create_class_data (GstD3D11Device * device,
1292 AMFComponent * comp)
1295 GstAmfH264EncDeviceCaps dev_caps = { 0, };
1296 std::string sink_caps_str;
1297 std::string src_caps_str;
1298 std::set < std::string > profiles;
1299 std::string profile_str;
1300 std::string resolution_str;
1301 GstAmfH264EncClassData *cdata;
1302 AMFCapsPtr amf_caps;
1303 AMFIOCapsPtr in_iocaps;
1304 AMFIOCapsPtr out_iocaps;
1305 amf_int32 in_min_width = 0, in_max_width = 0;
1306 amf_int32 in_min_height = 0, in_max_height = 0;
1307 amf_int32 out_min_width = 0, out_max_width = 0;
1308 amf_int32 out_min_height = 0, out_max_height = 0;
1309 amf_bool interlace_supported;
1311 gboolean have_nv12 = FALSE;
1312 gboolean d3d11_supported = FALSE;
1313 gint min_width, max_width, min_height, max_height;
1315 GstCaps *system_caps;
1317 result = comp->GetCaps (&amf_caps);
1318 if (result != AMF_OK) {
1319 GST_WARNING_OBJECT (device, "Unable to get caps");
1323 result = amf_caps->GetInputCaps (&in_iocaps);
1324 if (result != AMF_OK) {
1325 GST_WARNING_OBJECT (device, "Unable to get input io caps");
1329 in_iocaps->GetWidthRange (&in_min_width, &in_max_width);
1330 in_iocaps->GetHeightRange (&in_min_height, &in_max_height);
1331 dev_caps.valign = in_iocaps->GetVertAlign ();
1332 interlace_supported = in_iocaps->IsInterlacedSupported ();
1334 GST_INFO_OBJECT (device, "Input width: [%d, %d], height: [%d, %d], "
1335 "valign: %d, interlace supported: %d",
1336 in_min_width, in_max_width, in_min_height, in_max_height, dev_caps.valign,
1337 interlace_supported);
1339 if (interlace_supported)
1340 dev_caps.interlace_supported = TRUE;
1342 num_val = in_iocaps->GetNumOfFormats ();
1343 GST_LOG_OBJECT (device, "Input format count: %d", num_val);
1344 for (amf_int32 i = 0; i < num_val; i++) {
1345 AMF_SURFACE_FORMAT format;
1348 result = in_iocaps->GetFormatAt (i, &format, &native);
1349 if (result != AMF_OK)
1352 GST_INFO_OBJECT (device, "Format %d supported, native %d", format, native);
1353 if (format == AMF_SURFACE_NV12)
1358 GST_WARNING_OBJECT (device, "NV12 is not supported");
1362 num_val = in_iocaps->GetNumOfMemoryTypes ();
1363 GST_LOG_OBJECT (device, "Input memory type count: %d", num_val);
1364 for (amf_int32 i = 0; i < num_val; i++) {
1365 AMF_MEMORY_TYPE type;
1368 result = in_iocaps->GetMemoryTypeAt (i, &type, &native);
1369 if (result != AMF_OK)
1372 GST_INFO_OBJECT (device,
1373 "MemoryType %d supported, native %d", type, native);
1374 if (type == AMF_MEMORY_DX11)
1375 d3d11_supported = TRUE;
1378 if (!d3d11_supported) {
1379 GST_WARNING_OBJECT (device, "D3D11 is not supported");
1383 result = amf_caps->GetOutputCaps (&out_iocaps);
1384 if (result != AMF_OK) {
1385 GST_WARNING_OBJECT (device, "Unable to get input io caps");
1389 out_iocaps->GetWidthRange (&out_min_width, &out_max_width);
1390 out_iocaps->GetHeightRange (&out_min_height, &out_max_height);
1392 GST_INFO_OBJECT (device, "Output width: [%d, %d], height: [%d, %d]",
1393 in_min_width, in_max_width, in_min_height, in_max_height);
1395 #define QUERY_CAPS_PROP(prop,val) G_STMT_START { \
1396 amf_int64 _val = 0; \
1397 result = amf_caps->GetProperty (prop, &_val); \
1398 if (result == AMF_OK) { \
1399 GST_INFO_OBJECT (device, G_STRINGIFY (val) ": %" G_GINT64_FORMAT, _val); \
1400 dev_caps.val = _val; \
1404 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MAX_BITRATE, max_bitrate);
1405 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_NUM_OF_STREAMS, num_of_streams);
1406 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MAX_PROFILE, max_profile);
1407 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MAX_LEVEL, max_level);
1408 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_BFRAMES, bframes);
1409 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MIN_REFERENCE_FRAMES, min_ref_frames);
1410 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MAX_REFERENCE_FRAMES, max_ref_frames);
1411 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MAX_TEMPORAL_LAYERS,
1412 max_temporal_layers);
1413 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_FIXED_SLICE_MODE, fixed_slice_mode);
1414 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_NUM_OF_HW_INSTANCES,
1415 num_of_hw_instances);
1416 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_COLOR_CONVERSION, color_conversion);
1417 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_PRE_ANALYSIS, pre_analysis);
1418 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_ROI, roi_map);
1419 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAP_MAX_THROUGHPUT, max_throughput);
1420 QUERY_CAPS_PROP (AMF_VIDEO_ENCODER_CAPS_QUERY_TIMEOUT_SUPPORT,
1421 query_timeout_support);
1422 #undef QUERY_CAPS_PROP
1424 #define QUERY_DEFAULT_PROP(prop,val,default_val) G_STMT_START { \
1425 const AMFPropertyInfo *pinfo = nullptr; \
1426 result = comp->GetPropertyInfo (prop, &pinfo); \
1427 if (result == AMF_OK && pinfo) { \
1428 dev_caps.val = AMFVariantGetInt64 (&pinfo->defaultValue); \
1429 GST_INFO_OBJECT (device, G_STRINGIFY (val) ": %" G_GINT64_FORMAT, \
1432 dev_caps.val = default_val; \
1436 QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_QP_I, default_qp_i, 22);
1437 QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_QP_I, default_qp_p, 22);
1438 QUERY_DEFAULT_PROP (AMF_VIDEO_ENCODER_QP_I, default_qp_b, 22);
1439 #undef QUERY_DEFAULT_PROP
1441 min_width = MAX (in_min_width, 1);
1442 max_width = in_max_width;
1443 if (max_width == 0) {
1444 GST_WARNING_OBJECT (device, "Unknown max width, assuming 4096");
1448 min_height = MAX (in_min_height, 1);
1449 max_height = in_max_height;
1450 if (max_height == 0) {
1451 GST_WARNING_OBJECT (device, "Unknown max height, assuming 4096");
1455 if (dev_caps.max_profile >= (gint64) AMF_VIDEO_ENCODER_PROFILE_BASELINE) {
1456 profiles.insert ("baseline");
1457 profiles.insert ("constrained-baseline");
1460 if (dev_caps.max_profile >= (gint64) AMF_VIDEO_ENCODER_PROFILE_MAIN)
1461 profiles.insert ("main");
1463 if (dev_caps.max_profile >= (gint64) AMF_VIDEO_ENCODER_PROFILE_HIGH) {
1464 profiles.insert ("high");
1467 if (dev_caps.max_profile >=
1468 (gint64) AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH) {
1469 profiles.insert ("constrained-high");
1472 if (profiles.empty ()) {
1473 GST_WARNING_OBJECT (device, "Failed to determine profile support");
1476 #define APPEND_STRING(dst,set,str) G_STMT_START { \
1477 if (set.find(str) != set.end()) { \
1485 if (profiles.size () == 1) {
1486 profile_str = "profile = (string) " + *(profiles.begin ());
1488 gboolean first = TRUE;
1490 profile_str = "profile = (string) { ";
1491 APPEND_STRING (profile_str, profiles, "main");
1492 APPEND_STRING (profile_str, profiles, "high");
1493 APPEND_STRING (profile_str, profiles, "constrained-high");
1494 APPEND_STRING (profile_str, profiles, "constrained-baseline");
1495 APPEND_STRING (profile_str, profiles, "baseline");
1496 profile_str += " } ";
1498 #undef APPEND_STRING
1500 resolution_str = "width = (int) [ " + std::to_string (min_width)
1501 + ", " + std::to_string (max_width) + " ]";
1502 resolution_str += ", height = (int) [ " + std::to_string (min_height)
1503 + ", " + std::to_string (max_height) + " ]";
1505 sink_caps_str = "video/x-raw, format = (string) NV12, " + resolution_str;
1506 if (dev_caps.interlace_supported > 0) {
1507 sink_caps_str += ", interlace-mode = (string) { interleaved, mixed }";
1509 sink_caps_str += ", interlace-mode = (string) progressive";
1512 src_caps_str = "video/x-h264, " + resolution_str + ", " + profile_str +
1513 ", stream-format = (string) { avc, byte-stream }, alignment = (string) au";
1515 system_caps = gst_caps_from_string (sink_caps_str.c_str ());
1516 sink_caps = gst_caps_copy (system_caps);
1517 gst_caps_set_features (sink_caps, 0,
1518 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr));
1519 gst_caps_append (sink_caps, system_caps);
1521 cdata = g_new0 (GstAmfH264EncClassData, 1);
1522 cdata->sink_caps = sink_caps;
1523 cdata->src_caps = gst_caps_from_string (src_caps_str.c_str ());
1524 cdata->dev_caps = dev_caps;
1525 g_object_get (device, "adapter-luid", &cdata->adapter_luid, nullptr);
1527 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
1528 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1529 GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
1530 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1532 GST_DEBUG_OBJECT (device, "Sink caps %" GST_PTR_FORMAT, cdata->sink_caps);
1533 GST_DEBUG_OBJECT (device, "Src caps %" GST_PTR_FORMAT, cdata->src_caps);
1539 gst_amf_h264_enc_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
1540 gpointer context, guint rank)
1542 GstAmfH264EncClassData *cdata;
1543 AMFContext *amf_context = (AMFContext *) context;
1544 AMFFactory *factory = (AMFFactory *) gst_amf_get_factory ();
1545 AMFComponentPtr comp;
1548 GST_DEBUG_CATEGORY_INIT (gst_amf_h264_enc_debug, "amfh264enc", 0,
1551 result = factory->CreateComponent (amf_context, AMFVideoEncoderVCE_AVC,
1553 if (result != AMF_OK) {
1554 GST_WARNING_OBJECT (device, "Failed to create component, result %"
1555 GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1559 cdata = gst_amf_h264_enc_create_class_data (device, comp.GetPtr ());
1565 gchar *feature_name;
1566 GTypeInfo type_info = {
1567 sizeof (GstAmfH264EncClass),
1570 (GClassInitFunc) gst_amf_h264_enc_class_init,
1573 sizeof (GstAmfH264Enc),
1575 (GInstanceInitFunc) gst_amf_h264_enc_init,
1578 type_name = g_strdup ("GstAmfH264Enc");
1579 feature_name = g_strdup ("amfh264enc");
1582 while (g_type_from_name (type_name)) {
1585 g_free (feature_name);
1586 type_name = g_strdup_printf ("GstAmfH264Device%dEnc", index);
1587 feature_name = g_strdup_printf ("amfh264device%denc", index);
1590 type = g_type_register_static (GST_TYPE_AMF_ENCODER, type_name,
1591 &type_info, (GTypeFlags) 0);
1593 if (rank > 0 && index != 0)
1597 gst_element_type_set_skip_documentation (type);
1599 if (!gst_element_register (plugin, feature_name, rank, type))
1600 GST_WARNING ("Failed to register plugin '%s'", type_name);
1603 g_free (feature_name);