amfcodec: fix setting quality presets
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / amfcodec / gstamfh264enc.cpp
1 /* GStreamer
2  * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION:element-amfh264enc
22  * @title: amfh264enc
23  * @short_description: An AMD AMF API based H.264 video encoder
24  *
25  * amfh264enc element encodes raw video stream into compressed H.264 bitstream
26  * via AMD AMF API.
27  *
28  * ## Example launch line
29  * ```
30  * gst-launch-1.0 videotestsrc num-buffers=100 ! amfh264enc ! h264parse ! mp4mux ! filesink location=encoded.mp4
31  * ```
32  *
33  * Since: 1.22
34  *
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
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>
47 #include <string>
48 #include <set>
49 #include <string.h>
50
51 using namespace amf;
52
53 GST_DEBUG_CATEGORY_STATIC (gst_amf_h264_enc_debug);
54 #define GST_CAT_DEFAULT gst_amf_h264_enc_debug
55
56 static GTypeClass *parent_class = nullptr;
57
58 typedef struct
59 {
60   amf_int64 max_bitrate;
61   amf_int64 num_of_streams;
62   amf_int64 max_profile;
63   amf_int64 max_level;
64   amf_int64 bframes;
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;
72   amf_int64 roi_map;
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;
79   guint valign;
80 } GstAmfH264EncDeviceCaps;
81
82 /**
83  * GstAmfH264EncUsage:
84  *
85  * Encoder usages
86  *
87  * Since: 1.22
88  */
89 #define GST_TYPE_AMF_H264_ENC_USAGE (gst_amf_h264_enc_usage_get_type ())
90 static GType
91 gst_amf_h264_enc_usage_get_type (void)
92 {
93   static GType usage_type = 0;
94   static const GEnumValue usages[] = {
95     /**
96      * GstAmfH264EncUsage::transcoding:
97      *
98      * Transcoding usage
99      */
100     {AMF_VIDEO_ENCODER_USAGE_TRANSCODING, "Transcoding", "transcoding"},
101
102     /**
103      * GstAmfH264EncUsage::ultra-low-latency:
104      *
105      * Ultra Low Latency usage
106      */
107     {AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY, "Ultra Low Latency",
108         "ultra-low-latency"},
109
110     /**
111      * GstAmfH264EncUsage::low-latency:
112      *
113      * Low Latency usage
114      */
115     {AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY, "Low Latency", "low-latency"},
116
117     /**
118      * GstAmfH264EncUsage::webcam:
119      *
120      * Webcam usage
121      */
122     {AMF_VIDEO_ENCODER_USAGE_WEBCAM, "Webcam", "webcam"},
123     {0, nullptr, nullptr}
124   };
125
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);
129   }
130
131   return usage_type;
132 }
133
134 /**
135  * GstAmfH264EncRateControl:
136  *
137  * Rate control methods
138  *
139  * Since: 1.22
140  */
141 #define GST_TYPE_AMF_H264_ENC_RATE_CONTROL (gst_amf_h264_enc_rate_control_get_type ())
142 static GType
143 gst_amf_h264_enc_rate_control_get_type (void)
144 {
145   static GType rate_control_type = 0;
146   static const GEnumValue rate_controls[] = {
147     /**
148      * GstAmfH264EncRateControl::default:
149      *
150      * Default rate control method depending on usage
151      */
152     {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN, "Default, depends on Usage",
153         "default"},
154
155     /**
156      * GstAmfH264EncRateControl::cqp:
157      *
158      * Constant QP
159      */
160     {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP, "Constant QP", "cqp"},
161
162     /**
163      * GstAmfH264EncRateControl::cbr:
164      *
165      * Constant Bitrate
166      */
167     {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR, "Constant Bitrate", "cbr"},
168
169     /**
170      * GstAmfH264EncRateControl::vbr:
171      *
172      * Peak Constrained Variable Bitrate
173      */
174     {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
175         "Peak Constrained VBR", "vbr"},
176
177     /**
178      * GstAmfH264EncRateControl::lcvbr:
179      *
180      * Latency Constrained Variable Bitrate
181      */
182     {AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
183         "Latency Constrained VBR", "lcvbr"},
184     {0, nullptr, nullptr}
185   };
186
187   if (g_once_init_enter (&rate_control_type)) {
188     GType type =
189         g_enum_register_static ("GstAmfH264EncRateControl", rate_controls);
190     g_once_init_leave (&rate_control_type, type);
191   }
192
193   return rate_control_type;
194 }
195
196 /**
197  * GstAmfH264EncPreset:
198  *
199  * Encoding quality presets
200  *
201  * Since: 1.22
202  */
203 #define AMF_VIDEO_ENCODER_QUALITY_PRESET_UNKNOWN -1
204 #define GST_TYPE_AMF_H264_ENC_PRESET (gst_amf_h264_enc_preset_get_type ())
205 static GType
206 gst_amf_h264_enc_preset_get_type (void)
207 {
208   static GType preset_type = 0;
209   static const GEnumValue presets[] = {
210     /**
211      * GstAmfH264EncRateControl::default:
212      *
213      * Default preset depends on usage
214      */
215     {AMF_VIDEO_ENCODER_QUALITY_PRESET_UNKNOWN, "Default, depends on USAGE",
216         "default"},
217
218     /**
219      * GstAmfH264EncRateControl::balanced:
220      *
221      * Balanced preset
222      */
223     {AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, "Balanced", "balanced"},
224
225     /**
226      * GstAmfH264EncRateControl::speed:
227      *
228      * Speed oriented preset
229      */
230     {AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED, "Speed", "speed"},
231
232     /**
233      * GstAmfH264EncRateControl::quality:
234      *
235      * Quality oriented preset
236      */
237     {AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, "Quality", "quality"},
238     {0, nullptr, nullptr}
239   };
240
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);
244   }
245
246   return preset_type;
247 }
248
249 typedef struct
250 {
251   GstCaps *sink_caps;
252   GstCaps *src_caps;
253
254   gint64 adapter_luid;
255
256   GstAmfH264EncDeviceCaps dev_caps;
257 } GstAmfH264EncClassData;
258
259 enum
260 {
261   PROP_0,
262   PROP_ADAPTER_LUID,
263   PROP_USAGE,
264   PROP_RATE_CONTROL,
265   PROP_PRESET,
266   PROP_BITRATE,
267   PROP_MAX_BITRATE,
268   PROP_GOP_SIZE,
269   PROP_MIN_QP,
270   PROP_MAX_QP,
271   PROP_QP_I,
272   PROP_QP_P,
273   PROP_REF_FRAMES,
274   PROP_AUD,
275   PROP_CABAC,
276 };
277
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
287
288 typedef struct _GstAmfH264Enc
289 {
290   GstAmfEncoder parent;
291
292   gboolean packetized;
293   GstH264NalParser *parser;
294
295   GMutex prop_lock;
296   gboolean property_updated;
297
298   gint usage;
299   gint rate_control;
300   gint preset;
301   guint bitrate;
302   guint max_bitrate;
303   gint gop_size;
304   gint min_qp;
305   gint max_qp;
306   guint qp_i;
307   guint qp_p;
308   guint ref_frames;
309
310   gboolean aud;
311   gboolean cabac;
312 } GstAmfH264Enc;
313
314 typedef struct _GstAmfH264EncClass
315 {
316   GstAmfEncoderClass parent_class;
317   GstAmfH264EncDeviceCaps dev_caps;
318
319   gint64 adapter_luid;
320 } GstAmfH264EncClass;
321
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))
325
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,
332     GstCaps * filter);
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);
342
343 static void
344 gst_amf_h264_enc_class_init (GstAmfH264EncClass * klass, gpointer data)
345 {
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);
354
355   parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
356
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;
360
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));
415
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>");
421
422   gst_element_class_add_pad_template (element_class,
423       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
424           cdata->sink_caps));
425   gst_element_class_add_pad_template (element_class,
426       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
427           cdata->src_caps));
428
429   videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_amf_h264_enc_getcaps);
430
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);
440
441   klass->dev_caps = cdata->dev_caps;
442   klass->adapter_luid = cdata->adapter_luid;
443
444   gst_caps_unref (cdata->sink_caps);
445   gst_caps_unref (cdata->src_caps);
446   g_free (cdata);
447
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);
454 }
455
456 static void
457 gst_amf_h264_enc_init (GstAmfH264Enc * self)
458 {
459   GstAmfH264EncClass *klass = GST_AMF_H264_ENC_GET_CLASS (self);
460   GstAmfH264EncDeviceCaps *dev_caps = &klass->dev_caps;
461
462   gst_amf_encoder_set_subclass_data (GST_AMF_ENCODER (self),
463       klass->adapter_luid, AMFVideoEncoderVCE_AVC);
464
465   self->parser = gst_h264_nal_parser_new ();
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 = 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;
482 }
483
484 static void
485 gst_amf_h264_enc_finalize (GObject * object)
486 {
487   GstAmfH264Enc *self = GST_AMF_H264_ENC (object);
488
489   gst_h264_nal_parser_free (self->parser);
490   g_mutex_clear (&self->prop_lock);
491
492   G_OBJECT_CLASS (parent_class)->finalize (object);
493 }
494
495 static void
496 update_int (GstAmfH264Enc * self, gint * old_val, const GValue * new_val)
497 {
498   gint val = g_value_get_int (new_val);
499
500   if (*old_val == val)
501     return;
502
503   *old_val = val;
504   self->property_updated = TRUE;
505 }
506
507 static void
508 update_uint (GstAmfH264Enc * self, guint * old_val, const GValue * new_val)
509 {
510   guint val = g_value_get_uint (new_val);
511
512   if (*old_val == val)
513     return;
514
515   *old_val = val;
516   self->property_updated = TRUE;
517 }
518
519 static void
520 update_enum (GstAmfH264Enc * self, gint * old_val, const GValue * new_val)
521 {
522   gint val = g_value_get_enum (new_val);
523
524   if (*old_val == val)
525     return;
526
527   *old_val = val;
528   self->property_updated = TRUE;
529 }
530
531 static void
532 update_bool (GstAmfH264Enc * self, gboolean * old_val, const GValue * new_val)
533 {
534   gboolean val = g_value_get_boolean (new_val);
535
536   if (*old_val == val)
537     return;
538
539   *old_val = val;
540   self->property_updated = TRUE;
541 }
542
543 static void
544 gst_amf_h264_enc_set_property (GObject * object, guint prop_id,
545     const GValue * value, GParamSpec * pspec)
546 {
547   GstAmfH264Enc *self = GST_AMF_H264_ENC (object);
548
549   g_mutex_lock (&self->prop_lock);
550   switch (prop_id) {
551     case PROP_USAGE:
552       update_enum (self, &self->usage, value);
553       break;
554     case PROP_RATE_CONTROL:
555       update_enum (self, &self->rate_control, value);
556       break;
557     case PROP_PRESET:
558       update_enum (self, &self->preset, value);
559       break;
560     case PROP_BITRATE:
561       update_uint (self, &self->bitrate, value);
562       break;
563     case PROP_MAX_BITRATE:
564       update_uint (self, &self->max_bitrate, value);
565       break;
566     case PROP_GOP_SIZE:
567       update_int (self, &self->gop_size, value);
568       break;
569     case PROP_MIN_QP:
570       update_int (self, &self->min_qp, value);
571       break;
572     case PROP_MAX_QP:
573       update_int (self, &self->max_qp, value);
574       break;
575     case PROP_QP_I:
576       update_uint (self, &self->qp_i, value);
577       break;
578     case PROP_QP_P:
579       update_uint (self, &self->qp_p, value);
580       break;
581     case PROP_REF_FRAMES:
582       update_uint (self, &self->ref_frames, value);
583       break;
584     case PROP_AUD:
585       /* This is per frame property, don't need to reset encoder */
586       self->aud = g_value_get_boolean (value);
587       break;
588     case PROP_CABAC:
589       update_bool (self, &self->cabac, value);
590       break;
591     default:
592       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
593       break;
594   }
595   g_mutex_unlock (&self->prop_lock);
596 }
597
598 static void
599 gst_amf_h264_enc_get_property (GObject * object, guint prop_id,
600     GValue * value, GParamSpec * pspec)
601 {
602   GstAmfH264EncClass *klass = GST_AMF_H264_ENC_GET_CLASS (object);
603   GstAmfH264Enc *self = GST_AMF_H264_ENC (object);
604
605   switch (prop_id) {
606     case PROP_ADAPTER_LUID:
607       g_value_set_int64 (value, klass->adapter_luid);
608       break;
609     case PROP_USAGE:
610       g_value_set_enum (value, self->usage);
611       break;
612     case PROP_RATE_CONTROL:
613       g_value_set_enum (value, self->rate_control);
614       break;
615     case PROP_PRESET:
616       g_value_set_enum (value, self->preset);
617       break;
618     case PROP_BITRATE:
619       g_value_set_uint (value, self->bitrate);
620       break;
621     case PROP_MAX_BITRATE:
622       g_value_set_uint (value, self->max_bitrate);
623       break;
624     case PROP_GOP_SIZE:
625       g_value_set_int (value, self->gop_size);
626       break;
627     case PROP_MIN_QP:
628       g_value_set_int (value, self->min_qp);
629       break;
630     case PROP_MAX_QP:
631       g_value_set_int (value, self->max_qp);
632       break;
633     case PROP_QP_I:
634       g_value_set_uint (value, self->qp_i);
635       break;
636     case PROP_QP_P:
637       g_value_set_uint (value, self->qp_p);
638       break;
639     case PROP_REF_FRAMES:
640       g_value_set_uint (value, self->ref_frames);
641       break;
642     case PROP_AUD:
643       g_value_set_boolean (value, self->aud);
644       break;
645     case PROP_CABAC:
646       g_value_set_boolean (value, self->cabac);
647       break;
648     default:
649       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
650       break;
651   }
652 }
653
654 static void
655 gst_amf_h264_enc_get_downstream_profiles_and_format (GstAmfH264Enc * self,
656     std::set < std::string > &downstream_profiles, gboolean * packetized)
657 {
658   GstCaps *allowed_caps;
659   GstStructure *s;
660   const gchar *stream_format;
661
662   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
663
664   if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
665       gst_caps_is_any (allowed_caps)) {
666     gst_clear_caps (&allowed_caps);
667
668     return;
669   }
670
671   for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
672     const GValue *profile_value;
673     const gchar *profile;
674
675     s = gst_caps_get_structure (allowed_caps, i);
676     profile_value = gst_structure_get_value (s, "profile");
677     if (!profile_value)
678       continue;
679
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);
683
684         if (!G_VALUE_HOLDS_STRING (p))
685           continue;
686
687         profile = g_value_get_string (p);
688         if (profile)
689           downstream_profiles.insert (profile);
690       }
691
692     } else if (G_VALUE_HOLDS_STRING (profile_value)) {
693       profile = g_value_get_string (profile_value);
694       if (profile)
695         downstream_profiles.insert (profile);
696     }
697   }
698
699   if (packetized) {
700     *packetized = FALSE;
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)
705       *packetized = TRUE;
706   }
707
708   gst_caps_unref (allowed_caps);
709 }
710
711 static GstCaps *
712 gst_amf_h264_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
713 {
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;
719
720   if (!klass->dev_caps.interlace_supported)
721     return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
722
723   gst_amf_h264_enc_get_downstream_profiles_and_format (self,
724       downstream_profiles, nullptr);
725
726   GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
727       downstream_profiles.size ());
728
729   if (downstream_profiles.size () == 0)
730     return gst_video_encoder_proxy_getcaps (encoder, NULL, filter);
731
732   /* Profile allows interlaced? */
733   /* *INDENT-OFF* */
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;
738       break;
739     }
740   }
741   /* *INDENT-ON* */
742
743   GST_DEBUG_OBJECT (self, "Downstream %s support interlaced format",
744       can_support_interlaced ? "can" : "cannot");
745
746   if (can_support_interlaced) {
747     /* No special handling is needed */
748     return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
749   }
750
751   template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
752   template_caps = gst_caps_make_writable (template_caps);
753
754   gst_caps_set_simple (template_caps, "interlace-mode", G_TYPE_STRING,
755       "progressive", nullptr);
756
757   supported_caps = gst_video_encoder_proxy_getcaps (encoder,
758       template_caps, filter);
759   gst_caps_unref (template_caps);
760
761   GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
762
763   return supported_caps;
764 }
765
766 static gboolean
767 gst_amf_h264_enc_set_format (GstAmfEncoder * encoder,
768     GstVideoCodecState * state, gpointer component)
769 {
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;
777   AMF_RESULT result;
778   AMFRate framerate;
779   AMFRatio aspect_ratio;
780   amf_int64 int64_val;
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;
784
785   self->packetized = FALSE;
786
787   gst_amf_h264_enc_get_downstream_profiles_and_format (self,
788       downstream_profiles, &self->packetized);
789
790   if (downstream_profiles.empty ()) {
791     GST_ERROR_OBJECT (self, "Unable to get downstream profile");
792     return FALSE;
793   }
794
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");
799
800     if (downstream_profiles.empty ()) {
801       GST_ERROR_OBJECT (self,
802           "None of downstream profile supports interlaced encoding");
803       return FALSE;
804     }
805   }
806
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;
816     } else {
817       profile = AMF_VIDEO_ENCODER_PROFILE_HIGH;
818     }
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;
824     } else {
825       profile = AMF_VIDEO_ENCODER_PROFILE_BASELINE;
826     }
827   } else if (downstream_profiles.find ("baseline") !=
828       downstream_profiles.end ()) {
829     profile = AMF_VIDEO_ENCODER_PROFILE_BASELINE;
830   } else {
831     GST_ERROR_OBJECT (self, "Failed to determine profile");
832     return FALSE;
833   }
834
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));
842     goto error;
843   }
844
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));
849     goto error;
850   }
851
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));
858       goto error;
859     }
860   }
861
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));
866     goto error;
867   }
868
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));
874     goto error;
875   }
876
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));
882     goto error;
883   }
884
885   if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255)
886     boolean_val = true;
887   else
888     boolean_val = false;
889
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));
894     goto error;
895   }
896
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));
903       goto error;
904     }
905   }
906
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));
911     goto error;
912   }
913
914   /* dynamic properties */
915   result = comp->GetProperty (AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD,
916       &int64_val);
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));
920     goto error;
921   }
922
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);
928
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);
931
932   switch (rc_mode) {
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);
939       }
940       break;
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);
946       }
947       if (self->max_bitrate > 0) {
948         comp->SetProperty (AMF_VIDEO_ENCODER_PEAK_BITRATE,
949             (amf_int64) self->max_bitrate * 1000);
950       }
951       break;
952     default:
953       break;
954   }
955
956   /* Disable frame skip for now, need investigation the behavior */
957   result = comp->SetProperty (AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE,
958       (amf_bool) false);
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));
962     goto error;
963   }
964
965   if (info->fps_n > 0 && info->fps_d) {
966     framerate = AMFConstructRate (info->fps_n, info->fps_d);
967   } else {
968     framerate = AMFConstructRate (25, 1);
969   }
970
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));
975     goto error;
976   }
977
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));
984       goto error;
985     }
986   }
987
988   if (profile != AMF_VIDEO_ENCODER_PROFILE_BASELINE &&
989       profile != AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE) {
990     if (self->cabac)
991       cabac = AMF_VIDEO_ENCODER_CABAC;
992     else
993       cabac = AMF_VIDEO_ENCODER_CALV;
994   }
995
996   result = comp->SetProperty (AMF_VIDEO_ENCODER_CABAC_ENABLE,
997       (amf_int64) cabac);
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));
1001     goto error;
1002   }
1003
1004   self->property_updated = FALSE;
1005   g_mutex_unlock (&self->prop_lock);
1006
1007   return TRUE;
1008
1009 error:
1010   g_mutex_unlock (&self->prop_lock);
1011
1012   return FALSE;
1013 }
1014
1015 static gboolean
1016 gst_amf_h264_enc_set_output_state (GstAmfEncoder * encoder,
1017     GstVideoCodecState * state, gpointer component)
1018 {
1019   GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1020   AMFComponent *comp = (AMFComponent *) component;
1021   GstVideoCodecState *output_state;
1022   GstCaps *caps;
1023   const gchar *profile_from_sps;
1024   std::set < std::string > downstream_profiles;
1025   std::string caps_str;
1026   GstTagList *tags;
1027   GstBuffer *codec_data = nullptr;
1028   GstH264NalUnit sps_nalu, pps_nalu;
1029   GstH264ParserResult rst;
1030   AMF_RESULT result;
1031   AMFInterfacePtr iface;
1032   AMFBufferPtr spspps_buf;
1033   guint8 *spspps;
1034   amf_size spspps_size;
1035
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));
1040     return FALSE;
1041   }
1042
1043   spspps_buf = AMFBufferPtr (iface);
1044   if (!spspps_buf) {
1045     GST_ERROR_OBJECT (self, "Failed to set get AMFBuffer interface, result %"
1046         GST_AMF_RESULT_FORMAT, GST_AMF_RESULT_ARGS (result));
1047     return FALSE;
1048   }
1049
1050   spspps_size = spspps_buf->GetSize ();
1051   if (spspps_size < 4) {
1052     GST_ERROR_OBJECT (self, "Too small spspps size %d", (guint) spspps_size);
1053     return FALSE;
1054   }
1055
1056   spspps = (guint8 *) spspps_buf->GetNative ();
1057   if (!spspps) {
1058     GST_ERROR_OBJECT (self, "Null SPS/PPS");
1059     return FALSE;
1060   }
1061
1062   caps_str = "video/x-h264, alignment = (string) au";
1063   gst_amf_h264_enc_get_downstream_profiles_and_format (self,
1064       downstream_profiles, nullptr);
1065
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");
1070     return FALSE;
1071   }
1072
1073   if (sps_nalu.size < 4) {
1074     GST_ERROR_OBJECT (self, "Too small sps nal size %d", sps_nalu.size);
1075     return FALSE;
1076   }
1077
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);
1082     return FALSE;
1083   }
1084
1085   if (self->packetized) {
1086     GstMapInfo info;
1087     guint8 *data;
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;
1092
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];
1097
1098     /* 5: configuration version, profile, compatibility, level, nal length
1099      * 1: num sps
1100      * 2: sps size bytes
1101      * sizeof (sps)
1102      * 1: num pps
1103      * 2: pps size bytes
1104      * sizeof (pps)
1105      *
1106      * -> 11 + sps_size + pps_size
1107      */
1108     codec_data = gst_buffer_new_and_alloc (11 + sps_nalu.size + pps_nalu.size);
1109
1110     gst_buffer_map (codec_data, &info, GST_MAP_WRITE);
1111
1112     data = (guint8 *) info.data;
1113     data[0] = 1;
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;
1119     data += 6;
1120     GST_WRITE_UINT16_BE (data, sps_nalu.size);
1121     data += 2;
1122     memcpy (data, sps_nalu.data + sps_nalu.offset, sps_nalu.size);
1123     data += sps_nalu.size;
1124
1125     data[0] = num_pps;
1126     data++;
1127
1128     GST_WRITE_UINT16_BE (data, pps_nalu.size);
1129     data += 2;
1130     memcpy (data, pps_nalu.data + pps_nalu.offset, pps_nalu.size);
1131
1132     gst_buffer_unmap (codec_data, &info);
1133   }
1134
1135   profile_from_sps =
1136       gst_codec_utils_h264_get_profile (sps_nalu.data + sps_nalu.offset +
1137       sps_nalu.header_bytes, 3);
1138
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";
1153     }
1154   } else {
1155     caps_str += ", profile = (string) " + std::string (profile_from_sps);
1156   }
1157
1158   if (self->packetized) {
1159     caps_str += ", stream-format = (string) avc";
1160   } else {
1161     caps_str += ", stream-format = (string) byte-stream";
1162   }
1163
1164   caps = gst_caps_from_string (caps_str.c_str ());
1165
1166   if (self->packetized) {
1167     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data,
1168         nullptr);
1169     gst_buffer_unref (codec_data);
1170   }
1171
1172   output_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1173       caps, state);
1174
1175   GST_INFO_OBJECT (self, "Output caps: %" GST_PTR_FORMAT, output_state->caps);
1176   gst_video_codec_state_unref (output_state);
1177
1178   tags = gst_tag_list_new_empty ();
1179   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1180       "amfh264enc", nullptr);
1181
1182   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
1183       tags, GST_TAG_MERGE_REPLACE);
1184   gst_tag_list_unref (tags);
1185
1186   return TRUE;
1187 }
1188
1189 static gboolean
1190 gst_amf_h264_enc_set_surfrace_prop (GstAmfEncoder * encoder,
1191     GstVideoCodecFrame * frame, gpointer surface)
1192 {
1193   GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1194   AMFSurface *surf = (AMFSurface *) surface;
1195   AMF_RESULT result;
1196   amf_bool insert_aud = self->aud ? true : false;
1197
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));
1204     }
1205   }
1206
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));
1211   }
1212
1213   return TRUE;
1214 }
1215
1216 static GstBuffer *
1217 gst_amf_h264_enc_create_output_buffer (GstAmfEncoder * encoder,
1218     gpointer data, gboolean * sync_point)
1219 {
1220   GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1221   AMFBuffer *amf_buf = (AMFBuffer *) data;
1222   GstBuffer *buf;
1223   GstH264ParserResult rst;
1224   GstH264NalUnit nalu;
1225   guint8 *data_ptr;
1226   gsize data_size;
1227   amf_int64 output_type = 0;
1228   AMF_RESULT result;
1229
1230   data_ptr = (guint8 *) amf_buf->GetNative ();
1231   data_size = amf_buf->GetSize ();
1232
1233   if (!data_ptr || data_size == 0) {
1234     GST_WARNING_OBJECT (self, "Empty buffer");
1235     return nullptr;
1236   }
1237
1238   if (!self->packetized) {
1239     buf = gst_buffer_new_memdup (data_ptr, data_size);
1240   } else {
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;
1246
1247     while (rst == GST_H264_PARSER_OK) {
1248       GstMemory *mem;
1249       guint8 *data;
1250
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);
1254
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);
1258
1259       rst = gst_h264_parser_identify_nalu (self->parser,
1260           data_ptr, nalu.offset + nalu.size, data_size, &nalu);
1261
1262       if (rst == GST_H264_PARSER_NO_NAL_END)
1263         rst = GST_H264_PARSER_OK;
1264     }
1265   }
1266
1267   result = amf_buf->GetProperty (AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE,
1268       &output_type);
1269   if (result == AMF_OK &&
1270       output_type == (amf_int64) AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
1271     *sync_point = TRUE;
1272   }
1273
1274   return buf;
1275 }
1276
1277 static gboolean
1278 gst_amf_h264_enc_check_reconfigure (GstAmfEncoder * encoder)
1279 {
1280   GstAmfH264Enc *self = GST_AMF_H264_ENC (encoder);
1281   gboolean ret;
1282
1283   g_mutex_lock (&self->prop_lock);
1284   ret = self->property_updated;
1285   g_mutex_unlock (&self->prop_lock);
1286
1287   return ret;
1288 }
1289
1290 static GstAmfH264EncClassData *
1291 gst_amf_h264_enc_create_class_data (GstD3D11Device * device,
1292     AMFComponent * comp)
1293 {
1294   AMF_RESULT result;
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;
1310   amf_int32 num_val;
1311   gboolean have_nv12 = FALSE;
1312   gboolean d3d11_supported = FALSE;
1313   gint min_width, max_width, min_height, max_height;
1314   GstCaps *sink_caps;
1315   GstCaps *system_caps;
1316
1317   result = comp->GetCaps (&amf_caps);
1318   if (result != AMF_OK) {
1319     GST_WARNING_OBJECT (device, "Unable to get caps");
1320     return nullptr;
1321   }
1322
1323   result = amf_caps->GetInputCaps (&in_iocaps);
1324   if (result != AMF_OK) {
1325     GST_WARNING_OBJECT (device, "Unable to get input io caps");
1326     return nullptr;
1327   }
1328
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 ();
1333
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);
1338
1339   if (interlace_supported)
1340     dev_caps.interlace_supported = TRUE;
1341
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;
1346     amf_bool native;
1347
1348     result = in_iocaps->GetFormatAt (i, &format, &native);
1349     if (result != AMF_OK)
1350       continue;
1351
1352     GST_INFO_OBJECT (device, "Format %d supported, native %d", format, native);
1353     if (format == AMF_SURFACE_NV12)
1354       have_nv12 = TRUE;
1355   }
1356
1357   if (!have_nv12) {
1358     GST_WARNING_OBJECT (device, "NV12 is not supported");
1359     return nullptr;
1360   }
1361
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;
1366     amf_bool native;
1367
1368     result = in_iocaps->GetMemoryTypeAt (i, &type, &native);
1369     if (result != AMF_OK)
1370       continue;
1371
1372     GST_INFO_OBJECT (device,
1373         "MemoryType %d supported, native %d", type, native);
1374     if (type == AMF_MEMORY_DX11)
1375       d3d11_supported = TRUE;
1376   }
1377
1378   if (!d3d11_supported) {
1379     GST_WARNING_OBJECT (device, "D3D11 is not supported");
1380     return nullptr;
1381   }
1382
1383   result = amf_caps->GetOutputCaps (&out_iocaps);
1384   if (result != AMF_OK) {
1385     GST_WARNING_OBJECT (device, "Unable to get input io caps");
1386     return nullptr;
1387   }
1388
1389   out_iocaps->GetWidthRange (&out_min_width, &out_max_width);
1390   out_iocaps->GetHeightRange (&out_min_height, &out_max_height);
1391
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);
1394
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; \
1401   } \
1402 } G_STMT_END
1403
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
1423
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, \
1430         dev_caps.val); \
1431   } else { \
1432     dev_caps.val = default_val; \
1433   } \
1434 } G_STMT_END
1435
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
1440
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");
1445     max_width = 4096;
1446   }
1447
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");
1452     max_height = 4096;
1453   }
1454
1455   if (dev_caps.max_profile >= (gint64) AMF_VIDEO_ENCODER_PROFILE_BASELINE) {
1456     profiles.insert ("baseline");
1457     profiles.insert ("constrained-baseline");
1458   }
1459
1460   if (dev_caps.max_profile >= (gint64) AMF_VIDEO_ENCODER_PROFILE_MAIN)
1461     profiles.insert ("main");
1462
1463   if (dev_caps.max_profile >= (gint64) AMF_VIDEO_ENCODER_PROFILE_HIGH) {
1464     profiles.insert ("high");
1465   }
1466
1467   if (dev_caps.max_profile >=
1468       (gint64) AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH) {
1469     profiles.insert ("constrained-high");
1470   }
1471
1472   if (profiles.empty ()) {
1473     GST_WARNING_OBJECT (device, "Failed to determine profile support");
1474     return nullptr;
1475   }
1476 #define APPEND_STRING(dst,set,str) G_STMT_START { \
1477   if (set.find(str) != set.end()) { \
1478     if (!first) \
1479       dst += ", "; \
1480     dst += str; \
1481     first = FALSE; \
1482   } \
1483 } G_STMT_END
1484
1485   if (profiles.size () == 1) {
1486     profile_str = "profile = (string) " + *(profiles.begin ());
1487   } else {
1488     gboolean first = TRUE;
1489
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 += " } ";
1497   }
1498 #undef APPEND_STRING
1499
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) + " ]";
1504
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 }";
1508   } else {
1509     sink_caps_str += ", interlace-mode = (string) progressive";
1510   }
1511
1512   src_caps_str = "video/x-h264, " + resolution_str + ", " + profile_str +
1513       ", stream-format = (string) { avc, byte-stream }, alignment = (string) au";
1514
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);
1520
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);
1526
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);
1531
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);
1534
1535   return cdata;
1536 }
1537
1538 void
1539 gst_amf_h264_enc_register_d3d11 (GstPlugin * plugin, GstD3D11Device * device,
1540     gpointer context, guint rank)
1541 {
1542   GstAmfH264EncClassData *cdata;
1543   AMFContext *amf_context = (AMFContext *) context;
1544   AMFFactory *factory = (AMFFactory *) gst_amf_get_factory ();
1545   AMFComponentPtr comp;
1546   AMF_RESULT result;
1547
1548   GST_DEBUG_CATEGORY_INIT (gst_amf_h264_enc_debug, "amfh264enc", 0,
1549       "amfh264enc");
1550
1551   result = factory->CreateComponent (amf_context, AMFVideoEncoderVCE_AVC,
1552       &comp);
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));
1556     return;
1557   }
1558
1559   cdata = gst_amf_h264_enc_create_class_data (device, comp.GetPtr ());
1560   if (!cdata)
1561     return;
1562
1563   GType type;
1564   gchar *type_name;
1565   gchar *feature_name;
1566   GTypeInfo type_info = {
1567     sizeof (GstAmfH264EncClass),
1568     nullptr,
1569     nullptr,
1570     (GClassInitFunc) gst_amf_h264_enc_class_init,
1571     nullptr,
1572     cdata,
1573     sizeof (GstAmfH264Enc),
1574     0,
1575     (GInstanceInitFunc) gst_amf_h264_enc_init,
1576   };
1577
1578   type_name = g_strdup ("GstAmfH264Enc");
1579   feature_name = g_strdup ("amfh264enc");
1580
1581   gint index = 0;
1582   while (g_type_from_name (type_name)) {
1583     index++;
1584     g_free (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);
1588   }
1589
1590   type = g_type_register_static (GST_TYPE_AMF_ENCODER, type_name,
1591       &type_info, (GTypeFlags) 0);
1592
1593   if (rank > 0 && index != 0)
1594     rank--;
1595
1596   if (index != 0)
1597     gst_element_type_set_skip_documentation (type);
1598
1599   if (!gst_element_register (plugin, feature_name, rank, type))
1600     GST_WARNING ("Failed to register plugin '%s'", type_name);
1601
1602   g_free (type_name);
1603   g_free (feature_name);
1604 }