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