• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2020 Seungha Yang <seungha.yang@navercorp.com>
3  * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:element-mfh265enc
23  * @title: mfh265enc
24  *
25  * This element encodes raw video into H265 (HEVC) compressed data.
26  *
27  * ## Example pipelines
28  * |[
29  * gst-launch-1.0 -v videotestsrc ! mfh265enc ! h265parse ! qtmux ! filesink location=videotestsrc.mp4
30  * ]| This example pipeline will encode a test video source to H265 using
31  * Media Foundation encoder, and muxes it in a mp4 container.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <gst/gst.h>
39 #include "gstmfvideoenc.h"
40 #include "gstmfh265enc.h"
41 #include <wrl.h>
42 
43 /* *INDENT-OFF* */
44 using namespace Microsoft::WRL;
45 /* *INDENT-ON* */
46 
47 GST_DEBUG_CATEGORY (gst_mf_h265_enc_debug);
48 #define GST_CAT_DEFAULT gst_mf_h265_enc_debug
49 
50 enum
51 {
52   GST_MF_H265_ENC_RC_MODE_CBR = 0,
53   GST_MF_H265_ENC_RC_MODE_QUALITY,
54 };
55 
56 #define GST_TYPE_MF_H265_ENC_RC_MODE (gst_mf_h265_enc_rc_mode_get_type())
57 static GType
gst_mf_h265_enc_rc_mode_get_type(void)58 gst_mf_h265_enc_rc_mode_get_type (void)
59 {
60   static GType rc_mode_type = 0;
61 
62   static const GEnumValue rc_mode_types[] = {
63     {GST_MF_H265_ENC_RC_MODE_CBR, "Constant bitrate", "cbr"},
64     {GST_MF_H265_ENC_RC_MODE_QUALITY, "Quality-based variable bitrate", "qvbr"},
65     {0, NULL, NULL}
66   };
67 
68   if (!rc_mode_type) {
69     rc_mode_type = g_enum_register_static ("GstMFH265EncRCMode", rc_mode_types);
70   }
71   return rc_mode_type;
72 }
73 
74 enum
75 {
76   GST_MF_H265_ENC_CONTENT_TYPE_UNKNOWN,
77   GST_MF_H265_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE,
78 };
79 
80 #define GST_TYPE_MF_H265_ENC_CONTENT_TYPE (gst_mf_h265_enc_content_type_get_type())
81 static GType
gst_mf_h265_enc_content_type_get_type(void)82 gst_mf_h265_enc_content_type_get_type (void)
83 {
84   static GType content_type = 0;
85 
86   static const GEnumValue content_types[] = {
87     {GST_MF_H265_ENC_CONTENT_TYPE_UNKNOWN, "Unknown", "unknown"},
88     {GST_MF_H265_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE,
89         "Fixed Camera Angle, such as a webcam", "fixed"},
90     {0, NULL, NULL}
91   };
92 
93   if (!content_type) {
94     content_type =
95         g_enum_register_static ("GstMFH265EncContentType", content_types);
96   }
97   return content_type;
98 }
99 
100 enum
101 {
102   PROP_0,
103   PROP_BITRATE,
104   PROP_RC_MODE,
105   PROP_BUFFER_SIZE,
106   PROP_MAX_BITRATE,
107   PROP_QUALITY_VS_SPEED,
108   PROP_BFRAMES,
109   PROP_GOP_SIZE,
110   PROP_THREADS,
111   PROP_CONTENT_TYPE,
112   PROP_QP,
113   PROP_LOW_LATENCY,
114   PROP_MIN_QP,
115   PROP_MAX_QP,
116   PROP_QP_I,
117   PROP_QP_P,
118   PROP_QP_B,
119   PROP_REF,
120   PROP_D3D11_AWARE,
121   PROP_ADAPTER_LUID,
122 };
123 
124 #define DEFAULT_BITRATE (2 * 1024)
125 #define DEFAULT_RC_MODE GST_MF_H265_ENC_RC_MODE_CBR
126 #define DEFAULT_BUFFER_SIZE 0
127 #define DEFAULT_MAX_BITRATE 0
128 #define DEFAULT_QUALITY_VS_SPEED 50
129 #define DEFAULT_CABAC TRUE
130 #define DEFAULT_BFRAMES 0
131 #define DEFAULT_GOP_SIZE -1
132 #define DEFAULT_THREADS 0
133 #define DEFAULT_CONTENT_TYPE GST_MF_H265_ENC_CONTENT_TYPE_UNKNOWN
134 #define DEFAULT_QP 24
135 #define DEFAULT_LOW_LATENCY FALSE
136 #define DEFAULT_MIN_QP 0
137 #define DEFAULT_MAX_QP 51
138 #define DEFAULT_QP_I 26
139 #define DEFAULT_QP_P 26
140 #define DEFAULT_QP_B 26
141 #define DEFAULT_REF 2
142 
143 typedef struct _GstMFH265Enc
144 {
145   GstMFVideoEnc parent;
146 
147   /* properties */
148   guint bitrate;
149 
150   /* device dependent properties */
151   guint rc_mode;
152   guint buffer_size;
153   guint max_bitrate;
154   guint quality_vs_speed;
155   guint bframes;
156   guint gop_size;
157   guint threads;
158   guint content_type;
159   guint qp;
160   gboolean low_latency;
161   guint min_qp;
162   guint max_qp;
163   guint qp_i;
164   guint qp_p;
165   guint qp_b;
166   guint max_num_ref;
167 } GstMFH265Enc;
168 
169 typedef struct _GstMFH265EncClass
170 {
171   GstMFVideoEncClass parent_class;
172 } GstMFH265EncClass;
173 
174 static GstElementClass *parent_class = NULL;
175 
176 static void gst_mf_h265_enc_get_property (GObject * object, guint prop_id,
177     GValue * value, GParamSpec * pspec);
178 static void gst_mf_h265_enc_set_property (GObject * object, guint prop_id,
179     const GValue * value, GParamSpec * pspec);
180 static gboolean gst_mf_h265_enc_set_option (GstMFVideoEnc * mfenc,
181     GstVideoCodecState * state, IMFMediaType * output_type);
182 static gboolean gst_mf_h265_enc_set_src_caps (GstMFVideoEnc * mfenc,
183     GstVideoCodecState * state, IMFMediaType * output_type);
184 
185 static void
gst_mf_h265_enc_class_init(GstMFH265EncClass * klass,gpointer data)186 gst_mf_h265_enc_class_init (GstMFH265EncClass * klass, gpointer data)
187 {
188   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
189   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
190   GstMFVideoEncClass *mfenc_class = GST_MF_VIDEO_ENC_CLASS (klass);
191   GstMFVideoEncClassData *cdata = (GstMFVideoEncClassData *) data;
192   GstMFVideoEncDeviceCaps *device_caps = &cdata->device_caps;
193   gchar *long_name;
194   gchar *classification;
195 
196   parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
197 
198   gobject_class->get_property = gst_mf_h265_enc_get_property;
199   gobject_class->set_property = gst_mf_h265_enc_set_property;
200 
201   g_object_class_install_property (gobject_class, PROP_BITRATE,
202       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
203           (G_MAXUINT >> 10), DEFAULT_BITRATE,
204           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
205 
206   if (device_caps->rc_mode) {
207     g_object_class_install_property (gobject_class, PROP_RC_MODE,
208         g_param_spec_enum ("rc-mode", "Rate Control Mode",
209             "Rate Control Mode",
210             GST_TYPE_MF_H265_ENC_RC_MODE, DEFAULT_RC_MODE,
211             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
212                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
213 
214     /* NOTE: documentation will be done by only for default device */
215     if (cdata->is_default) {
216       gst_type_mark_as_plugin_api (GST_TYPE_MF_H265_ENC_RC_MODE,
217           (GstPluginAPIFlags) 0);
218     }
219   }
220 
221   if (device_caps->buffer_size) {
222     g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
223         g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
224             "VBV(HRD) Buffer Size in bytes (0 = MFT default)",
225             0, G_MAXUINT - 1, DEFAULT_BUFFER_SIZE,
226             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
227                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
228   }
229 
230   if (device_caps->max_bitrate) {
231     g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
232         g_param_spec_uint ("max-bitrate", "Max Bitrate",
233             "The maximum bitrate applied when rc-mode is \"pcvbr\" in kbit/sec "
234             "(0 = MFT default)", 0, (G_MAXUINT >> 10), DEFAULT_MAX_BITRATE,
235             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
236                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
237   }
238 
239   if (device_caps->quality_vs_speed) {
240     g_object_class_install_property (gobject_class, PROP_QUALITY_VS_SPEED,
241         g_param_spec_uint ("quality-vs-speed", "Quality Vs Speed",
242             "Quality and speed tradeoff, [0, 33]: Low complexity, "
243             "[34, 66]: Medium complexity, [67, 100]: High complexity",
244             0, 100, DEFAULT_QUALITY_VS_SPEED,
245             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
246                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
247   }
248 
249   if (device_caps->bframes) {
250     g_object_class_install_property (gobject_class, PROP_BFRAMES,
251         g_param_spec_uint ("bframes", "bframes",
252             "The maximum number of consecutive B frames",
253             0, 2, DEFAULT_BFRAMES,
254             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
255                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
256   }
257 
258   if (device_caps->gop_size) {
259     g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
260         g_param_spec_int ("gop-size", "GOP size",
261             "The number of pictures from one GOP header to the next. "
262             "Depending on GPU vendor implementation, zero gop-size might "
263             "produce only one keyframe at the beginning (-1 for automatic)",
264             -1, G_MAXINT, DEFAULT_GOP_SIZE,
265             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
266                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
267   }
268 
269   if (device_caps->threads) {
270     g_object_class_install_property (gobject_class, PROP_THREADS,
271         g_param_spec_uint ("threads", "Threads",
272             "The number of worker threads used by a encoder, (0 = MFT default)",
273             0, 16, DEFAULT_THREADS,
274             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
275                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
276   }
277 
278   if (device_caps->content_type) {
279     g_object_class_install_property (gobject_class, PROP_CONTENT_TYPE,
280         g_param_spec_enum ("content-type", "Content Type",
281             "Indicates the type of video content",
282             GST_TYPE_MF_H265_ENC_CONTENT_TYPE, DEFAULT_CONTENT_TYPE,
283             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
284                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
285 
286     /* NOTE: documentation will be done by only for default device */
287     if (cdata->is_default) {
288       gst_type_mark_as_plugin_api (GST_TYPE_MF_H265_ENC_CONTENT_TYPE,
289           (GstPluginAPIFlags) 0);
290     }
291   }
292 
293   if (device_caps->qp) {
294     g_object_class_install_property (gobject_class, PROP_QP,
295         g_param_spec_uint ("qp", "qp",
296             "QP applied when rc-mode is \"qvbr\"", 16, 51, DEFAULT_QP,
297             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
298                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
299   }
300 
301   if (device_caps->low_latency) {
302     g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
303         g_param_spec_boolean ("low-latency", "Low Latency",
304             "Enable low latency encoding", DEFAULT_LOW_LATENCY,
305             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
306                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
307   }
308 
309   if (device_caps->min_qp) {
310     g_object_class_install_property (gobject_class, PROP_MIN_QP,
311         g_param_spec_uint ("min-qp", "Min QP",
312             "The minimum allowed QP applied to all rc-mode",
313             0, 51, DEFAULT_MIN_QP,
314             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
315                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
316   }
317 
318   if (device_caps->max_qp) {
319     g_object_class_install_property (gobject_class, PROP_MAX_QP,
320         g_param_spec_uint ("max-qp", "Max QP",
321             "The maximum allowed QP applied to all rc-mode",
322             0, 51, DEFAULT_MAX_QP,
323             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
324                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
325   }
326 
327   if (device_caps->frame_type_qp) {
328     g_object_class_install_property (gobject_class, PROP_QP_I,
329         g_param_spec_uint ("qp-i", "QP I",
330             "QP applied to I frames", 0, 51,
331             DEFAULT_QP_I,
332             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
333                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
334 
335     g_object_class_install_property (gobject_class, PROP_QP_P,
336         g_param_spec_uint ("qp-p", "QP P",
337             "QP applied to P frames", 0, 51,
338             DEFAULT_QP_P,
339             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
340                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
341 
342     g_object_class_install_property (gobject_class, PROP_QP_B,
343         g_param_spec_uint ("qp-b", "QP B",
344             "QP applied to B frames", 0, 51,
345             DEFAULT_QP_B,
346             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
347                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
348   }
349 
350   if (device_caps->max_num_ref) {
351     g_object_class_install_property (gobject_class, PROP_REF,
352         g_param_spec_uint ("ref", "Reference Frames",
353             "The number of reference frames",
354             device_caps->max_num_ref_low, device_caps->max_num_ref_high,
355             DEFAULT_REF,
356             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
357                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
358   }
359 
360   /**
361    * GstMFH265Enc:d3d11-aware:
362    *
363    * Whether element supports Direct3D11 texture as an input or not
364    *
365    * Since: 1.20
366    */
367   g_object_class_install_property (gobject_class, PROP_D3D11_AWARE,
368       g_param_spec_boolean ("d3d11-aware", "D3D11 Aware",
369           "Whether device can support Direct3D11 interop",
370           device_caps->d3d11_aware,
371           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
372 
373   /**
374    * GstMFH265Enc:adapter-luid:
375    *
376    * DXGI Adapter LUID for this elemenet
377    *
378    * Since: 1.20
379    */
380   if (device_caps->d3d11_aware) {
381     g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
382         g_param_spec_int64 ("adapter-luid", "Adapter LUID",
383             "DXGI Adapter LUID (Locally Unique Identifier) of created device",
384             G_MININT64, G_MAXINT64, device_caps->adapter_luid,
385             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
386                 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
387   }
388 
389   long_name = g_strdup_printf ("Media Foundation %s", cdata->device_name);
390   classification = g_strdup_printf ("Codec/Encoder/Video%s",
391       (cdata->enum_flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE ?
392       "/Hardware" : "");
393   gst_element_class_set_metadata (element_class, long_name,
394       classification,
395       "Microsoft Media Foundation H.265 Encoder",
396       "Seungha Yang <seungha.yang@navercorp.com>");
397   g_free (long_name);
398   g_free (classification);
399 
400   gst_element_class_add_pad_template (element_class,
401       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
402           cdata->sink_caps));
403   gst_element_class_add_pad_template (element_class,
404       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
405           cdata->src_caps));
406 
407   mfenc_class->set_option = GST_DEBUG_FUNCPTR (gst_mf_h265_enc_set_option);
408   mfenc_class->set_src_caps = GST_DEBUG_FUNCPTR (gst_mf_h265_enc_set_src_caps);
409 
410   mfenc_class->codec_id = MFVideoFormat_HEVC;
411   mfenc_class->enum_flags = cdata->enum_flags;
412   mfenc_class->device_index = cdata->device_index;
413   mfenc_class->device_caps = *device_caps;
414 
415   g_free (cdata->device_name);
416   gst_caps_unref (cdata->sink_caps);
417   gst_caps_unref (cdata->src_caps);
418   g_free (cdata);
419 }
420 
421 static void
gst_mf_h265_enc_init(GstMFH265Enc * self)422 gst_mf_h265_enc_init (GstMFH265Enc * self)
423 {
424   self->bitrate = DEFAULT_BITRATE;
425   self->rc_mode = DEFAULT_RC_MODE;
426   self->max_bitrate = DEFAULT_MAX_BITRATE;
427   self->quality_vs_speed = DEFAULT_QUALITY_VS_SPEED;
428   self->bframes = DEFAULT_BFRAMES;
429   self->gop_size = DEFAULT_GOP_SIZE;
430   self->threads = DEFAULT_THREADS;
431   self->content_type = DEFAULT_CONTENT_TYPE;
432   self->qp = DEFAULT_QP;
433   self->low_latency = DEFAULT_LOW_LATENCY;
434   self->min_qp = DEFAULT_MIN_QP;
435   self->max_qp = DEFAULT_MAX_QP;
436   self->qp_i = DEFAULT_QP_I;
437   self->qp_p = DEFAULT_QP_P;
438   self->qp_b = DEFAULT_QP_B;
439   self->max_num_ref = DEFAULT_REF;
440 }
441 
442 static void
gst_mf_h265_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)443 gst_mf_h265_enc_get_property (GObject * object, guint prop_id,
444     GValue * value, GParamSpec * pspec)
445 {
446   GstMFH265Enc *self = (GstMFH265Enc *) (object);
447   GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (object);
448 
449   switch (prop_id) {
450     case PROP_BITRATE:
451       g_value_set_uint (value, self->bitrate);
452       break;
453     case PROP_RC_MODE:
454       g_value_set_enum (value, self->rc_mode);
455       break;
456     case PROP_BUFFER_SIZE:
457       g_value_set_uint (value, self->buffer_size);
458       break;
459     case PROP_MAX_BITRATE:
460       g_value_set_uint (value, self->max_bitrate);
461       break;
462     case PROP_QUALITY_VS_SPEED:
463       g_value_set_uint (value, self->quality_vs_speed);
464       break;
465     case PROP_BFRAMES:
466       g_value_set_uint (value, self->bframes);
467       break;
468     case PROP_GOP_SIZE:
469       g_value_set_int (value, self->gop_size);
470       break;
471     case PROP_THREADS:
472       g_value_set_uint (value, self->threads);
473       break;
474     case PROP_CONTENT_TYPE:
475       g_value_set_enum (value, self->content_type);
476       break;
477     case PROP_QP:
478       g_value_set_uint (value, self->qp);
479       break;
480     case PROP_LOW_LATENCY:
481       g_value_set_boolean (value, self->low_latency);
482       break;
483     case PROP_MIN_QP:
484       g_value_set_uint (value, self->min_qp);
485       break;
486     case PROP_MAX_QP:
487       g_value_set_uint (value, self->max_qp);
488       break;
489     case PROP_QP_I:
490       g_value_set_uint (value, self->qp_i);
491       break;
492     case PROP_QP_P:
493       g_value_set_uint (value, self->qp_p);
494       break;
495     case PROP_QP_B:
496       g_value_set_uint (value, self->qp_b);
497       break;
498     case PROP_REF:
499       g_value_set_uint (value, self->max_num_ref);
500       break;
501     case PROP_D3D11_AWARE:
502       g_value_set_boolean (value, klass->device_caps.d3d11_aware);
503       break;
504     case PROP_ADAPTER_LUID:
505       g_value_set_int64 (value, klass->device_caps.adapter_luid);
506       break;
507     default:
508       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
509       break;
510   }
511 }
512 
513 static void
gst_mf_h265_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)514 gst_mf_h265_enc_set_property (GObject * object, guint prop_id,
515     const GValue * value, GParamSpec * pspec)
516 {
517   GstMFH265Enc *self = (GstMFH265Enc *) (object);
518 
519   switch (prop_id) {
520     case PROP_BITRATE:
521       self->bitrate = g_value_get_uint (value);
522       break;
523     case PROP_RC_MODE:
524       self->rc_mode = g_value_get_enum (value);
525       break;
526     case PROP_BUFFER_SIZE:
527       self->buffer_size = g_value_get_uint (value);
528       break;
529     case PROP_MAX_BITRATE:
530       self->max_bitrate = g_value_get_uint (value);
531       break;
532     case PROP_QUALITY_VS_SPEED:
533       self->quality_vs_speed = g_value_get_uint (value);
534       break;
535     case PROP_BFRAMES:
536       self->bframes = g_value_get_uint (value);
537       break;
538     case PROP_GOP_SIZE:
539       self->gop_size = g_value_get_int (value);
540       break;
541     case PROP_THREADS:
542       self->threads = g_value_get_uint (value);
543       break;
544     case PROP_CONTENT_TYPE:
545       self->content_type = g_value_get_enum (value);
546       break;
547     case PROP_QP:
548       self->qp = g_value_get_uint (value);
549       break;
550     case PROP_LOW_LATENCY:
551       self->low_latency = g_value_get_boolean (value);
552       break;
553     case PROP_MIN_QP:
554       self->min_qp = g_value_get_uint (value);
555       break;
556     case PROP_MAX_QP:
557       self->max_qp = g_value_get_uint (value);
558       break;
559     case PROP_QP_I:
560       self->qp_i = g_value_get_uint (value);
561       break;
562     case PROP_QP_P:
563       self->qp_p = g_value_get_uint (value);
564       break;
565     case PROP_QP_B:
566       self->qp_b = g_value_get_uint (value);
567       break;
568     case PROP_REF:
569       self->max_num_ref = g_value_get_uint (value);
570       break;
571     default:
572       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
573       break;
574   }
575 }
576 
577 static guint
gst_mf_h265_enc_rc_mode_to_enum(guint rc_mode)578 gst_mf_h265_enc_rc_mode_to_enum (guint rc_mode)
579 {
580   switch (rc_mode) {
581     case GST_MF_H265_ENC_RC_MODE_CBR:
582       return eAVEncCommonRateControlMode_CBR;
583     case GST_MF_H265_ENC_RC_MODE_QUALITY:
584       return eAVEncCommonRateControlMode_Quality;
585     default:
586       return G_MAXUINT;
587   }
588 }
589 
590 static guint
gst_mf_h265_enc_content_type_to_enum(guint rc_mode)591 gst_mf_h265_enc_content_type_to_enum (guint rc_mode)
592 {
593   switch (rc_mode) {
594     case GST_MF_H265_ENC_CONTENT_TYPE_UNKNOWN:
595       return eAVEncVideoContentType_Unknown;
596     case GST_MF_H265_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE:
597       return eAVEncVideoContentType_FixedCameraAngle;
598     default:
599       return G_MAXUINT;
600   }
601 }
602 
603 #define WARNING_HR(hr,func) \
604   G_STMT_START { \
605     if (!gst_mf_result (hr)) { \
606       GST_WARNING_OBJECT (self, G_STRINGIFY(func) " failed, hr: 0x%x", (guint) hr); \
607     } \
608   } G_STMT_END
609 
610 static gboolean
gst_mf_h265_enc_set_option(GstMFVideoEnc * mfenc,GstVideoCodecState * state,IMFMediaType * output_type)611 gst_mf_h265_enc_set_option (GstMFVideoEnc * mfenc, GstVideoCodecState * state,
612     IMFMediaType * output_type)
613 {
614   GstMFH265Enc *self = (GstMFH265Enc *) mfenc;
615   GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (mfenc);
616   GstMFVideoEncDeviceCaps *device_caps = &klass->device_caps;
617   HRESULT hr;
618   GstMFTransform *transform = mfenc->transform;
619 
620   hr = output_type->SetGUID (MF_MT_SUBTYPE, MFVideoFormat_HEVC);
621   if (!gst_mf_result (hr))
622     return FALSE;
623 
624   if (GST_VIDEO_INFO_FORMAT (&mfenc->input_state->info) ==
625       GST_VIDEO_FORMAT_P010_10LE) {
626     hr = output_type->SetUINT32 (MF_MT_MPEG2_PROFILE,
627         eAVEncH265VProfile_Main_420_10);
628   } else {
629     hr = output_type->SetUINT32 (MF_MT_MPEG2_PROFILE,
630         eAVEncH265VProfile_Main_420_8);
631   }
632 
633   if (!gst_mf_result (hr))
634     return FALSE;
635 
636   hr = output_type->SetUINT32 (MF_MT_AVG_BITRATE,
637       MIN (self->bitrate * 1024, G_MAXUINT - 1));
638   if (!gst_mf_result (hr))
639     return FALSE;
640 
641   if (device_caps->rc_mode) {
642     guint rc_mode;
643     rc_mode = gst_mf_h265_enc_rc_mode_to_enum (self->rc_mode);
644     if (rc_mode != G_MAXUINT) {
645       hr = gst_mf_transform_set_codec_api_uint32 (transform,
646           &CODECAPI_AVEncCommonRateControlMode, rc_mode);
647       WARNING_HR (hr, CODECAPI_AVEncCommonRateControlMode);
648     }
649   }
650 
651   if (device_caps->buffer_size && self->buffer_size > 0) {
652     hr = gst_mf_transform_set_codec_api_uint32 (transform,
653         &CODECAPI_AVEncCommonBufferSize, self->buffer_size);
654     WARNING_HR (hr, CODECAPI_AVEncCommonBufferSize);
655   }
656 
657   if (device_caps->max_bitrate && self->max_bitrate > 0) {
658     hr = gst_mf_transform_set_codec_api_uint32 (transform,
659         &CODECAPI_AVEncCommonMaxBitRate,
660         MIN (self->max_bitrate * 1024, G_MAXUINT - 1));
661     WARNING_HR (hr, CODECAPI_AVEncCommonMaxBitRate);
662   }
663 
664   if (device_caps->quality_vs_speed) {
665     hr = gst_mf_transform_set_codec_api_uint32 (transform,
666         &CODECAPI_AVEncCommonQualityVsSpeed, self->quality_vs_speed);
667     WARNING_HR (hr, CODECAPI_AVEncCommonQualityVsSpeed);
668   }
669 
670   mfenc->has_reorder_frame = FALSE;
671   if (device_caps->bframes) {
672     hr = gst_mf_transform_set_codec_api_uint32 (transform,
673         &CODECAPI_AVEncMPVDefaultBPictureCount, self->bframes);
674     if (SUCCEEDED (hr) && self->bframes > 0)
675       mfenc->has_reorder_frame = TRUE;
676 
677     WARNING_HR (hr, CODECAPI_AVEncMPVDefaultBPictureCount);
678   }
679 
680   if (device_caps->gop_size) {
681     GstVideoInfo *info = &state->info;
682     gint gop_size = self->gop_size;
683     gint fps_n, fps_d;
684 
685     /* Set default value (10 sec or 250 frames) like that of x264enc */
686     if (gop_size < 0) {
687       fps_n = GST_VIDEO_INFO_FPS_N (info);
688       fps_d = GST_VIDEO_INFO_FPS_D (info);
689       if (fps_n <= 0 || fps_d <= 0) {
690         gop_size = 250;
691       } else {
692         gop_size = 10 * fps_n / fps_d;
693       }
694 
695       GST_DEBUG_OBJECT (self, "Update GOP size to %d", gop_size);
696     }
697 
698     hr = gst_mf_transform_set_codec_api_uint32 (transform,
699         &CODECAPI_AVEncMPVGOPSize, gop_size);
700     WARNING_HR (hr, CODECAPI_AVEncMPVGOPSize);
701   }
702 
703   if (device_caps->threads) {
704     hr = gst_mf_transform_set_codec_api_uint32 (transform,
705         &CODECAPI_AVEncNumWorkerThreads, self->threads);
706     WARNING_HR (hr, CODECAPI_AVEncNumWorkerThreads);
707   }
708 
709   if (device_caps->content_type) {
710     guint content_type;
711     content_type = gst_mf_h265_enc_content_type_to_enum (self->content_type);
712     if (content_type != G_MAXUINT) {
713       hr = gst_mf_transform_set_codec_api_uint32 (transform,
714           &CODECAPI_AVEncVideoContentType, content_type);
715       WARNING_HR (hr, CODECAPI_AVEncVideoContentType);
716     }
717   }
718 
719   if (device_caps->qp) {
720     hr = gst_mf_transform_set_codec_api_uint64 (transform,
721         &CODECAPI_AVEncVideoEncodeQP, self->qp);
722     WARNING_HR (hr, CODECAPI_AVEncVideoEncodeQP);
723   }
724 
725   if (device_caps->low_latency) {
726     hr = gst_mf_transform_set_codec_api_boolean (transform,
727         &CODECAPI_AVLowLatencyMode, self->low_latency);
728     WARNING_HR (hr, CODECAPI_AVLowLatencyMode);
729   }
730 
731   if (device_caps->min_qp) {
732     hr = gst_mf_transform_set_codec_api_uint32 (transform,
733         &CODECAPI_AVEncVideoMinQP, self->min_qp);
734     WARNING_HR (hr, CODECAPI_AVEncVideoMinQP);
735   }
736 
737   if (device_caps->max_qp) {
738     hr = gst_mf_transform_set_codec_api_uint32 (transform,
739         &CODECAPI_AVEncVideoMaxQP, self->max_qp);
740     WARNING_HR (hr, CODECAPI_AVEncVideoMaxQP);
741   }
742 
743   if (device_caps->frame_type_qp) {
744     guint64 type_qp = 0;
745 
746     type_qp =
747         (guint64) self->qp_i | (guint64) self->qp_p << 16 |
748         (guint64) self->qp_b << 32;
749     hr = gst_mf_transform_set_codec_api_uint64 (transform,
750         &CODECAPI_AVEncVideoEncodeFrameTypeQP, type_qp);
751     WARNING_HR (hr, CODECAPI_AVEncVideoEncodeFrameTypeQP);
752   }
753 
754   if (device_caps->max_num_ref) {
755     hr = gst_mf_transform_set_codec_api_uint32 (transform,
756         &CODECAPI_AVEncVideoMaxNumRefFrame, self->max_num_ref);
757     WARNING_HR (hr, CODECAPI_AVEncVideoMaxNumRefFrame);
758   }
759 
760   return TRUE;
761 }
762 
763 static gboolean
gst_mf_h265_enc_set_src_caps(GstMFVideoEnc * mfenc,GstVideoCodecState * state,IMFMediaType * output_type)764 gst_mf_h265_enc_set_src_caps (GstMFVideoEnc * mfenc,
765     GstVideoCodecState * state, IMFMediaType * output_type)
766 {
767   GstMFH265Enc *self = (GstMFH265Enc *) mfenc;
768   GstVideoCodecState *out_state;
769   GstStructure *s;
770   GstCaps *out_caps;
771   GstTagList *tags;
772 
773   out_caps = gst_caps_new_empty_simple ("video/x-h265");
774   s = gst_caps_get_structure (out_caps, 0);
775 
776   gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream",
777       "alignment", G_TYPE_STRING, "au", NULL);
778 
779   if (GST_VIDEO_INFO_FORMAT (&mfenc->input_state->info) ==
780       GST_VIDEO_FORMAT_P010_10LE) {
781     gst_structure_set (s, "profile", G_TYPE_STRING, "main-10", NULL);
782   } else {
783     gst_structure_set (s, "profile", G_TYPE_STRING, "main", NULL);
784   }
785 
786   out_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
787       out_caps, state);
788 
789   GST_INFO_OBJECT (self, "output caps: %" GST_PTR_FORMAT, out_state->caps);
790 
791   /* encoder will keep it around for us */
792   gst_video_codec_state_unref (out_state);
793 
794   tags = gst_tag_list_new_empty ();
795   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
796       gst_element_get_metadata (GST_ELEMENT_CAST (self),
797           GST_ELEMENT_METADATA_LONGNAME), NULL);
798   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (self), tags,
799       GST_TAG_MERGE_REPLACE);
800   gst_tag_list_unref (tags);
801 
802   return TRUE;
803 }
804 
805 void
gst_mf_h265_enc_plugin_init(GstPlugin * plugin,guint rank,GList * d3d11_device)806 gst_mf_h265_enc_plugin_init (GstPlugin * plugin, guint rank,
807     GList * d3d11_device)
808 {
809   GTypeInfo type_info = {
810     sizeof (GstMFH265EncClass),
811     NULL,
812     NULL,
813     (GClassInitFunc) gst_mf_h265_enc_class_init,
814     NULL,
815     NULL,
816     sizeof (GstMFH265Enc),
817     0,
818     (GInstanceInitFunc) gst_mf_h265_enc_init,
819   };
820   GUID subtype = MFVideoFormat_HEVC;
821 
822   GST_DEBUG_CATEGORY_INIT (gst_mf_h265_enc_debug, "mfh265enc", 0, "mfh265enc");
823 
824   gst_mf_video_enc_register (plugin, rank, &subtype, &type_info, d3d11_device);
825 }
826