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