va: Fix struct empty initialization syntax
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / qsv / gstqsvvp9enc.cpp
1 /* GStreamer
2  * Copyright (C) 2021 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-qsvvp9enc
22  * @title: qsvvp9enc
23  *
24  * Intel Quick Sync VP9 encoder
25  *
26  * ## Example launch line
27  * ```
28  * gst-launch-1.0 videotestsrc ! qsvvp9enc ! vp9parse ! matroskamux ! filesink location=out.mkv
29  * ```
30  *
31  * Since: 1.22
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "gstqsvvp9enc.h"
39 #include <vector>
40 #include <string>
41 #include <set>
42 #include <string.h>
43
44 #ifdef G_OS_WIN32
45 #include <gst/d3d11/gstd3d11.h>
46 #else
47 #include <gst/va/gstva.h>
48 #endif
49
50 GST_DEBUG_CATEGORY_STATIC (gst_qsv_vp9_enc_debug);
51 #define GST_CAT_DEFAULT gst_qsv_vp9_enc_debug
52
53 /**
54  * GstQsvVP9EncRateControl:
55  *
56  * Since: 1.22
57  */
58 #define GST_TYPE_QSV_VP9_ENC_RATE_CONTROL (gst_qsv_vp9_enc_rate_control_get_type ())
59 static GType
60 gst_qsv_vp9_enc_rate_control_get_type (void)
61 {
62   static GType rate_control_type = 0;
63   static const GEnumValue rate_controls[] = {
64     /**
65      * GstQsvVP9EncRateControl::cbr:
66      *
67      * Since: 1.22
68      */
69     {MFX_RATECONTROL_CBR, "Constant Bitrate", "cbr"},
70
71     /**
72      * GstQsvVP9EncRateControl::vbr:
73      *
74      * Since: 1.22
75      */
76     {MFX_RATECONTROL_VBR, "Variable Bitrate", "vbr"},
77
78     /**
79      * GstQsvVP9EncRateControl::cqp:
80      *
81      * Since: 1.22
82      */
83     {MFX_RATECONTROL_CQP, "Constant Quantizer", "cqp"},
84
85     /**
86      * GstQsvVP9EncRateControl::icq:
87      *
88      * Since: 1.22
89      */
90     {MFX_RATECONTROL_ICQ, "Intelligent CQP", "icq"},
91     {0, nullptr, nullptr}
92   };
93
94   if (g_once_init_enter (&rate_control_type)) {
95     GType type =
96         g_enum_register_static ("GstQsvVP9EncRateControl", rate_controls);
97     g_once_init_leave (&rate_control_type, type);
98   }
99
100   return rate_control_type;
101 }
102
103 enum
104 {
105   PROP_0,
106   PROP_QP_I,
107   PROP_QP_P,
108   PROP_GOP_SIZE,
109   PROP_REF_FRAMES,
110   PROP_BITRATE,
111   PROP_MAX_BITRATE,
112   PROP_RATE_CONTROL,
113   PROP_ICQ_QUALITY,
114 };
115
116 #define DEFAULT_QP 0
117 #define DEFAULT_GOP_SIZE 0
118 #define DEFAULT_REF_FRAMES 1
119 #define DEFAULT_BITRATE 2000
120 #define DEFAULT_MAX_BITRATE 0
121 #define DEFAULT_RATE_CONTROL MFX_RATECONTROL_VBR
122 #define DEFAULT_IQC_QUALITY 0
123
124 #define DOC_SINK_CAPS_COMM \
125     "format = (string) { NV12, P010_10LE, VUYA, Y410 }, " \
126     "width = (int) [16, 8192 ], " \
127     "height = (int) [16, 8192 ]"
128
129 #define DOC_SINK_CAPS \
130     "video/x-raw(memory:D3D11Memory), " DOC_SINK_CAPS_COMM "; " \
131     "video/x-raw(memory:VAMemory), " DOC_SINK_CAPS_COMM "; " \
132     "video/x-raw, " DOC_SINK_CAPS_COMM
133
134 #define DOC_SRC_CAPS \
135     "video/x-vp9, width = (int) [16, 8192 ], height = (int) [16, 8192 ], " \
136     "profile = (string) { 0, 2, 1, 3 }"
137
138 typedef struct _GstQsvVP9EncClassData
139 {
140   GstCaps *sink_caps;
141   GstCaps *src_caps;
142   guint impl_index;
143   gint64 adapter_luid;
144   gchar *display_path;
145   gchar *description;
146 } GstQsvVP9EncClassData;
147
148 typedef struct _GstQsvVP9Enc
149 {
150   GstQsvEncoder parent;
151
152   mfxExtVP9Param vp9_param;
153
154   mfxU16 profile;
155
156   GMutex prop_lock;
157   /* protected by prop_lock */
158   gboolean bitrate_updated;
159   gboolean property_updated;
160
161   /* properties */
162   guint qp_i;
163   guint qp_p;
164   guint gop_size;
165   guint ref_frames;
166   guint bitrate;
167   guint max_bitrate;
168   mfxU16 rate_control;
169   guint icq_quality;
170 } GstQsvVP9Enc;
171
172 typedef struct _GstQsvVP9EncClass
173 {
174   GstQsvEncoderClass parent_class;
175 } GstQsvVP9EncClass;
176
177 static GstElementClass *parent_class = nullptr;
178
179 #define GST_QSV_VP9_ENC(object) ((GstQsvVP9Enc *) (object))
180 #define GST_QSV_VP9_ENC_GET_CLASS(object) \
181     (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstQsvVP9EncClass))
182
183 static void gst_qsv_vp9_enc_finalize (GObject * object);
184 static void gst_qsv_vp9_enc_set_property (GObject * object, guint prop_id,
185     const GValue * value, GParamSpec * pspec);
186 static void gst_qsv_vp9_enc_get_property (GObject * object, guint prop_id,
187     GValue * value, GParamSpec * pspec);
188
189 static GstCaps *gst_qsv_vp9_enc_getcaps (GstVideoEncoder * encoder,
190     GstCaps * filter);
191
192 static gboolean gst_qsv_vp9_enc_set_format (GstQsvEncoder * encoder,
193     GstVideoCodecState * state, mfxVideoParam * param,
194     GPtrArray * extra_params);
195 static gboolean gst_qsv_vp9_enc_set_output_state (GstQsvEncoder * encoder,
196     GstVideoCodecState * state, mfxSession session);
197 static GstQsvEncoderReconfigure
198 gst_qsv_vp9_enc_check_reconfigure (GstQsvEncoder * encoder, mfxSession session,
199     mfxVideoParam * param, GPtrArray * extra_params);
200
201 static void
202 gst_qsv_vp9_enc_class_init (GstQsvVP9EncClass * klass, gpointer data)
203 {
204   GObjectClass *object_class = G_OBJECT_CLASS (klass);
205   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
206   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
207   GstQsvEncoderClass *qsvenc_class = GST_QSV_ENCODER_CLASS (klass);
208   GstQsvVP9EncClassData *cdata = (GstQsvVP9EncClassData *) data;
209   GstPadTemplate *pad_templ;
210   GstCaps *doc_caps;
211
212   qsvenc_class->codec_id = MFX_CODEC_VP9;
213   qsvenc_class->impl_index = cdata->impl_index;
214   qsvenc_class->adapter_luid = cdata->adapter_luid;
215   qsvenc_class->display_path = cdata->display_path;
216
217   object_class->finalize = gst_qsv_vp9_enc_finalize;
218   object_class->set_property = gst_qsv_vp9_enc_set_property;
219   object_class->get_property = gst_qsv_vp9_enc_get_property;
220
221   g_object_class_install_property (object_class, PROP_QP_I,
222       g_param_spec_uint ("qp-i", "QP I",
223           "Constant quantizer for I frames (0: default)",
224           0, 255, DEFAULT_QP, (GParamFlags)
225           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
226   g_object_class_install_property (object_class, PROP_QP_P,
227       g_param_spec_uint ("qp-p", "QP P",
228           "Constant quantizer for P frames (0: default)",
229           0, 255, DEFAULT_QP, (GParamFlags)
230           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
231   g_object_class_install_property (object_class, PROP_GOP_SIZE,
232       g_param_spec_uint ("gop-size", "GOP Size",
233           "Number of pictures within a GOP (0: unspecified)",
234           0, G_MAXINT, DEFAULT_GOP_SIZE, (GParamFlags)
235           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
236   g_object_class_install_property (object_class, PROP_REF_FRAMES,
237       g_param_spec_uint ("ref-frames", "Reference Frames",
238           "Number of reference frames (0: unspecified)",
239           0, 3, DEFAULT_REF_FRAMES, (GParamFlags)
240           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
241   g_object_class_install_property (object_class, PROP_BITRATE,
242       g_param_spec_uint ("bitrate", "Bitrate",
243           "Target bitrate in kbit/sec, Ignored when selected rate-control mode "
244           "is constant QP variants (i.e., \"cqp\" and \"icq\")",
245           0, G_MAXUINT16, DEFAULT_BITRATE, (GParamFlags)
246           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
247   g_object_class_install_property (object_class, PROP_MAX_BITRATE,
248       g_param_spec_uint ("max-bitrate", "Max Bitrate",
249           "Maximum bitrate in kbit/sec, Ignored when selected rate-control mode "
250           "is constant QP variants (i.e., \"cqp\" and \"icq\")",
251           0, G_MAXUINT16, DEFAULT_MAX_BITRATE, (GParamFlags)
252           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
253   g_object_class_install_property (object_class, PROP_RATE_CONTROL,
254       g_param_spec_enum ("rate-control", "Rate Control",
255           "Rate Control Method", GST_TYPE_QSV_VP9_ENC_RATE_CONTROL,
256           DEFAULT_RATE_CONTROL,
257           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
258   g_object_class_install_property (object_class, PROP_ICQ_QUALITY,
259       g_param_spec_uint ("icq-quality", "ICQ Quality",
260           "Intelligent Constant Quality for \"icq\" rate-control (0: default)",
261           0, 255, DEFAULT_IQC_QUALITY, (GParamFlags)
262           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
263
264   parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
265
266 #ifdef G_OS_WIN32
267   std::string long_name = "Intel Quick Sync Video " +
268       std::string (cdata->description) + " VP9 Encoder";
269
270   gst_element_class_set_metadata (element_class, long_name.c_str (),
271       "Codec/Encoder/Video/Hardware",
272       "Intel Quick Sync Video VP9 Encoder",
273       "Seungha Yang <seungha@centricular.com>");
274 #else
275   gst_element_class_set_static_metadata (element_class,
276       "Intel Quick Sync Video VP9 Encoder",
277       "Codec/Encoder/Video/Hardware",
278       "Intel Quick Sync Video VP9 Encoder",
279       "Seungha Yang <seungha@centricular.com>");
280 #endif
281
282   pad_templ = gst_pad_template_new ("sink",
283       GST_PAD_SINK, GST_PAD_ALWAYS, cdata->sink_caps);
284   doc_caps = gst_caps_from_string (DOC_SINK_CAPS);
285   gst_pad_template_set_documentation_caps (pad_templ, doc_caps);
286   gst_caps_unref (doc_caps);
287   gst_element_class_add_pad_template (element_class, pad_templ);
288
289   pad_templ = gst_pad_template_new ("src",
290       GST_PAD_SRC, GST_PAD_ALWAYS, cdata->src_caps);
291   doc_caps = gst_caps_from_string (DOC_SRC_CAPS);
292   gst_pad_template_set_documentation_caps (pad_templ, doc_caps);
293   gst_caps_unref (doc_caps);
294   gst_element_class_add_pad_template (element_class, pad_templ);
295
296   encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_qsv_vp9_enc_getcaps);
297
298   qsvenc_class->set_format = GST_DEBUG_FUNCPTR (gst_qsv_vp9_enc_set_format);
299   qsvenc_class->set_output_state =
300       GST_DEBUG_FUNCPTR (gst_qsv_vp9_enc_set_output_state);
301   qsvenc_class->check_reconfigure =
302       GST_DEBUG_FUNCPTR (gst_qsv_vp9_enc_check_reconfigure);
303
304   gst_type_mark_as_plugin_api (GST_TYPE_QSV_VP9_ENC_RATE_CONTROL,
305       (GstPluginAPIFlags) 0);
306
307   gst_caps_unref (cdata->sink_caps);
308   gst_caps_unref (cdata->src_caps);
309   g_free (cdata->description);
310   g_free (cdata);
311 }
312
313 static void
314 gst_qsv_vp9_enc_init (GstQsvVP9Enc * self)
315 {
316   self->qp_i = DEFAULT_QP;
317   self->qp_p = DEFAULT_QP;
318   self->gop_size = DEFAULT_GOP_SIZE;
319   self->ref_frames = DEFAULT_REF_FRAMES;
320   self->bitrate = DEFAULT_BITRATE;
321   self->max_bitrate = DEFAULT_MAX_BITRATE;
322   self->rate_control = DEFAULT_RATE_CONTROL;
323   self->icq_quality = DEFAULT_IQC_QUALITY;
324
325   g_mutex_init (&self->prop_lock);
326 }
327
328 static void
329 gst_qsv_vp9_enc_finalize (GObject * object)
330 {
331   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (object);
332
333   g_mutex_clear (&self->prop_lock);
334
335   G_OBJECT_CLASS (parent_class)->finalize (object);
336 }
337
338 static void
339 gst_qsv_vp9_enc_check_update_uint (GstQsvVP9Enc * self, guint * old_val,
340     guint new_val, gboolean is_bitrate_param)
341 {
342   if (*old_val == new_val)
343     return;
344
345   g_mutex_lock (&self->prop_lock);
346   *old_val = new_val;
347   if (is_bitrate_param)
348     self->bitrate_updated = TRUE;
349   else
350     self->property_updated = TRUE;
351   g_mutex_unlock (&self->prop_lock);
352 }
353
354 static void
355 gst_qsv_vp9_enc_check_update_enum (GstQsvVP9Enc * self, mfxU16 * old_val,
356     gint new_val)
357 {
358   if (*old_val == (mfxU16) new_val)
359     return;
360
361   g_mutex_lock (&self->prop_lock);
362   *old_val = (mfxU16) new_val;
363   self->property_updated = TRUE;
364   g_mutex_unlock (&self->prop_lock);
365 }
366
367 static void
368 gst_qsv_vp9_enc_set_property (GObject * object, guint prop_id,
369     const GValue * value, GParamSpec * pspec)
370 {
371   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (object);
372
373   switch (prop_id) {
374     case PROP_QP_I:
375       gst_qsv_vp9_enc_check_update_uint (self, &self->qp_i,
376           g_value_get_uint (value), TRUE);
377       break;
378     case PROP_QP_P:
379       gst_qsv_vp9_enc_check_update_uint (self, &self->qp_p,
380           g_value_get_uint (value), TRUE);
381       break;
382     case PROP_GOP_SIZE:
383       gst_qsv_vp9_enc_check_update_uint (self, &self->gop_size,
384           g_value_get_uint (value), FALSE);
385       break;
386     case PROP_REF_FRAMES:
387       gst_qsv_vp9_enc_check_update_uint (self, &self->ref_frames,
388           g_value_get_uint (value), FALSE);
389       break;
390     case PROP_BITRATE:
391       gst_qsv_vp9_enc_check_update_uint (self, &self->bitrate,
392           g_value_get_uint (value), TRUE);
393       break;
394     case PROP_MAX_BITRATE:
395       gst_qsv_vp9_enc_check_update_uint (self, &self->max_bitrate,
396           g_value_get_uint (value), TRUE);
397       break;
398     case PROP_RATE_CONTROL:
399       gst_qsv_vp9_enc_check_update_enum (self, &self->rate_control,
400           g_value_get_enum (value));
401       break;
402     case PROP_ICQ_QUALITY:
403       gst_qsv_vp9_enc_check_update_uint (self, &self->icq_quality,
404           g_value_get_uint (value), FALSE);
405       break;
406     default:
407       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
408       break;
409   }
410 }
411
412 static void
413 gst_qsv_vp9_enc_get_property (GObject * object, guint prop_id, GValue * value,
414     GParamSpec * pspec)
415 {
416   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (object);
417
418   switch (prop_id) {
419     case PROP_QP_I:
420       g_value_set_uint (value, self->qp_i);
421       break;
422     case PROP_QP_P:
423       g_value_set_uint (value, self->qp_p);
424       break;
425     case PROP_GOP_SIZE:
426       g_value_set_uint (value, self->gop_size);
427       break;
428     case PROP_REF_FRAMES:
429       g_value_set_uint (value, self->ref_frames);
430       break;
431     case PROP_BITRATE:
432       g_value_set_uint (value, self->bitrate);
433       break;
434     case PROP_MAX_BITRATE:
435       g_value_set_uint (value, self->max_bitrate);
436       break;
437     case PROP_RATE_CONTROL:
438       g_value_set_enum (value, self->rate_control);
439       break;
440     case PROP_ICQ_QUALITY:
441       g_value_set_uint (value, self->icq_quality);
442       break;
443     default:
444       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
445       break;
446   }
447 }
448
449 static GstCaps *
450 gst_qsv_vp9_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
451 {
452   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (encoder);
453   GstCaps *allowed_caps;
454   GstCaps *template_caps;
455   GstCaps *supported_caps;
456   std::set < std::string > downstream_profiles;
457
458   allowed_caps = gst_pad_get_allowed_caps (encoder->srcpad);
459
460   /* Shouldn't be any or empty though, just return template caps in this case */
461   if (!allowed_caps || gst_caps_is_empty (allowed_caps) ||
462       gst_caps_is_any (allowed_caps)) {
463     gst_clear_caps (&allowed_caps);
464
465     return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
466   }
467
468   /* Check if downstream specified profile explicitly, then filter out
469    * incompatible raw video format */
470   for (guint i = 0; i < gst_caps_get_size (allowed_caps); i++) {
471     const GValue *profile_value;
472     const gchar *profile;
473     GstStructure *s;
474
475     s = gst_caps_get_structure (allowed_caps, i);
476     profile_value = gst_structure_get_value (s, "profile");
477     if (!profile_value)
478       continue;
479
480     if (GST_VALUE_HOLDS_LIST (profile_value)) {
481       for (guint j = 0; j < gst_value_list_get_size (profile_value); j++) {
482         const GValue *p = gst_value_list_get_value (profile_value, j);
483
484         if (!G_VALUE_HOLDS_STRING (p))
485           continue;
486
487         profile = g_value_get_string (p);
488         if (profile)
489           downstream_profiles.insert (profile);
490       }
491     } else if (G_VALUE_HOLDS_STRING (profile_value)) {
492       profile = g_value_get_string (profile_value);
493       if (g_strcmp0 (profile, "0") == 0 || g_strcmp0 (profile, "1") == 0 ||
494           g_strcmp0 (profile, "2") == 0 || g_strcmp0 (profile, "3") == 0) {
495         downstream_profiles.insert (profile);
496       }
497     }
498   }
499
500   GST_DEBUG_OBJECT (self, "Downstream specified %" G_GSIZE_FORMAT " profiles",
501       downstream_profiles.size ());
502
503   /* Caps returned by gst_pad_get_allowed_caps() should hold profile field
504    * already */
505   if (downstream_profiles.size () == 0) {
506     GST_WARNING_OBJECT (self,
507         "Allowed caps holds no profile field %" GST_PTR_FORMAT, allowed_caps);
508
509     gst_clear_caps (&allowed_caps);
510
511     return gst_video_encoder_proxy_getcaps (encoder, nullptr, filter);
512   }
513
514   gst_clear_caps (&allowed_caps);
515
516   template_caps = gst_pad_get_pad_template_caps (encoder->sinkpad);
517   template_caps = gst_caps_make_writable (template_caps);
518
519   if (downstream_profiles.size () == 1) {
520     std::string format;
521     const std::string & profile = *downstream_profiles.begin ();
522
523     if (profile == "0") {
524       format = "NV12";
525     } else if (profile == "1") {
526       format = "VUYA";
527     } else if (profile == "2") {
528       format = "P010_10LE";
529     } else if (profile == "3") {
530       format = "Y410";
531     } else {
532       gst_clear_caps (&template_caps);
533       g_assert_not_reached ();
534       return nullptr;
535     }
536
537     gst_caps_set_simple (template_caps, "format", G_TYPE_STRING,
538         format.c_str (), nullptr);
539   } else {
540     GValue formats = G_VALUE_INIT;
541
542     g_value_init (&formats, GST_TYPE_LIST);
543
544     /* *INDENT-OFF* */
545     for (const auto & iter : downstream_profiles) {
546       GValue val = G_VALUE_INIT;
547       g_value_init (&val, G_TYPE_STRING);
548       if (iter == "0") {
549         g_value_set_static_string (&val, "NV12");
550       } else if (iter == "1") {
551         g_value_set_static_string (&val, "VUYA");
552       } else if (iter == "2") {
553         g_value_set_static_string (&val, "P010_10LE");
554       } else if (iter == "3") {
555         g_value_set_static_string (&val, "Y410");
556       } else {
557         g_value_unset (&val);
558         gst_clear_caps (&template_caps);
559         g_assert_not_reached ();
560         return nullptr;
561       }
562
563       gst_value_list_append_and_take_value (&formats, &val);
564     }
565     /* *INDENT-ON* */
566
567     gst_caps_set_value (template_caps, "format", &formats);
568     g_value_unset (&formats);
569   }
570
571   supported_caps = gst_video_encoder_proxy_getcaps (encoder,
572       template_caps, filter);
573   gst_caps_unref (template_caps);
574
575   GST_DEBUG_OBJECT (self, "Returning %" GST_PTR_FORMAT, supported_caps);
576
577   return supported_caps;
578 }
579
580 typedef struct
581 {
582   mfxU16 profile;
583   const gchar *profile_str;
584   const gchar *raw_format;
585 } VP9Profile;
586
587 static const VP9Profile profile_map[] = {
588   /* preference order */
589   {MFX_PROFILE_VP9_0, "0", "NV12"},
590   {MFX_PROFILE_VP9_2, "2", "P010_10LE"},
591   {MFX_PROFILE_VP9_1, "1", "VUYA"},
592   {MFX_PROFILE_VP9_3, "3", "Y410"},
593 };
594
595 static const gchar *
596 gst_qsv_vp9_profile_to_string (mfxU16 profile)
597 {
598   for (guint i = 0; i < G_N_ELEMENTS (profile_map); i++) {
599     if (profile_map[i].profile == profile)
600       return profile_map[i].profile_str;
601   }
602
603   return nullptr;
604 }
605
606 static void
607 gst_qsv_vp9_enc_init_vp9_param (mfxExtVP9Param * param)
608 {
609   memset (param, 0, sizeof (mfxExtVP9Param));
610
611   param->Header.BufferId = MFX_EXTBUFF_VP9_PARAM;
612   param->Header.BufferSz = sizeof (mfxExtVP9Param);
613 }
614
615 static void
616 gst_qsv_vp9_enc_set_bitrate (GstQsvVP9Enc * self, mfxVideoParam * param)
617 {
618   switch (param->mfx.RateControlMethod) {
619     case MFX_RATECONTROL_CBR:
620       param->mfx.TargetKbps = param->mfx.MaxKbps = self->bitrate;
621       param->mfx.BRCParamMultiplier = 1;
622       break;
623     case MFX_RATECONTROL_VBR:
624       param->mfx.TargetKbps = self->bitrate;
625       param->mfx.MaxKbps = self->max_bitrate;
626       param->mfx.BRCParamMultiplier = 1;
627       break;
628     case MFX_RATECONTROL_CQP:
629       param->mfx.QPI = self->qp_i;
630       param->mfx.QPP = self->qp_p;
631       break;
632     case MFX_RATECONTROL_ICQ:
633       param->mfx.ICQQuality = self->icq_quality;
634       break;
635     default:
636       GST_WARNING_OBJECT (self,
637           "Unhandled rate-control method %d", self->rate_control);
638       break;
639   }
640 }
641
642 static gboolean
643 gst_qsv_vp9_enc_set_format (GstQsvEncoder * encoder,
644     GstVideoCodecState * state, mfxVideoParam * param, GPtrArray * extra_params)
645 {
646   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (encoder);
647   mfxU16 mfx_profile = MFX_PROFILE_UNKNOWN;
648   GstVideoInfo *info = &state->info;
649   mfxExtVP9Param *vp9_param;
650   mfxFrameInfo *frame_info;
651
652   frame_info = &param->mfx.FrameInfo;
653
654   /* QSV expects this resolution, but actual coded frame resolution will be
655    * signalled via mfxExtVP9Param */
656   frame_info->Width = frame_info->CropW = GST_ROUND_UP_16 (info->width);
657   frame_info->Height = frame_info->CropH = GST_ROUND_UP_16 (info->height);
658
659   frame_info->PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
660
661   if (GST_VIDEO_INFO_FPS_N (info) > 0 && GST_VIDEO_INFO_FPS_D (info) > 0) {
662     frame_info->FrameRateExtN = GST_VIDEO_INFO_FPS_N (info);
663     frame_info->FrameRateExtD = GST_VIDEO_INFO_FPS_D (info);
664   } else {
665     /* HACK: Same as x264enc */
666     frame_info->FrameRateExtN = 25;
667     frame_info->FrameRateExtD = 1;
668   }
669
670   frame_info->AspectRatioW = GST_VIDEO_INFO_PAR_N (info);
671   frame_info->AspectRatioH = GST_VIDEO_INFO_PAR_D (info);
672
673   switch (GST_VIDEO_INFO_FORMAT (info)) {
674     case GST_VIDEO_FORMAT_NV12:
675       mfx_profile = MFX_PROFILE_VP9_0;
676       frame_info->ChromaFormat = MFX_CHROMAFORMAT_YUV420;
677       frame_info->FourCC = MFX_FOURCC_NV12;
678       frame_info->BitDepthLuma = 8;
679       frame_info->BitDepthChroma = 8;
680       frame_info->Shift = 0;
681       break;
682     case GST_VIDEO_FORMAT_VUYA:
683       mfx_profile = MFX_PROFILE_VP9_1;
684       frame_info->ChromaFormat = MFX_CHROMAFORMAT_YUV444;
685       frame_info->FourCC = MFX_FOURCC_AYUV;
686       frame_info->BitDepthLuma = 8;
687       frame_info->BitDepthChroma = 8;
688       frame_info->Shift = 0;
689       break;
690     case GST_VIDEO_FORMAT_P010_10LE:
691       mfx_profile = MFX_PROFILE_VP9_2;
692       frame_info->ChromaFormat = MFX_CHROMAFORMAT_YUV420;
693       frame_info->FourCC = MFX_FOURCC_P010;
694       frame_info->BitDepthLuma = 10;
695       frame_info->BitDepthChroma = 10;
696       frame_info->Shift = 1;
697       break;
698     case GST_VIDEO_FORMAT_Y410:
699       mfx_profile = MFX_PROFILE_VP9_3;
700       frame_info->ChromaFormat = MFX_CHROMAFORMAT_YUV444;
701       frame_info->FourCC = MFX_FOURCC_Y410;
702       frame_info->BitDepthLuma = 10;
703       frame_info->BitDepthChroma = 10;
704       frame_info->Shift = 0;
705       break;
706     default:
707       GST_ERROR_OBJECT (self, "Unexpected format %s",
708           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
709       return FALSE;
710   }
711
712   gst_qsv_vp9_enc_init_vp9_param (&self->vp9_param);
713   vp9_param = &self->vp9_param;
714
715   vp9_param->FrameWidth = GST_VIDEO_INFO_WIDTH (info);
716   vp9_param->FrameHeight = GST_VIDEO_INFO_HEIGHT (info);
717
718   /* We will always output raw VP9 frames */
719   vp9_param->WriteIVFHeaders = MFX_CODINGOPTION_OFF;
720
721   g_mutex_lock (&self->prop_lock);
722   param->mfx.CodecId = MFX_CODEC_VP9;
723   param->mfx.CodecProfile = mfx_profile;
724   param->mfx.GopRefDist = 1;
725   param->mfx.GopPicSize = self->gop_size;
726   param->mfx.RateControlMethod = self->rate_control;
727   param->mfx.NumRefFrame = self->ref_frames;
728
729   gst_qsv_vp9_enc_set_bitrate (self, param);
730
731   g_ptr_array_add (extra_params, vp9_param);
732
733   param->ExtParam = (mfxExtBuffer **) extra_params->pdata;
734   param->NumExtParam = extra_params->len;
735
736   self->bitrate_updated = FALSE;
737   self->property_updated = FALSE;
738
739   g_mutex_unlock (&self->prop_lock);
740
741   return TRUE;
742 }
743
744 static gboolean
745 gst_qsv_vp9_enc_set_output_state (GstQsvEncoder * encoder,
746     GstVideoCodecState * state, mfxSession session)
747 {
748   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (encoder);
749   GstCaps *caps;
750   GstTagList *tags;
751   GstVideoCodecState *out_state;
752   guint bitrate, max_bitrate;
753   mfxVideoParam param;
754   const gchar *profile_str;
755   mfxStatus status;
756
757   memset (&param, 0, sizeof (mfxVideoParam));
758   status = MFXVideoENCODE_GetVideoParam (session, &param);
759   if (status < MFX_ERR_NONE) {
760     GST_ERROR_OBJECT (self, "Failed to get video param %d (%s)",
761         QSV_STATUS_ARGS (status));
762     return FALSE;
763   } else if (status != MFX_ERR_NONE) {
764     GST_WARNING_OBJECT (self, "GetVideoParam returned warning %d (%s)",
765         QSV_STATUS_ARGS (status));
766   }
767
768   caps = gst_caps_from_string ("video/x-vp9");
769   profile_str = gst_qsv_vp9_profile_to_string (param.mfx.CodecProfile);
770   if (profile_str)
771     gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_str, nullptr);
772
773   out_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder),
774       caps, state);
775   gst_video_codec_state_unref (out_state);
776
777   tags = gst_tag_list_new_empty ();
778   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "qsvvp9enc",
779       nullptr);
780
781   switch (param.mfx.RateControlMethod) {
782     case MFX_RATECONTROL_CQP:
783     case MFX_RATECONTROL_ICQ:
784       /* We don't know target/max bitrate in this case */
785       break;
786     default:
787       max_bitrate = (guint) param.mfx.MaxKbps;
788       bitrate = (guint) param.mfx.TargetKbps;
789       if (bitrate > 0) {
790         gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
791             GST_TAG_NOMINAL_BITRATE, bitrate * 1000, nullptr);
792       }
793
794       if (max_bitrate > 0) {
795         gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
796             GST_TAG_MAXIMUM_BITRATE, max_bitrate * 1000, nullptr);
797       }
798       break;
799   }
800
801   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder),
802       tags, GST_TAG_MERGE_REPLACE);
803   gst_tag_list_unref (tags);
804
805   return TRUE;
806 }
807
808 static GstQsvEncoderReconfigure
809 gst_qsv_vp9_enc_check_reconfigure (GstQsvEncoder * encoder, mfxSession session,
810     mfxVideoParam * param, GPtrArray * extra_params)
811 {
812   GstQsvVP9Enc *self = GST_QSV_VP9_ENC (encoder);
813   GstQsvEncoderReconfigure ret = GST_QSV_ENCODER_RECONFIGURE_NONE;
814
815   g_mutex_lock (&self->prop_lock);
816   if (self->property_updated) {
817     ret = GST_QSV_ENCODER_RECONFIGURE_FULL;
818     goto done;
819   }
820
821   if (self->bitrate_updated) {
822     /* VP9 does not support query with MFX_EXTBUFF_ENCODER_RESET_OPTION
823      * Just return GST_QSV_ENCODER_RECONFIGURE_BITRATE here.
824      * Baseclass will care error */
825     gst_qsv_vp9_enc_set_bitrate (self, param);
826
827     ret = GST_QSV_ENCODER_RECONFIGURE_BITRATE;
828   }
829
830 done:
831   self->property_updated = FALSE;
832   self->bitrate_updated = FALSE;
833   g_mutex_unlock (&self->prop_lock);
834
835   return ret;
836 }
837
838 void
839 gst_qsv_vp9_enc_register (GstPlugin * plugin, guint rank, guint impl_index,
840     GstObject * device, mfxSession session)
841 {
842   mfxVideoParam param;
843   mfxInfoMFX *mfx;
844   std::vector < mfxU16 > supported_profiles;
845   std::vector < std::string > supported_formats;
846   GstQsvResolution max_resolution;
847   mfxExtVP9Param vp9_param;
848   mfxExtBuffer *ext_bufs[1];
849
850   GST_DEBUG_CATEGORY_INIT (gst_qsv_vp9_enc_debug, "qsvvp9enc", 0, "qsvvp9enc");
851
852   memset (&param, 0, sizeof (mfxVideoParam));
853   memset (&max_resolution, 0, sizeof (GstQsvResolution));
854
855   ext_bufs[0] = (mfxExtBuffer *) & vp9_param;
856
857   param.AsyncDepth = 4;
858   param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
859
860   mfx = &param.mfx;
861   mfx->LowPower = MFX_CODINGOPTION_UNKNOWN;
862   mfx->CodecId = MFX_CODEC_VP9;
863
864   mfx->FrameInfo.Width = mfx->FrameInfo.CropW = GST_ROUND_UP_16 (320);
865   mfx->FrameInfo.Height = mfx->FrameInfo.CropH = GST_ROUND_UP_16 (240);
866   mfx->FrameInfo.FrameRateExtN = 30;
867   mfx->FrameInfo.FrameRateExtD = 1;
868   mfx->FrameInfo.AspectRatioW = 1;
869   mfx->FrameInfo.AspectRatioH = 1;
870   mfx->FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
871
872   param.NumExtParam = 1;
873   param.ExtParam = ext_bufs;
874
875   for (guint i = 0; i < G_N_ELEMENTS (profile_map); i++) {
876     mfx->CodecProfile = profile_map[i].profile;
877
878     gst_qsv_vp9_enc_init_vp9_param (&vp9_param);
879     vp9_param.FrameWidth = 320;
880     vp9_param.FrameHeight = 240;
881
882     vp9_param.WriteIVFHeaders = MFX_CODINGOPTION_OFF;
883
884     switch (mfx->CodecProfile) {
885       case MFX_PROFILE_VP9_0:
886         mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
887         mfx->FrameInfo.FourCC = MFX_FOURCC_NV12;
888         mfx->FrameInfo.BitDepthLuma = 8;
889         mfx->FrameInfo.BitDepthChroma = 8;
890         mfx->FrameInfo.Shift = 0;
891         break;
892       case MFX_PROFILE_VP9_1:
893         mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
894         mfx->FrameInfo.FourCC = MFX_FOURCC_AYUV;
895         mfx->FrameInfo.BitDepthLuma = 8;
896         mfx->FrameInfo.BitDepthChroma = 8;
897         mfx->FrameInfo.Shift = 0;
898         break;
899       case MFX_PROFILE_VP9_2:
900         mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
901         mfx->FrameInfo.FourCC = MFX_FOURCC_P010;
902         mfx->FrameInfo.BitDepthLuma = 10;
903         mfx->FrameInfo.BitDepthChroma = 10;
904         mfx->FrameInfo.Shift = 1;
905         break;
906       case MFX_PROFILE_VP9_3:
907         mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
908         mfx->FrameInfo.FourCC = MFX_FOURCC_Y410;
909         mfx->FrameInfo.BitDepthLuma = 10;
910         mfx->FrameInfo.BitDepthChroma = 10;
911         mfx->FrameInfo.Shift = 0;
912         break;
913       default:
914         g_assert_not_reached ();
915         return;
916     }
917
918     if (MFXVideoENCODE_Query (session, &param, &param) != MFX_ERR_NONE)
919       continue;
920
921     supported_profiles.push_back (profile_map[i].profile);
922     supported_formats.push_back (profile_map[i].raw_format);
923   }
924
925   if (supported_profiles.empty ()) {
926     GST_INFO ("Device doesn't support VP9 encoding");
927     return;
928   }
929
930   mfx->CodecProfile = MFX_PROFILE_VP9_0;
931   mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
932   mfx->FrameInfo.FourCC = MFX_FOURCC_NV12;
933   mfx->FrameInfo.BitDepthLuma = 8;
934   mfx->FrameInfo.BitDepthChroma = 8;
935   mfx->FrameInfo.Shift = 0;
936
937   /* Check max-resolution */
938   for (guint i = 0; i < G_N_ELEMENTS (gst_qsv_resolutions); i++) {
939     mfx->FrameInfo.Width = mfx->FrameInfo.CropW =
940         GST_ROUND_UP_16 (gst_qsv_resolutions[i].width);
941     mfx->FrameInfo.Height = mfx->FrameInfo.CropH =
942         GST_ROUND_UP_16 (gst_qsv_resolutions[i].height);
943
944     gst_qsv_vp9_enc_init_vp9_param (&vp9_param);
945
946     vp9_param.FrameWidth = gst_qsv_resolutions[i].width;
947     vp9_param.FrameHeight = gst_qsv_resolutions[i].height;
948
949     vp9_param.WriteIVFHeaders = MFX_CODINGOPTION_OFF;
950
951     if (MFXVideoENCODE_Query (session, &param, &param) != MFX_ERR_NONE)
952       break;
953
954     max_resolution.width = gst_qsv_resolutions[i].width;
955     max_resolution.height = gst_qsv_resolutions[i].height;
956   }
957
958   GST_INFO ("Maximum supported resolution: %dx%d",
959       max_resolution.width, max_resolution.height);
960
961   /* TODO: check supported rate-control methods and expose only supported
962    * methods, since the device might not be able to support some of them */
963
964   /* To cover both landscape and portrait,
965    * select max value (width in this case) */
966   guint resolution = MAX (max_resolution.width, max_resolution.height);
967   std::string sink_caps_str = "video/x-raw";
968
969   sink_caps_str += ", width=(int) [ 16, " + std::to_string (resolution) + " ]";
970   sink_caps_str += ", height=(int) [ 16, " + std::to_string (resolution) + " ]";
971
972   /* *INDENT-OFF* */
973   if (supported_formats.size () > 1) {
974     sink_caps_str += ", format=(string) { ";
975     bool first = true;
976     for (const auto &iter: supported_formats) {
977       if (!first) {
978         sink_caps_str += ", ";
979       }
980
981       sink_caps_str += iter;
982       first = false;
983     }
984     sink_caps_str += " }";
985   } else {
986     sink_caps_str += ", format=(string) " + supported_formats[0];
987   }
988   /* *INDENT-ON* */
989
990   GstCaps *sink_caps = gst_caps_from_string (sink_caps_str.c_str ());
991
992   /* TODO: Add support for VA */
993 #ifdef G_OS_WIN32
994   GstCaps *d3d11_caps = gst_caps_copy (sink_caps);
995   GstCapsFeatures *caps_features =
996       gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr);
997   gst_caps_set_features_simple (d3d11_caps, caps_features);
998   gst_caps_append (d3d11_caps, sink_caps);
999   sink_caps = d3d11_caps;
1000 #else
1001   GstCaps *va_caps = gst_caps_copy (sink_caps);
1002   GstCapsFeatures *caps_features =
1003       gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VA, nullptr);
1004   gst_caps_set_features_simple (va_caps, caps_features);
1005   gst_caps_append (va_caps, sink_caps);
1006   sink_caps = va_caps;
1007 #endif
1008
1009   std::string src_caps_str = "video/x-vp9";
1010   src_caps_str += ", width=(int) [ 16, " + std::to_string (resolution) + " ]";
1011   src_caps_str += ", height=(int) [ 16, " + std::to_string (resolution) + " ]";
1012
1013   /* *INDENT-OFF* */
1014   if (supported_profiles.size () > 1) {
1015     src_caps_str += ", profile=(string) { ";
1016     bool first = true;
1017     for (const auto &iter: supported_profiles) {
1018       if (!first) {
1019         src_caps_str += ", ";
1020       }
1021
1022       src_caps_str += gst_qsv_vp9_profile_to_string (iter);
1023       first = false;
1024     }
1025     src_caps_str += " }";
1026   } else {
1027     src_caps_str += ", profile=(string) ";
1028     src_caps_str += gst_qsv_vp9_profile_to_string (supported_profiles[0]);
1029   }
1030   /* *INDENT-ON* */
1031
1032   GstCaps *src_caps = gst_caps_from_string (src_caps_str.c_str ());
1033
1034   GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1035   GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1036
1037   GstQsvVP9EncClassData *cdata = g_new0 (GstQsvVP9EncClassData, 1);
1038   cdata->sink_caps = sink_caps;
1039   cdata->src_caps = src_caps;
1040   cdata->impl_index = impl_index;
1041
1042 #ifdef G_OS_WIN32
1043   g_object_get (device, "adapter-luid", &cdata->adapter_luid,
1044       "description", &cdata->description, nullptr);
1045 #else
1046   g_object_get (device, "path", &cdata->display_path, nullptr);
1047 #endif
1048
1049   GType type;
1050   gchar *type_name;
1051   gchar *feature_name;
1052   GTypeInfo type_info = {
1053     sizeof (GstQsvVP9EncClass),
1054     nullptr,
1055     nullptr,
1056     (GClassInitFunc) gst_qsv_vp9_enc_class_init,
1057     nullptr,
1058     cdata,
1059     sizeof (GstQsvVP9Enc),
1060     0,
1061     (GInstanceInitFunc) gst_qsv_vp9_enc_init,
1062   };
1063
1064   type_name = g_strdup ("GstQsvVP9Enc");
1065   feature_name = g_strdup ("qsvvp9enc");
1066
1067   gint index = 0;
1068   while (g_type_from_name (type_name)) {
1069     index++;
1070     g_free (type_name);
1071     g_free (feature_name);
1072     type_name = g_strdup_printf ("GstQsvVP9Device%dEnc", index);
1073     feature_name = g_strdup_printf ("qsvvp9device%denc", index);
1074   }
1075
1076   type = g_type_register_static (GST_TYPE_QSV_ENCODER, type_name, &type_info,
1077       (GTypeFlags) 0);
1078
1079   if (rank > 0 && index != 0)
1080     rank--;
1081
1082   if (index != 0)
1083     gst_element_type_set_skip_documentation (type);
1084
1085   if (!gst_element_register (plugin, feature_name, rank, type))
1086     GST_WARNING ("Failed to register plugin '%s'", type_name);
1087
1088   g_free (type_name);
1089   g_free (feature_name);
1090 }