• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2019 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-mfh264enc
23  * @title: mfh264enc
24  *
25  * This element encodes raw video into H264 compressed data.
26  *
27  * ## Example pipelines
28  * |[
29  * gst-launch-1.0 -v videotestsrc ! mfh264enc ! h264parse ! qtmux ! filesink location=videotestsrc.mp4
30  * ]| This example pipeline will encode a test video source to H264 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 "gstmfconfig.h"
39 
40 #include <gst/gst.h>
41 #include <gst/pbutils/pbutils.h>
42 #include "gstmfvideoenc.h"
43 #include "gstmfh264enc.h"
44 #include <wrl.h>
45 
46 #if GST_MF_HAVE_D3D11
47 #include <gst/d3d11/gstd3d11.h>
48 #endif
49 
50 /* *INDENT-OFF* */
51 using namespace Microsoft::WRL;
52 /* *INDENT-ON* */
53 
54 GST_DEBUG_CATEGORY (gst_mf_h264_enc_debug);
55 #define GST_CAT_DEFAULT gst_mf_h264_enc_debug
56 
57 enum
58 {
59   GST_MF_H264_ENC_RC_MODE_CBR = 0,
60   GST_MF_H264_ENC_RC_MODE_PEAK_CONSTRAINED_VBR,
61   GST_MF_H264_ENC_RC_MODE_UNCONSTRAINED_VBR,
62   GST_MF_H264_ENC_RC_MODE_QUALITY,
63 };
64 
65 #define GST_TYPE_MF_H264_ENC_RC_MODE (gst_mf_h264_enc_rc_mode_get_type())
66 static GType
gst_mf_h264_enc_rc_mode_get_type(void)67 gst_mf_h264_enc_rc_mode_get_type (void)
68 {
69   static GType rc_mode_type = 0;
70 
71   static const GEnumValue rc_mode_types[] = {
72     {GST_MF_H264_ENC_RC_MODE_CBR, "Constant bitrate", "cbr"},
73     {GST_MF_H264_ENC_RC_MODE_PEAK_CONSTRAINED_VBR,
74         "Peak Constrained variable bitrate", "pcvbr"},
75     {GST_MF_H264_ENC_RC_MODE_UNCONSTRAINED_VBR,
76         "Unconstrained variable bitrate", "uvbr"},
77     {GST_MF_H264_ENC_RC_MODE_QUALITY, "Quality-based variable bitrate", "qvbr"},
78     {0, NULL, NULL}
79   };
80 
81   if (!rc_mode_type) {
82     rc_mode_type = g_enum_register_static ("GstMFH264EncRCMode", rc_mode_types);
83   }
84   return rc_mode_type;
85 }
86 
87 enum
88 {
89   GST_MF_H264_ENC_ADAPTIVE_MODE_NONE,
90   GST_MF_H264_ENC_ADAPTIVE_MODE_FRAMERATE,
91 };
92 
93 #define GST_TYPE_MF_H264_ENC_ADAPTIVE_MODE (gst_mf_h264_enc_adaptive_mode_get_type())
94 static GType
gst_mf_h264_enc_adaptive_mode_get_type(void)95 gst_mf_h264_enc_adaptive_mode_get_type (void)
96 {
97   static GType adaptive_mode_type = 0;
98 
99   static const GEnumValue adaptive_mode_types[] = {
100     {GST_MF_H264_ENC_ADAPTIVE_MODE_NONE, "None", "none"},
101     {GST_MF_H264_ENC_ADAPTIVE_MODE_FRAMERATE,
102         "Adaptively change the frame rate", "framerate"},
103     {0, NULL, NULL}
104   };
105 
106   if (!adaptive_mode_type) {
107     adaptive_mode_type =
108         g_enum_register_static ("GstMFH264EncAdaptiveMode",
109         adaptive_mode_types);
110   }
111   return adaptive_mode_type;
112 }
113 
114 enum
115 {
116   GST_MF_H264_ENC_CONTENT_TYPE_UNKNOWN,
117   GST_MF_H264_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE,
118 };
119 
120 #define GST_TYPE_MF_H264_ENC_CONTENT_TYPE (gst_mf_h264_enc_content_type_get_type())
121 static GType
gst_mf_h264_enc_content_type_get_type(void)122 gst_mf_h264_enc_content_type_get_type (void)
123 {
124   static GType content_type = 0;
125 
126   static const GEnumValue content_types[] = {
127     {GST_MF_H264_ENC_CONTENT_TYPE_UNKNOWN, "Unknown", "unknown"},
128     {GST_MF_H264_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE,
129         "Fixed Camera Angle, such as a webcam", "fixed"},
130     {0, NULL, NULL}
131   };
132 
133   if (!content_type) {
134     content_type =
135         g_enum_register_static ("GstMFH264EncContentType", content_types);
136   }
137   return content_type;
138 }
139 
140 enum
141 {
142   PROP_0,
143   PROP_BITRATE,
144   PROP_RC_MODE,
145   PROP_QUALITY,
146   PROP_ADAPTIVE_MODE,
147   PROP_BUFFER_SIZE,
148   PROP_MAX_BITRATE,
149   PROP_QUALITY_VS_SPEED,
150   PROP_CABAC,
151   PROP_SPS_ID,
152   PROP_PPS_ID,
153   PROP_BFRAMES,
154   PROP_GOP_SIZE,
155   PROP_THREADS,
156   PROP_CONTENT_TYPE,
157   PROP_QP,
158   PROP_LOW_LATENCY,
159   PROP_MIN_QP,
160   PROP_MAX_QP,
161   PROP_QP_I,
162   PROP_QP_P,
163   PROP_QP_B,
164   PROP_REF,
165   PROP_D3D11_AWARE,
166   PROP_ADAPTER_LUID,
167 };
168 
169 #define DEFAULT_BITRATE (2 * 1024)
170 #define DEFAULT_RC_MODE GST_MF_H264_ENC_RC_MODE_UNCONSTRAINED_VBR
171 #define DEFAULT_QUALITY_LEVEL 70
172 #define DEFAULT_ADAPTIVE_MODE GST_MF_H264_ENC_ADAPTIVE_MODE_NONE
173 #define DEFAULT_BUFFER_SIZE 0
174 #define DEFAULT_MAX_BITRATE 0
175 #define DEFAULT_QUALITY_VS_SPEED 50
176 #define DEFAULT_CABAC TRUE
177 #define DEFAULT_SPS_ID 0
178 #define DEFAULT_PPS_ID 0
179 #define DEFAULT_BFRAMES 0
180 #define DEFAULT_GOP_SIZE -1
181 #define DEFAULT_THREADS 0
182 #define DEFAULT_CONTENT_TYPE GST_MF_H264_ENC_CONTENT_TYPE_UNKNOWN
183 #define DEFAULT_QP 24
184 #define DEFAULT_LOW_LATENCY FALSE
185 #define DEFAULT_MIN_QP 0
186 #define DEFAULT_MAX_QP 51
187 #define DEFAULT_QP_I 26
188 #define DEFAULT_QP_P 26
189 #define DEFAULT_QP_B 26
190 #define DEFAULT_REF 2
191 
192 typedef struct _GstMFH264Enc
193 {
194   GstMFVideoEnc parent;
195 
196   /* properties */
197   guint bitrate;
198 
199   /* device dependent properties */
200   guint rc_mode;
201   guint quality;
202   guint adaptive_mode;
203   guint buffer_size;
204   guint max_bitrate;
205   guint quality_vs_speed;
206   gboolean cabac;
207   guint sps_id;
208   guint pps_id;
209   guint bframes;
210   gint gop_size;
211   guint threads;
212   guint content_type;
213   guint qp;
214   gboolean low_latency;
215   guint min_qp;
216   guint max_qp;
217   guint qp_i;
218   guint qp_p;
219   guint qp_b;
220   guint max_num_ref;
221   gchar *profile_str;
222 } GstMFH264Enc;
223 
224 typedef struct _GstMFH264EncClass
225 {
226   GstMFVideoEncClass parent_class;
227 } GstMFH264EncClass;
228 
229 static GstElementClass *parent_class = NULL;
230 
231 static void gst_mf_h264_enc_finalize (GObject * object);
232 static void gst_mf_h264_enc_get_property (GObject * object, guint prop_id,
233     GValue * value, GParamSpec * pspec);
234 static void gst_mf_h264_enc_set_property (GObject * object, guint prop_id,
235     const GValue * value, GParamSpec * pspec);
236 static gboolean gst_mf_h264_enc_set_option (GstMFVideoEnc * mfenc,
237     GstVideoCodecState * state, IMFMediaType * output_type);
238 static gboolean gst_mf_h264_enc_set_src_caps (GstMFVideoEnc * mfenc,
239     GstVideoCodecState * state, IMFMediaType * output_type);
240 
241 static void
gst_mf_h264_enc_class_init(GstMFH264EncClass * klass,gpointer data)242 gst_mf_h264_enc_class_init (GstMFH264EncClass * klass, gpointer data)
243 {
244   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
245   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
246   GstMFVideoEncClass *mfenc_class = GST_MF_VIDEO_ENC_CLASS (klass);
247   GstMFVideoEncClassData *cdata = (GstMFVideoEncClassData *) data;
248   GstMFVideoEncDeviceCaps *device_caps = &cdata->device_caps;
249   gchar *long_name;
250   gchar *classification;
251 
252   parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
253 
254   gobject_class->finalize = gst_mf_h264_enc_finalize;
255   gobject_class->get_property = gst_mf_h264_enc_get_property;
256   gobject_class->set_property = gst_mf_h264_enc_set_property;
257 
258   g_object_class_install_property (gobject_class, PROP_BITRATE,
259       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
260           (G_MAXUINT >> 10), DEFAULT_BITRATE,
261           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
262 
263   if (device_caps->rc_mode) {
264     g_object_class_install_property (gobject_class, PROP_RC_MODE,
265         g_param_spec_enum ("rc-mode", "Rate Control Mode",
266             "Rate Control Mode",
267             GST_TYPE_MF_H264_ENC_RC_MODE, DEFAULT_RC_MODE,
268             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
269                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
270 
271     /* NOTE: documentation will be done by only for default device */
272     if (cdata->is_default) {
273       gst_type_mark_as_plugin_api (GST_TYPE_MF_H264_ENC_RC_MODE,
274           (GstPluginAPIFlags) 0);
275     }
276   }
277 
278   /* quality and qp has the identical meaning but scale is different
279    * use qp if available */
280   if (device_caps->quality && !device_caps->qp) {
281     g_object_class_install_property (gobject_class, PROP_QUALITY,
282         g_param_spec_uint ("quality", "Quality",
283             "Quality applied when rc-mode is qvbr",
284             1, 100, DEFAULT_QUALITY_LEVEL,
285             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
286                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
287   }
288 
289   if (device_caps->adaptive_mode) {
290     g_object_class_install_property (gobject_class, PROP_ADAPTIVE_MODE,
291         g_param_spec_enum ("adaptive-mode", "Adaptive Mode",
292             "Adaptive Mode", GST_TYPE_MF_H264_ENC_ADAPTIVE_MODE,
293             DEFAULT_ADAPTIVE_MODE,
294             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
295                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
296 
297     /* NOTE: documentation will be done by only for default device */
298     if (cdata->is_default) {
299       gst_type_mark_as_plugin_api (GST_TYPE_MF_H264_ENC_ADAPTIVE_MODE,
300           (GstPluginAPIFlags) 0);
301     }
302   }
303 
304   if (device_caps->buffer_size) {
305     g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
306         g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
307             "VBV(HRD) Buffer Size in bytes (0 = MFT default)",
308             0, G_MAXUINT - 1, DEFAULT_BUFFER_SIZE,
309             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
310                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
311   }
312 
313   if (device_caps->max_bitrate) {
314     g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
315         g_param_spec_uint ("max-bitrate", "Max Bitrate",
316             "The maximum bitrate applied when rc-mode is \"pcvbr\" in kbit/sec",
317             0, (G_MAXUINT >> 10), DEFAULT_MAX_BITRATE,
318             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
319                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
320   }
321 
322   if (device_caps->quality_vs_speed) {
323     g_object_class_install_property (gobject_class, PROP_QUALITY_VS_SPEED,
324         g_param_spec_uint ("quality-vs-speed", "Quality Vs Speed",
325             "Quality and speed tradeoff, [0, 33]: Low complexity, "
326             "[34, 66]: Medium complexity, [67, 100]: High complexity", 0, 100,
327             DEFAULT_QUALITY_VS_SPEED,
328             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
329                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
330   }
331 
332   if (device_caps->cabac) {
333     g_object_class_install_property (gobject_class, PROP_CABAC,
334         g_param_spec_boolean ("cabac", "Use CABAC",
335             "Enable CABAC entropy coding",
336             DEFAULT_CABAC,
337             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
338                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
339   }
340 
341   if (device_caps->sps_id) {
342     g_object_class_install_property (gobject_class, PROP_SPS_ID,
343         g_param_spec_uint ("sps-id", "SPS Id",
344             "The SPS id to use", 0, 31,
345             DEFAULT_SPS_ID,
346             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
347                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
348   }
349 
350   if (device_caps->pps_id) {
351     g_object_class_install_property (gobject_class, PROP_PPS_ID,
352         g_param_spec_uint ("pps-id", "PPS Id",
353             "The PPS id to use", 0, 255,
354             DEFAULT_PPS_ID,
355             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
356                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
357   }
358 
359   if (device_caps->bframes) {
360     g_object_class_install_property (gobject_class, PROP_BFRAMES,
361         g_param_spec_uint ("bframes", "bframes",
362             "The maximum number of consecutive B frames", 0, 2,
363             DEFAULT_BFRAMES,
364             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
365                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
366   }
367 
368   if (device_caps->gop_size) {
369     g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
370         g_param_spec_int ("gop-size", "GOP size",
371             "The number of pictures from one GOP header to the next. "
372             "Depending on GPU vendor implementation, zero gop-size might "
373             "produce only one keyframe at the beginning (-1 for automatic)",
374             -1, G_MAXINT, DEFAULT_GOP_SIZE,
375             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
376                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
377   }
378 
379   if (device_caps->threads) {
380     g_object_class_install_property (gobject_class, PROP_THREADS,
381         g_param_spec_uint ("threads", "Threads",
382             "The number of worker threads used by a encoder, (0 = MFT default)",
383             0, 16, DEFAULT_THREADS,
384             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
385                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
386   }
387 
388   if (device_caps->content_type) {
389     g_object_class_install_property (gobject_class, PROP_CONTENT_TYPE,
390         g_param_spec_enum ("content-type", "Content Type",
391             "Indicates the type of video content",
392             GST_TYPE_MF_H264_ENC_CONTENT_TYPE, DEFAULT_CONTENT_TYPE,
393             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
394                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
395 
396     /* NOTE: documentation will be done by only for default device */
397     if (cdata->is_default) {
398       gst_type_mark_as_plugin_api (GST_TYPE_MF_H264_ENC_CONTENT_TYPE,
399           (GstPluginAPIFlags) 0);
400     }
401   }
402 
403   if (device_caps->qp) {
404     g_object_class_install_property (gobject_class, PROP_QP,
405         g_param_spec_uint ("qp", "qp",
406             "QP applied when rc-mode is \"qvbr\"", 16, 51,
407             DEFAULT_QP,
408             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
409                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
410   }
411 
412   if (device_caps->low_latency) {
413     g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
414         g_param_spec_boolean ("low-latency", "Low Latency",
415             "Enable low latency encoding",
416             DEFAULT_LOW_LATENCY,
417             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
418                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
419   }
420 
421   if (device_caps->min_qp) {
422     g_object_class_install_property (gobject_class, PROP_MIN_QP,
423         g_param_spec_uint ("min-qp", "Min QP",
424             "The minimum allowed QP applied to all rc-mode", 0, 51,
425             DEFAULT_MIN_QP,
426             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
427                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
428   }
429 
430   if (device_caps->max_qp) {
431     g_object_class_install_property (gobject_class, PROP_MAX_QP,
432         g_param_spec_uint ("max-qp", "Max QP",
433             "The maximum allowed QP applied to all rc-mode", 0, 51,
434             DEFAULT_MAX_QP,
435             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
436                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
437   }
438 
439   if (device_caps->frame_type_qp) {
440     g_object_class_install_property (gobject_class, PROP_QP_I,
441         g_param_spec_uint ("qp-i", "QP I",
442             "QP applied to I frames", 0, 51,
443             DEFAULT_QP_I,
444             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
445                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
446 
447     g_object_class_install_property (gobject_class, PROP_QP_P,
448         g_param_spec_uint ("qp-p", "QP P",
449             "QP applied to P frames", 0, 51,
450             DEFAULT_QP_P,
451             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
452                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
453 
454     g_object_class_install_property (gobject_class, PROP_QP_B,
455         g_param_spec_uint ("qp-b", "QP B",
456             "QP applied to B frames", 0, 51,
457             DEFAULT_QP_B,
458             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
459                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
460   }
461 
462   if (device_caps->max_num_ref) {
463     g_object_class_install_property (gobject_class, PROP_REF,
464         g_param_spec_uint ("ref", "Reference Frames",
465             "The number of reference frames",
466             device_caps->max_num_ref_low, device_caps->max_num_ref_high,
467             DEFAULT_REF,
468             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
469                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
470   }
471 
472   /**
473    * GstMFH264Enc:d3d11-aware:
474    *
475    * Whether element supports Direct3D11 texture as an input or not
476    *
477    * Since: 1.20
478    */
479   g_object_class_install_property (gobject_class, PROP_D3D11_AWARE,
480       g_param_spec_boolean ("d3d11-aware", "D3D11 Aware",
481           "Whether device can support Direct3D11 interop",
482           device_caps->d3d11_aware,
483           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
484 
485   /**
486    * GstMFH264Enc:adapter-luid:
487    *
488    * DXGI Adapter LUID for this elemenet
489    *
490    * Since: 1.20
491    */
492   if (device_caps->d3d11_aware) {
493     g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
494         g_param_spec_int64 ("adapter-luid", "Adapter LUID",
495             "DXGI Adapter LUID (Locally Unique Identifier) of created device",
496             G_MININT64, G_MAXINT64, device_caps->adapter_luid,
497             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
498                 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
499   }
500 
501   long_name = g_strdup_printf ("Media Foundation %s", cdata->device_name);
502   classification = g_strdup_printf ("Codec/Encoder/Video%s",
503       (cdata->enum_flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE ?
504       "/Hardware" : "");
505   gst_element_class_set_metadata (element_class, long_name,
506       classification,
507       "Microsoft Media Foundation H.264 Encoder",
508       "Seungha Yang <seungha.yang@navercorp.com>");
509   g_free (long_name);
510   g_free (classification);
511 
512   gst_element_class_add_pad_template (element_class,
513       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
514           cdata->sink_caps));
515   gst_element_class_add_pad_template (element_class,
516       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
517           cdata->src_caps));
518 
519   mfenc_class->set_option = GST_DEBUG_FUNCPTR (gst_mf_h264_enc_set_option);
520   mfenc_class->set_src_caps = GST_DEBUG_FUNCPTR (gst_mf_h264_enc_set_src_caps);
521 
522   mfenc_class->codec_id = MFVideoFormat_H264;
523   mfenc_class->enum_flags = cdata->enum_flags;
524   mfenc_class->device_index = cdata->device_index;
525   mfenc_class->device_caps = *device_caps;
526 
527   g_free (cdata->device_name);
528   gst_caps_unref (cdata->sink_caps);
529   gst_caps_unref (cdata->src_caps);
530   g_free (cdata);
531 }
532 
533 static void
gst_mf_h264_enc_init(GstMFH264Enc * self)534 gst_mf_h264_enc_init (GstMFH264Enc * self)
535 {
536   self->bitrate = DEFAULT_BITRATE;
537   self->rc_mode = DEFAULT_RC_MODE;
538   self->quality = DEFAULT_QUALITY_LEVEL;
539   self->adaptive_mode = DEFAULT_ADAPTIVE_MODE;
540   self->max_bitrate = DEFAULT_MAX_BITRATE;
541   self->quality_vs_speed = DEFAULT_QUALITY_VS_SPEED;
542   self->cabac = DEFAULT_CABAC;
543   self->sps_id = DEFAULT_SPS_ID;
544   self->pps_id = DEFAULT_PPS_ID;
545   self->bframes = DEFAULT_BFRAMES;
546   self->gop_size = DEFAULT_GOP_SIZE;
547   self->threads = DEFAULT_THREADS;
548   self->content_type = DEFAULT_CONTENT_TYPE;
549   self->qp = DEFAULT_QP;
550   self->low_latency = DEFAULT_LOW_LATENCY;
551   self->min_qp = DEFAULT_MIN_QP;
552   self->max_qp = DEFAULT_MAX_QP;
553   self->qp_i = DEFAULT_QP_I;
554   self->qp_p = DEFAULT_QP_P;
555   self->qp_b = DEFAULT_QP_B;
556   self->max_num_ref = DEFAULT_REF;
557 }
558 
559 static void
gst_mf_h264_enc_finalize(GObject * object)560 gst_mf_h264_enc_finalize (GObject * object)
561 {
562   GstMFH264Enc *self = (GstMFH264Enc *) (object);
563 
564   g_free (self->profile_str);
565 
566   G_OBJECT_CLASS (parent_class)->finalize (object);
567 }
568 
569 static void
gst_mf_h264_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)570 gst_mf_h264_enc_get_property (GObject * object, guint prop_id,
571     GValue * value, GParamSpec * pspec)
572 {
573   GstMFH264Enc *self = (GstMFH264Enc *) (object);
574   GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (object);
575 
576   switch (prop_id) {
577     case PROP_BITRATE:
578       g_value_set_uint (value, self->bitrate);
579       break;
580     case PROP_RC_MODE:
581       g_value_set_enum (value, self->rc_mode);
582       break;
583     case PROP_QUALITY:
584       g_value_set_uint (value, self->quality);
585       break;
586     case PROP_ADAPTIVE_MODE:
587       g_value_set_enum (value, self->adaptive_mode);
588       break;
589     case PROP_BUFFER_SIZE:
590       g_value_set_uint (value, self->buffer_size);
591       break;
592     case PROP_MAX_BITRATE:
593       g_value_set_uint (value, self->max_bitrate);
594       break;
595     case PROP_QUALITY_VS_SPEED:
596       g_value_set_uint (value, self->quality_vs_speed);
597       break;
598     case PROP_CABAC:
599       g_value_set_boolean (value, self->cabac);
600       break;
601     case PROP_SPS_ID:
602       g_value_set_uint (value, self->sps_id);
603       break;
604     case PROP_PPS_ID:
605       g_value_set_uint (value, self->pps_id);
606       break;
607     case PROP_BFRAMES:
608       g_value_set_uint (value, self->bframes);
609       break;
610     case PROP_GOP_SIZE:
611       g_value_set_int (value, self->gop_size);
612       break;
613     case PROP_THREADS:
614       g_value_set_uint (value, self->threads);
615       break;
616     case PROP_CONTENT_TYPE:
617       g_value_set_enum (value, self->content_type);
618       break;
619     case PROP_QP:
620       g_value_set_uint (value, self->qp);
621       break;
622     case PROP_LOW_LATENCY:
623       g_value_set_boolean (value, self->low_latency);
624       break;
625     case PROP_MIN_QP:
626       g_value_set_uint (value, self->min_qp);
627       break;
628     case PROP_MAX_QP:
629       g_value_set_uint (value, self->max_qp);
630       break;
631     case PROP_QP_I:
632       g_value_set_uint (value, self->qp_i);
633       break;
634     case PROP_QP_P:
635       g_value_set_uint (value, self->qp_p);
636       break;
637     case PROP_QP_B:
638       g_value_set_uint (value, self->qp_b);
639       break;
640     case PROP_REF:
641       g_value_set_uint (value, self->max_num_ref);
642       break;
643     case PROP_D3D11_AWARE:
644       g_value_set_boolean (value, klass->device_caps.d3d11_aware);
645       break;
646     case PROP_ADAPTER_LUID:
647       g_value_set_int64 (value, klass->device_caps.adapter_luid);
648       break;
649     default:
650       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
651       break;
652   }
653 }
654 
655 static void
gst_mf_h264_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)656 gst_mf_h264_enc_set_property (GObject * object, guint prop_id,
657     const GValue * value, GParamSpec * pspec)
658 {
659   GstMFH264Enc *self = (GstMFH264Enc *) (object);
660 
661   switch (prop_id) {
662     case PROP_BITRATE:
663       self->bitrate = g_value_get_uint (value);
664       break;
665     case PROP_RC_MODE:
666       self->rc_mode = g_value_get_enum (value);
667       break;
668     case PROP_QUALITY:
669       self->quality = g_value_get_uint (value);
670       break;
671     case PROP_ADAPTIVE_MODE:
672       self->adaptive_mode = g_value_get_enum (value);
673       break;
674     case PROP_BUFFER_SIZE:
675       self->buffer_size = g_value_get_uint (value);
676       break;
677     case PROP_MAX_BITRATE:
678       self->max_bitrate = g_value_get_uint (value);
679       break;
680     case PROP_QUALITY_VS_SPEED:
681       self->quality_vs_speed = g_value_get_uint (value);
682       break;
683     case PROP_CABAC:
684       self->cabac = g_value_get_boolean (value);
685       break;
686     case PROP_SPS_ID:
687       self->sps_id = g_value_get_uint (value);
688       break;
689     case PROP_PPS_ID:
690       self->pps_id = g_value_get_uint (value);
691       break;
692     case PROP_BFRAMES:
693       self->bframes = g_value_get_uint (value);
694       break;
695     case PROP_GOP_SIZE:
696       self->gop_size = g_value_get_int (value);
697       break;
698     case PROP_THREADS:
699       self->threads = g_value_get_uint (value);
700       break;
701     case PROP_CONTENT_TYPE:
702       self->content_type = g_value_get_enum (value);
703       break;
704     case PROP_QP:
705       self->qp = g_value_get_uint (value);
706       break;
707     case PROP_LOW_LATENCY:
708       self->low_latency = g_value_get_boolean (value);
709       break;
710     case PROP_MIN_QP:
711       self->min_qp = g_value_get_uint (value);
712       break;
713     case PROP_MAX_QP:
714       self->max_qp = g_value_get_uint (value);
715       break;
716     case PROP_QP_I:
717       self->qp_i = g_value_get_uint (value);
718       break;
719     case PROP_QP_P:
720       self->qp_p = g_value_get_uint (value);
721       break;
722     case PROP_QP_B:
723       self->qp_b = g_value_get_uint (value);
724       break;
725     case PROP_REF:
726       self->max_num_ref = g_value_get_uint (value);
727       break;
728     default:
729       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
730       break;
731   }
732 }
733 
734 static guint
gst_mf_h264_enc_rc_mode_to_enum(guint rc_mode)735 gst_mf_h264_enc_rc_mode_to_enum (guint rc_mode)
736 {
737   switch (rc_mode) {
738     case GST_MF_H264_ENC_RC_MODE_CBR:
739       return eAVEncCommonRateControlMode_CBR;
740     case GST_MF_H264_ENC_RC_MODE_PEAK_CONSTRAINED_VBR:
741       return eAVEncCommonRateControlMode_PeakConstrainedVBR;
742     case GST_MF_H264_ENC_RC_MODE_UNCONSTRAINED_VBR:
743       return eAVEncCommonRateControlMode_UnconstrainedVBR;
744     case GST_MF_H264_ENC_RC_MODE_QUALITY:
745       return eAVEncCommonRateControlMode_Quality;
746     default:
747       return G_MAXUINT;
748   }
749 }
750 
751 static guint
gst_mf_h264_enc_adaptive_mode_to_enum(guint rc_mode)752 gst_mf_h264_enc_adaptive_mode_to_enum (guint rc_mode)
753 {
754   switch (rc_mode) {
755     case GST_MF_H264_ENC_ADAPTIVE_MODE_NONE:
756       return eAVEncAdaptiveMode_None;
757     case GST_MF_H264_ENC_ADAPTIVE_MODE_FRAMERATE:
758       return eAVEncAdaptiveMode_FrameRate;
759     default:
760       return G_MAXUINT;
761   }
762 }
763 
764 static guint
gst_mf_h264_enc_content_type_to_enum(guint rc_mode)765 gst_mf_h264_enc_content_type_to_enum (guint rc_mode)
766 {
767   switch (rc_mode) {
768     case GST_MF_H264_ENC_CONTENT_TYPE_UNKNOWN:
769       return eAVEncVideoContentType_Unknown;
770     case GST_MF_H264_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE:
771       return eAVEncVideoContentType_FixedCameraAngle;
772     default:
773       return G_MAXUINT;
774   }
775 }
776 
777 #define WARNING_HR(hr,func) \
778   G_STMT_START { \
779     if (!gst_mf_result (hr)) { \
780       GST_WARNING_OBJECT (self, G_STRINGIFY(func) " failed, hr: 0x%x", (guint) hr); \
781     } \
782   } G_STMT_END
783 
784 static gboolean
gst_mf_h264_enc_set_option(GstMFVideoEnc * mfenc,GstVideoCodecState * state,IMFMediaType * output_type)785 gst_mf_h264_enc_set_option (GstMFVideoEnc * mfenc, GstVideoCodecState * state,
786     IMFMediaType * output_type)
787 {
788   GstMFH264Enc *self = (GstMFH264Enc *) mfenc;
789   GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (mfenc);
790   GstMFVideoEncDeviceCaps *device_caps = &klass->device_caps;
791   HRESULT hr;
792   GstCaps *allowed_caps, *template_caps;
793   eAVEncH264VProfile selected_profile = eAVEncH264VProfile_Main;
794   gint level_idc = -1;
795   GstMFTransform *transform = mfenc->transform;
796 
797   g_free (self->profile_str);
798   self->profile_str = g_strdup ("main");
799 
800   template_caps =
801       gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
802   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
803 
804   if (template_caps == allowed_caps) {
805     GST_INFO_OBJECT (self, "downstream has ANY caps");
806   } else if (allowed_caps) {
807     GstStructure *s;
808     const gchar *profile;
809     const gchar *level;
810 
811     if (gst_caps_is_empty (allowed_caps)) {
812       gst_caps_unref (allowed_caps);
813       gst_caps_unref (template_caps);
814       return FALSE;
815     }
816 
817     allowed_caps = gst_caps_make_writable (allowed_caps);
818     allowed_caps = gst_caps_fixate (allowed_caps);
819     s = gst_caps_get_structure (allowed_caps, 0);
820 
821     profile = gst_structure_get_string (s, "profile");
822     if (profile) {
823       /* Although we are setting eAVEncH264VProfile_Base, actual profile
824        * chosen by MFT seems to be constrained-baseline */
825       if (strcmp (profile, "baseline") == 0 ||
826           strcmp (profile, "constrained-baseline") == 0) {
827         selected_profile = eAVEncH264VProfile_Base;
828         g_free (self->profile_str);
829         self->profile_str = g_strdup (profile);
830       } else if (g_str_has_prefix (profile, "high")) {
831         selected_profile = eAVEncH264VProfile_High;
832         g_free (self->profile_str);
833         self->profile_str = g_strdup (profile);
834       } else if (g_str_has_prefix (profile, "main")) {
835         selected_profile = eAVEncH264VProfile_Main;
836         g_free (self->profile_str);
837         self->profile_str = g_strdup (profile);
838       }
839     }
840 
841     level = gst_structure_get_string (s, "level");
842     if (level)
843       level_idc = gst_codec_utils_h264_get_level_idc (level);
844 
845     gst_caps_unref (allowed_caps);
846   }
847   gst_caps_unref (template_caps);
848 
849   hr = output_type->SetGUID (MF_MT_SUBTYPE, MFVideoFormat_H264);
850   if (!gst_mf_result (hr))
851     return FALSE;
852 
853   hr = output_type->SetUINT32 (MF_MT_MPEG2_PROFILE, selected_profile);
854   if (!gst_mf_result (hr))
855     return FALSE;
856 
857   if (level_idc >= eAVEncH264VLevel1 && level_idc <= eAVEncH264VLevel5_2) {
858     hr = output_type->SetUINT32 (MF_MT_MPEG2_LEVEL, level_idc);
859     if (!gst_mf_result (hr))
860       return FALSE;
861   }
862 
863   hr = output_type->SetUINT32 (MF_MT_AVG_BITRATE,
864       MIN (self->bitrate * 1024, G_MAXUINT - 1));
865   if (!gst_mf_result (hr))
866     return FALSE;
867 
868   if (device_caps->rc_mode) {
869     guint rc_mode;
870     rc_mode = gst_mf_h264_enc_rc_mode_to_enum (self->rc_mode);
871     if (rc_mode != G_MAXUINT) {
872       hr = gst_mf_transform_set_codec_api_uint32 (transform,
873           &CODECAPI_AVEncCommonRateControlMode, rc_mode);
874       WARNING_HR (hr, CODECAPI_AVEncCommonRateControlMode);
875     }
876   }
877 
878   if (device_caps->quality && !device_caps->qp) {
879     hr = gst_mf_transform_set_codec_api_uint32 (transform,
880         &CODECAPI_AVEncCommonQuality, self->quality);
881     WARNING_HR (hr, CODECAPI_AVEncCommonQuality);
882   }
883 
884   if (device_caps->adaptive_mode) {
885     guint adaptive_mode;
886     adaptive_mode = gst_mf_h264_enc_adaptive_mode_to_enum (self->adaptive_mode);
887     if (adaptive_mode != G_MAXUINT) {
888       hr = gst_mf_transform_set_codec_api_uint32 (transform,
889           &CODECAPI_AVEncAdaptiveMode, adaptive_mode);
890       WARNING_HR (hr, CODECAPI_AVEncAdaptiveMode);
891     }
892   }
893 
894   if (device_caps->buffer_size && self->buffer_size > 0) {
895     hr = gst_mf_transform_set_codec_api_uint32 (transform,
896         &CODECAPI_AVEncCommonBufferSize, self->buffer_size);
897     WARNING_HR (hr, CODECAPI_AVEncCommonBufferSize);
898   }
899 
900   if (device_caps->max_bitrate && self->max_bitrate > 0) {
901     hr = gst_mf_transform_set_codec_api_uint32 (transform,
902         &CODECAPI_AVEncCommonMaxBitRate,
903         MIN (self->max_bitrate * 1024, G_MAXUINT - 1));
904     WARNING_HR (hr, CODECAPI_AVEncCommonMaxBitRate);
905   }
906 
907   if (device_caps->quality_vs_speed) {
908     hr = gst_mf_transform_set_codec_api_uint32 (transform,
909         &CODECAPI_AVEncCommonQualityVsSpeed, self->quality_vs_speed);
910     WARNING_HR (hr, CODECAPI_AVEncCommonQualityVsSpeed);
911   }
912 
913   if (device_caps->cabac && selected_profile != eAVEncH264VProfile_Base) {
914     hr = gst_mf_transform_set_codec_api_boolean (transform,
915         &CODECAPI_AVEncH264CABACEnable, self->cabac);
916     WARNING_HR (hr, CODECAPI_AVEncH264CABACEnable);
917   }
918 
919   if (device_caps->sps_id) {
920     hr = gst_mf_transform_set_codec_api_uint32 (transform,
921         &CODECAPI_AVEncH264SPSID, self->sps_id);
922     WARNING_HR (hr, CODECAPI_AVEncH264SPSID);
923   }
924 
925   if (device_caps->pps_id) {
926     hr = gst_mf_transform_set_codec_api_uint32 (transform,
927         &CODECAPI_AVEncH264PPSID, self->pps_id);
928     WARNING_HR (hr, CODECAPI_AVEncH264PPSID);
929   }
930 
931   mfenc->has_reorder_frame = FALSE;
932   if (device_caps->bframes && selected_profile != eAVEncH264VProfile_Base) {
933     hr = gst_mf_transform_set_codec_api_uint32 (transform,
934         &CODECAPI_AVEncMPVDefaultBPictureCount, self->bframes);
935     if (SUCCEEDED (hr) && self->bframes > 0)
936       mfenc->has_reorder_frame = TRUE;
937 
938     WARNING_HR (hr, CODECAPI_AVEncMPVDefaultBPictureCount);
939   }
940 
941   if (device_caps->gop_size) {
942     GstVideoInfo *info = &state->info;
943     gint gop_size = self->gop_size;
944     gint fps_n, fps_d;
945 
946     /* Set default value (10 sec or 250 frames) like that of x264enc */
947     if (gop_size < 0) {
948       fps_n = GST_VIDEO_INFO_FPS_N (info);
949       fps_d = GST_VIDEO_INFO_FPS_D (info);
950       if (fps_n <= 0 || fps_d <= 0) {
951         gop_size = 250;
952       } else {
953         gop_size = 10 * fps_n / fps_d;
954       }
955 
956       GST_DEBUG_OBJECT (self, "Update GOP size to %d", gop_size);
957     }
958 
959     hr = gst_mf_transform_set_codec_api_uint32 (transform,
960         &CODECAPI_AVEncMPVGOPSize, gop_size);
961     WARNING_HR (hr, CODECAPI_AVEncMPVGOPSize);
962   }
963 
964   if (device_caps->threads) {
965     hr = gst_mf_transform_set_codec_api_uint32 (transform,
966         &CODECAPI_AVEncNumWorkerThreads, self->threads);
967     WARNING_HR (hr, CODECAPI_AVEncNumWorkerThreads);
968   }
969 
970   if (device_caps->content_type) {
971     guint content_type;
972     content_type = gst_mf_h264_enc_content_type_to_enum (self->content_type);
973     if (content_type != G_MAXUINT) {
974       hr = gst_mf_transform_set_codec_api_uint32 (transform,
975           &CODECAPI_AVEncVideoContentType, content_type);
976       WARNING_HR (hr, CODECAPI_AVEncVideoContentType);
977     }
978   }
979 
980   if (device_caps->qp) {
981     hr = gst_mf_transform_set_codec_api_uint64 (transform,
982         &CODECAPI_AVEncVideoEncodeQP, self->qp);
983     WARNING_HR (hr, CODECAPI_AVEncVideoEncodeQP);
984   }
985 
986   if (device_caps->low_latency) {
987     hr = gst_mf_transform_set_codec_api_boolean (transform,
988         &CODECAPI_AVLowLatencyMode, self->low_latency);
989     WARNING_HR (hr, CODECAPI_AVLowLatencyMode);
990   }
991 
992   if (device_caps->min_qp) {
993     hr = gst_mf_transform_set_codec_api_uint32 (transform,
994         &CODECAPI_AVEncVideoMinQP, self->min_qp);
995     WARNING_HR (hr, CODECAPI_AVEncVideoMinQP);
996   }
997 
998   if (device_caps->max_qp) {
999     hr = gst_mf_transform_set_codec_api_uint32 (transform,
1000         &CODECAPI_AVEncVideoMaxQP, self->max_qp);
1001     WARNING_HR (hr, CODECAPI_AVEncVideoMaxQP);
1002   }
1003 
1004   if (device_caps->frame_type_qp) {
1005     guint64 type_qp = 0;
1006 
1007     type_qp =
1008         (guint64) self->qp_i | (guint64) self->qp_p << 16 |
1009         (guint64) self->qp_b << 32;
1010     hr = gst_mf_transform_set_codec_api_uint64 (transform,
1011         &CODECAPI_AVEncVideoEncodeFrameTypeQP, type_qp);
1012     WARNING_HR (hr, CODECAPI_AVEncVideoEncodeFrameTypeQP);
1013   }
1014 
1015   if (device_caps->max_num_ref) {
1016     hr = gst_mf_transform_set_codec_api_uint32 (transform,
1017         &CODECAPI_AVEncVideoMaxNumRefFrame, self->max_num_ref);
1018     WARNING_HR (hr, CODECAPI_AVEncVideoMaxNumRefFrame);
1019   }
1020 
1021   return TRUE;
1022 }
1023 
1024 static gboolean
gst_mf_h264_enc_set_src_caps(GstMFVideoEnc * mfenc,GstVideoCodecState * state,IMFMediaType * output_type)1025 gst_mf_h264_enc_set_src_caps (GstMFVideoEnc * mfenc,
1026     GstVideoCodecState * state, IMFMediaType * output_type)
1027 {
1028   GstMFH264Enc *self = (GstMFH264Enc *) mfenc;
1029   GstVideoCodecState *out_state;
1030   GstStructure *s;
1031   GstCaps *out_caps;
1032   GstTagList *tags;
1033 
1034   out_caps = gst_caps_new_empty_simple ("video/x-h264");
1035   s = gst_caps_get_structure (out_caps, 0);
1036 
1037   gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream",
1038       "alignment", G_TYPE_STRING, "au", "profile",
1039       G_TYPE_STRING, self->profile_str, NULL);
1040 
1041   out_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
1042       out_caps, state);
1043 
1044   GST_INFO_OBJECT (self, "output caps: %" GST_PTR_FORMAT, out_state->caps);
1045 
1046   /* encoder will keep it around for us */
1047   gst_video_codec_state_unref (out_state);
1048 
1049   tags = gst_tag_list_new_empty ();
1050   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1051       gst_element_get_metadata (GST_ELEMENT_CAST (self),
1052           GST_ELEMENT_METADATA_LONGNAME), NULL);
1053   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (self), tags,
1054       GST_TAG_MERGE_REPLACE);
1055   gst_tag_list_unref (tags);
1056 
1057   return TRUE;
1058 }
1059 
1060 void
gst_mf_h264_enc_plugin_init(GstPlugin * plugin,guint rank,GList * d3d11_device)1061 gst_mf_h264_enc_plugin_init (GstPlugin * plugin, guint rank,
1062     GList * d3d11_device)
1063 {
1064   GTypeInfo type_info = {
1065     sizeof (GstMFH264EncClass),
1066     NULL,
1067     NULL,
1068     (GClassInitFunc) gst_mf_h264_enc_class_init,
1069     NULL,
1070     NULL,
1071     sizeof (GstMFH264Enc),
1072     0,
1073     (GInstanceInitFunc) gst_mf_h264_enc_init,
1074   };
1075   GUID subtype = MFVideoFormat_H264;
1076 
1077   GST_DEBUG_CATEGORY_INIT (gst_mf_h264_enc_debug, "mfh264enc", 0, "mfh264enc");
1078 
1079   gst_mf_video_enc_register (plugin, rank, &subtype, &type_info, d3d11_device);
1080 }
1081