1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Oblong Industries, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /**
33 * SECTION: element-msdkh264enc
34 * @title: msdkh264enc
35 * @short_description: Intel MSDK H264 encoder
36 *
37 * H264 video encoder based on Intel MFX
38 *
39 * ## Example launch line
40 * ```
41 * gst-launch-1.0 videotestsrc num-buffers=90 ! msdkh264enc ! h264parse ! filesink location=output.h264
42 * ```
43 *
44 * Since: 1.12
45 *
46 */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif
51
52 #include "gstmsdkh264enc.h"
53
54 #include <gst/base/base.h>
55 #include <gst/pbutils/pbutils.h>
56 #include <string.h>
57
58 GST_DEBUG_CATEGORY_EXTERN (gst_msdkh264enc_debug);
59 #define GST_CAT_DEFAULT gst_msdkh264enc_debug
60
61 enum
62 {
63 PROP_CABAC = GST_MSDKENC_PROP_MAX,
64 #ifndef GST_REMOVE_DEPRECATED
65 PROP_LOW_POWER,
66 #endif
67 PROP_FRAME_PACKING,
68 PROP_RC_LA_DOWNSAMPLING,
69 PROP_TRELLIS,
70 PROP_MAX_SLICE_SIZE,
71 PROP_B_PYRAMID,
72 PROP_TUNE_MODE,
73 PROP_P_PYRAMID,
74 PROP_MIN_QP,
75 PROP_MAX_QP,
76 PROP_INTRA_REFRESH_TYPE,
77 PROP_DBLK_IDC,
78 };
79
80 enum
81 {
82 GST_MSDK_FLAG_LOW_POWER = 1 << 0,
83 GST_MSDK_FLAG_TUNE_MODE = 1 << 1,
84 };
85
86 #define PROP_CABAC_DEFAULT TRUE
87 #define PROP_LOWPOWER_DEFAULT FALSE
88 #define PROP_FRAME_PACKING_DEFAULT -1
89 #define PROP_RC_LA_DOWNSAMPLING_DEFAULT MFX_LOOKAHEAD_DS_UNKNOWN
90 #define PROP_TRELLIS_DEFAULT _MFX_TRELLIS_NONE
91 #define PROP_MAX_SLICE_SIZE_DEFAULT 0
92 #define PROP_B_PYRAMID_DEFAULT FALSE
93 #define PROP_TUNE_MODE_DEFAULT MFX_CODINGOPTION_UNKNOWN
94 #define PROP_P_PYRAMID_DEFAULT FALSE
95 #define PROP_MIN_QP_DEFAULT 0
96 #define PROP_MAX_QP_DEFAULT 0
97 #define PROP_INTRA_REFRESH_TYPE_DEFAULT MFX_REFRESH_NO
98 #define PROP_DBLK_IDC_DEFAULT 0
99
100 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
101 GST_PAD_SRC,
102 GST_PAD_ALWAYS,
103 GST_STATIC_CAPS ("video/x-h264, "
104 "framerate = (fraction) [0/1, MAX], "
105 "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ], "
106 "stream-format = (string) byte-stream , alignment = (string) au , "
107 "profile = (string) { high, main, baseline, constrained-baseline }")
108 );
109
110 static GType
gst_msdkh264enc_frame_packing_get_type(void)111 gst_msdkh264enc_frame_packing_get_type (void)
112 {
113 static GType format_type = 0;
114 static const GEnumValue format_types[] = {
115 {GST_VIDEO_MULTIVIEW_FRAME_PACKING_NONE, "None (default)", "none"},
116 {GST_VIDEO_MULTIVIEW_FRAME_PACKING_SIDE_BY_SIDE, "Side by Side",
117 "side-by-side"},
118 {GST_VIDEO_MULTIVIEW_FRAME_PACKING_TOP_BOTTOM, "Top Bottom", "top-bottom"},
119 {0, NULL, NULL}
120 };
121
122 if (!format_type) {
123 format_type =
124 g_enum_register_static ("GstMsdkH264EncFramePacking", format_types);
125 }
126
127 return format_type;
128 }
129
130 #define gst_msdkh264enc_parent_class parent_class
131 G_DEFINE_TYPE (GstMsdkH264Enc, gst_msdkh264enc, GST_TYPE_MSDKENC);
132
133 static void
gst_msdkh264enc_insert_sei(GstMsdkH264Enc * thiz,GstVideoCodecFrame * frame,GstMemory * sei_mem)134 gst_msdkh264enc_insert_sei (GstMsdkH264Enc * thiz, GstVideoCodecFrame * frame,
135 GstMemory * sei_mem)
136 {
137 GstBuffer *new_buffer;
138
139 if (!thiz->parser)
140 thiz->parser = gst_h264_nal_parser_new ();
141
142 new_buffer = gst_h264_parser_insert_sei (thiz->parser,
143 frame->output_buffer, sei_mem);
144
145 if (!new_buffer) {
146 GST_WARNING_OBJECT (thiz, "Cannot insert SEI nal into AU buffer");
147 return;
148 }
149
150 gst_buffer_unref (frame->output_buffer);
151 frame->output_buffer = new_buffer;
152 }
153
154 static void
gst_msdkh264enc_add_cc(GstMsdkH264Enc * thiz,GstVideoCodecFrame * frame)155 gst_msdkh264enc_add_cc (GstMsdkH264Enc * thiz, GstVideoCodecFrame * frame)
156 {
157 GstVideoCaptionMeta *cc_meta;
158 gpointer iter = NULL;
159 GstBuffer *in_buf = frame->input_buffer;
160 GstMemory *mem = NULL;
161
162 if (thiz->cc_sei_array)
163 g_array_set_size (thiz->cc_sei_array, 0);
164
165 while ((cc_meta =
166 (GstVideoCaptionMeta *) gst_buffer_iterate_meta_filtered (in_buf,
167 &iter, GST_VIDEO_CAPTION_META_API_TYPE))) {
168 GstH264SEIMessage sei;
169 GstH264RegisteredUserData *rud;
170 guint8 *data;
171
172 if (cc_meta->caption_type != GST_VIDEO_CAPTION_TYPE_CEA708_RAW)
173 continue;
174
175 memset (&sei, 0, sizeof (GstH264SEIMessage));
176 sei.payloadType = GST_H264_SEI_REGISTERED_USER_DATA;
177 rud = &sei.payload.registered_user_data;
178
179 rud->country_code = 181;
180 rud->size = cc_meta->size + 10;
181
182 data = g_malloc (rud->size);
183 memcpy (data + 9, cc_meta->data, cc_meta->size);
184
185 data[0] = 0; /* 16-bits itu_t_t35_provider_code */
186 data[1] = 49;
187 data[2] = 'G'; /* 32-bits ATSC_user_identifier */
188 data[3] = 'A';
189 data[4] = '9';
190 data[5] = '4';
191 data[6] = 3; /* 8-bits ATSC1_data_user_data_type_code */
192 /* 8-bits:
193 * 1 bit process_em_data_flag (0)
194 * 1 bit process_cc_data_flag (1)
195 * 1 bit additional_data_flag (0)
196 * 5-bits cc_count
197 */
198 data[7] = ((cc_meta->size / 3) & 0x1f) | 0x40;
199 data[8] = 255; /* 8 bits em_data, unused */
200 data[cc_meta->size + 9] = 255; /* 8 marker bits */
201
202 rud->data = data;
203
204 if (!thiz->cc_sei_array) {
205 thiz->cc_sei_array =
206 g_array_new (FALSE, FALSE, sizeof (GstH264SEIMessage));
207 g_array_set_clear_func (thiz->cc_sei_array,
208 (GDestroyNotify) gst_h264_sei_clear);
209 }
210
211 g_array_append_val (thiz->cc_sei_array, sei);
212 }
213
214 if (!thiz->cc_sei_array || !thiz->cc_sei_array->len)
215 return;
216
217 mem = gst_h264_create_sei_memory (4, thiz->cc_sei_array);
218
219 if (!mem) {
220 GST_WARNING_OBJECT (thiz, "Cannot create SEI nal unit");
221 return;
222 }
223
224 GST_DEBUG_OBJECT (thiz,
225 "Inserting %d closed caption SEI message(s)", thiz->cc_sei_array->len);
226
227 gst_msdkh264enc_insert_sei (thiz, frame, mem);
228 gst_memory_unref (mem);
229 }
230
231 static GstFlowReturn
gst_msdkh264enc_pre_push(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)232 gst_msdkh264enc_pre_push (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
233 {
234 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (encoder);
235
236 if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame) && thiz->frame_packing_sei) {
237 /* Insert frame packing SEI
238 * FIXME: This assumes it does not exist in the stream, which is not
239 * going to be true anymore once this is fixed:
240 * https://github.com/Intel-Media-SDK/MediaSDK/issues/13
241 */
242 GST_DEBUG_OBJECT (thiz, "Inserting SEI Frame Packing for multiview");
243 gst_msdkh264enc_insert_sei (thiz, frame, thiz->frame_packing_sei);
244 }
245
246 gst_msdkh264enc_add_cc (thiz, frame);
247
248 return GST_FLOW_OK;
249 }
250
251 static gboolean
gst_msdkh264enc_set_format(GstMsdkEnc * encoder)252 gst_msdkh264enc_set_format (GstMsdkEnc * encoder)
253 {
254 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (encoder);
255 GstCaps *template_caps;
256 GstCaps *allowed_caps = NULL;
257
258 thiz->profile = 0;
259 thiz->level = 0;
260
261 template_caps = gst_static_pad_template_get_caps (&src_factory);
262 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
263
264 /* If downstream has ANY caps let encoder decide profile and level */
265 if (allowed_caps == template_caps) {
266 GST_INFO_OBJECT (thiz,
267 "downstream has ANY caps, profile/level set to auto");
268 } else if (allowed_caps) {
269 GstStructure *s;
270 const gchar *profile;
271 const gchar *level;
272
273 if (gst_caps_is_empty (allowed_caps)) {
274 gst_caps_unref (allowed_caps);
275 gst_caps_unref (template_caps);
276 return FALSE;
277 }
278
279 allowed_caps = gst_caps_make_writable (allowed_caps);
280 allowed_caps = gst_caps_fixate (allowed_caps);
281 s = gst_caps_get_structure (allowed_caps, 0);
282
283 profile = gst_structure_get_string (s, "profile");
284 if (profile) {
285 if (!strcmp (profile, "high")) {
286 thiz->profile = MFX_PROFILE_AVC_HIGH;
287 } else if (!strcmp (profile, "main")) {
288 thiz->profile = MFX_PROFILE_AVC_MAIN;
289 } else if (!strcmp (profile, "baseline")) {
290 thiz->profile = MFX_PROFILE_AVC_BASELINE;
291 } else if (!strcmp (profile, "constrained-baseline")) {
292 thiz->profile = MFX_PROFILE_AVC_CONSTRAINED_BASELINE;
293 } else {
294 g_assert_not_reached ();
295 }
296 }
297
298 level = gst_structure_get_string (s, "level");
299 if (level) {
300 thiz->level = gst_codec_utils_h264_get_level_idc (level);
301 }
302
303 gst_caps_unref (allowed_caps);
304 }
305
306 gst_caps_unref (template_caps);
307
308 if (thiz->frame_packing_sei) {
309 gst_memory_unref (thiz->frame_packing_sei);
310 thiz->frame_packing_sei = NULL;
311 }
312
313 /* prepare frame packing SEI message */
314 if (encoder->input_state) {
315 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
316
317 /* use property value if any */
318 if (thiz->frame_packing != GST_VIDEO_MULTIVIEW_MODE_NONE) {
319 mode = (GstVideoMultiviewMode) thiz->frame_packing;
320 } else {
321 mode = GST_VIDEO_INFO_MULTIVIEW_MODE (&encoder->input_state->info);
322 }
323
324 if (mode == GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE ||
325 mode == GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM) {
326 GstH264SEIMessage sei;
327 GstH264FramePacking *frame_packing;
328 GArray *array = g_array_new (FALSE, FALSE, sizeof (GstH264SEIMessage));
329
330 g_array_set_clear_func (thiz->cc_sei_array,
331 (GDestroyNotify) gst_h264_sei_clear);
332
333 GST_DEBUG_OBJECT (thiz,
334 "Prepare frame packing SEI data for multiview mode %d", mode);
335
336 memset (&sei, 0, sizeof (GstH264SEIMessage));
337
338 sei.payloadType = GST_H264_SEI_FRAME_PACKING;
339 frame_packing = &sei.payload.frame_packing;
340 frame_packing->frame_packing_id = 0;
341 frame_packing->frame_packing_cancel_flag = 0;
342 frame_packing->frame_packing_type =
343 (mode == GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE ?
344 GST_H264_FRAME_PACKING_SIDE_BY_SIDE :
345 GST_H264_FRMAE_PACKING_TOP_BOTTOM);
346 /* we don't do this */
347 frame_packing->quincunx_sampling_flag = 0;
348 /* 0: unspecified */
349 /* 1: frame 0 will be left view and frame 1 will be right view */
350 frame_packing->content_interpretation_type = 1;
351 /* we didn't do flip */
352 frame_packing->spatial_flipping_flag = 0;
353 frame_packing->frame0_flipped_flag = 0;
354 /* must be zero for frame_packing_type != 2 */
355 frame_packing->field_views_flag = 0;
356 /* must be zero for frame_packing_type != 5 */
357 frame_packing->current_frame_is_frame0_flag = 0;
358 /* may or may not used to reference each other */
359 frame_packing->frame0_self_contained_flag = 0;
360 frame_packing->frame1_self_contained_flag = 0;
361
362 frame_packing->frame0_grid_position_x = 0;
363 frame_packing->frame0_grid_position_y = 0;
364 frame_packing->frame1_grid_position_x = 0;
365 frame_packing->frame1_grid_position_y = 0;
366
367 /* will be applied to this GOP */
368 frame_packing->frame_packing_repetition_period = 1;
369
370 g_array_append_val (array, sei);
371
372 thiz->frame_packing_sei = gst_h264_create_sei_memory (4, array);
373 g_array_unref (array);
374 }
375 }
376
377 return TRUE;
378 }
379
380 static gboolean
gst_msdkh264enc_configure(GstMsdkEnc * encoder)381 gst_msdkh264enc_configure (GstMsdkEnc * encoder)
382 {
383 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (encoder);
384
385 encoder->param.mfx.LowPower = thiz->tune_mode;
386 encoder->param.mfx.CodecId = MFX_CODEC_AVC;
387 encoder->param.mfx.CodecProfile = thiz->profile;
388 encoder->param.mfx.CodecLevel = thiz->level;
389
390 thiz->option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION;
391 thiz->option.Header.BufferSz = sizeof (thiz->option);
392 if (thiz->profile == MFX_PROFILE_AVC_CONSTRAINED_BASELINE ||
393 thiz->profile == MFX_PROFILE_AVC_BASELINE ||
394 thiz->profile == MFX_PROFILE_AVC_EXTENDED) {
395 thiz->option.CAVLC = MFX_CODINGOPTION_ON;
396 } else {
397 thiz->option.CAVLC =
398 (thiz->cabac ? MFX_CODINGOPTION_OFF : MFX_CODINGOPTION_ON);
399 }
400
401 gst_msdkenc_add_extra_param (encoder, (mfxExtBuffer *) & thiz->option);
402
403 encoder->option2.Trellis = thiz->trellis ? thiz->trellis : MFX_TRELLIS_OFF;
404 encoder->option2.MaxSliceSize = thiz->max_slice_size;
405 encoder->option2.MinQPI = encoder->option2.MinQPP = encoder->option2.MinQPB =
406 thiz->min_qp;
407 encoder->option2.MaxQPI = encoder->option2.MaxQPP = encoder->option2.MaxQPB =
408 thiz->max_qp;
409 encoder->option2.IntRefType = thiz->intra_refresh_type;
410 encoder->option2.DisableDeblockingIdc = thiz->dblk_idc;
411
412 if (encoder->rate_control == MFX_RATECONTROL_LA ||
413 encoder->rate_control == MFX_RATECONTROL_LA_HRD ||
414 encoder->rate_control == MFX_RATECONTROL_LA_ICQ)
415 encoder->option2.LookAheadDS = thiz->lookahead_ds;
416
417 if (thiz->b_pyramid) {
418 encoder->option2.BRefType = MFX_B_REF_PYRAMID;
419 /* Don't define Gop structure for B-pyramid, otherwise EncodeInit
420 * will throw Invalid param error */
421 encoder->param.mfx.GopRefDist = 0;
422 }
423
424 if (thiz->p_pyramid) {
425 encoder->option3.PRefType = MFX_P_REF_PYRAMID;
426 /* MFX_P_REF_PYRAMID is available for GopRefDist = 1 */
427 encoder->param.mfx.GopRefDist = 1;
428 /* SDK decides the DPB size for P pyramid */
429 encoder->param.mfx.NumRefFrame = 0;
430 encoder->enable_extopt3 = TRUE;
431 }
432
433 /* Enable Extended coding options */
434 gst_msdkenc_ensure_extended_coding_options (encoder);
435
436 return TRUE;
437 }
438
439 static inline const gchar *
profile_to_string(gint profile)440 profile_to_string (gint profile)
441 {
442 switch (profile) {
443 case MFX_PROFILE_AVC_HIGH:
444 return "high";
445 case MFX_PROFILE_AVC_MAIN:
446 return "main";
447 case MFX_PROFILE_AVC_BASELINE:
448 return "baseline";
449 case MFX_PROFILE_AVC_CONSTRAINED_BASELINE:
450 return "constrained-baseline";
451 default:
452 break;
453 }
454
455 return NULL;
456 }
457
458 static inline const gchar *
level_to_string(gint level)459 level_to_string (gint level)
460 {
461 switch (level) {
462 case MFX_LEVEL_AVC_1:
463 return "1";
464 case MFX_LEVEL_AVC_1b:
465 return "1.1";
466 case MFX_LEVEL_AVC_11:
467 return "1.1";
468 case MFX_LEVEL_AVC_12:
469 return "1.2";
470 case MFX_LEVEL_AVC_13:
471 return "1.3";
472 case MFX_LEVEL_AVC_2:
473 return "2";
474 case MFX_LEVEL_AVC_21:
475 return "2.1";
476 case MFX_LEVEL_AVC_22:
477 return "2.2";
478 case MFX_LEVEL_AVC_3:
479 return "3";
480 case MFX_LEVEL_AVC_31:
481 return "3.1";
482 case MFX_LEVEL_AVC_32:
483 return "3.2";
484 case MFX_LEVEL_AVC_4:
485 return "4";
486 case MFX_LEVEL_AVC_41:
487 return "4.1";
488 case MFX_LEVEL_AVC_42:
489 return "4.2";
490 case MFX_LEVEL_AVC_5:
491 return "5";
492 case MFX_LEVEL_AVC_51:
493 return "5.1";
494 case MFX_LEVEL_AVC_52:
495 return "5.2";
496 default:
497 break;
498 }
499
500 return NULL;
501 }
502
503 static GstCaps *
gst_msdkh264enc_set_src_caps(GstMsdkEnc * encoder)504 gst_msdkh264enc_set_src_caps (GstMsdkEnc * encoder)
505 {
506 GstCaps *caps;
507 GstStructure *structure;
508 const gchar *profile;
509 const gchar *level;
510
511 caps = gst_caps_new_empty_simple ("video/x-h264");
512 structure = gst_caps_get_structure (caps, 0);
513
514 gst_structure_set (structure, "stream-format", G_TYPE_STRING, "byte-stream",
515 NULL);
516
517 gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
518
519 profile = profile_to_string (encoder->param.mfx.CodecProfile);
520 if (profile)
521 gst_structure_set (structure, "profile", G_TYPE_STRING, profile, NULL);
522
523 level = level_to_string (encoder->param.mfx.CodecLevel);
524 if (level)
525 gst_structure_set (structure, "level", G_TYPE_STRING, level, NULL);
526
527 return caps;
528 }
529
530 static void
gst_msdkh264enc_dispose(GObject * object)531 gst_msdkh264enc_dispose (GObject * object)
532 {
533 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (object);
534
535 if (thiz->frame_packing_sei) {
536 gst_memory_unref (thiz->frame_packing_sei);
537 thiz->frame_packing_sei = NULL;
538 }
539
540 G_OBJECT_CLASS (parent_class)->dispose (object);
541 }
542
543 static void
gst_msdkh264enc_finalize(GObject * object)544 gst_msdkh264enc_finalize (GObject * object)
545 {
546 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (object);
547
548 if (thiz->parser)
549 gst_h264_nal_parser_free (thiz->parser);
550 if (thiz->cc_sei_array)
551 g_array_unref (thiz->cc_sei_array);
552
553 G_OBJECT_CLASS (parent_class)->finalize (object);
554 }
555
556 static void
gst_msdkh264enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)557 gst_msdkh264enc_set_property (GObject * object, guint prop_id,
558 const GValue * value, GParamSpec * pspec)
559 {
560 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (object);
561
562 if (gst_msdkenc_set_common_property (object, prop_id, value, pspec))
563 return;
564
565 GST_OBJECT_LOCK (thiz);
566
567 switch (prop_id) {
568 case PROP_CABAC:
569 thiz->cabac = g_value_get_boolean (value);
570 break;
571 #ifndef GST_REMOVE_DEPRECATED
572 case PROP_LOW_POWER:
573 thiz->lowpower = g_value_get_boolean (value);
574 thiz->prop_flag |= GST_MSDK_FLAG_LOW_POWER;
575
576 /* Ignore it if user set tune mode explicitly */
577 if (!(thiz->prop_flag & GST_MSDK_FLAG_TUNE_MODE))
578 thiz->tune_mode =
579 thiz->lowpower ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
580
581 break;
582 #endif
583 case PROP_FRAME_PACKING:
584 thiz->frame_packing = g_value_get_enum (value);
585 break;
586 case PROP_RC_LA_DOWNSAMPLING:
587 thiz->lookahead_ds = g_value_get_enum (value);
588 break;
589 case PROP_TRELLIS:
590 thiz->trellis = g_value_get_flags (value);
591 break;
592 case PROP_MAX_SLICE_SIZE:
593 thiz->max_slice_size = g_value_get_uint (value);
594 break;
595 case PROP_B_PYRAMID:
596 thiz->b_pyramid = g_value_get_boolean (value);
597 break;
598 case PROP_TUNE_MODE:
599 thiz->tune_mode = g_value_get_enum (value);
600 thiz->prop_flag |= GST_MSDK_FLAG_TUNE_MODE;
601 break;
602 case PROP_P_PYRAMID:
603 thiz->p_pyramid = g_value_get_boolean (value);
604 break;
605 case PROP_MIN_QP:
606 thiz->min_qp = g_value_get_uint (value);
607 break;
608 case PROP_MAX_QP:
609 thiz->max_qp = g_value_get_uint (value);
610 break;
611 case PROP_INTRA_REFRESH_TYPE:
612 thiz->intra_refresh_type = g_value_get_enum (value);
613 break;
614 case PROP_DBLK_IDC:
615 thiz->dblk_idc = g_value_get_uint (value);
616 break;
617 default:
618 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
619 break;
620 }
621 GST_OBJECT_UNLOCK (thiz);
622 return;
623 }
624
625 static void
gst_msdkh264enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)626 gst_msdkh264enc_get_property (GObject * object, guint prop_id, GValue * value,
627 GParamSpec * pspec)
628 {
629 GstMsdkH264Enc *thiz = GST_MSDKH264ENC (object);
630
631 if (gst_msdkenc_get_common_property (object, prop_id, value, pspec))
632 return;
633
634 GST_OBJECT_LOCK (thiz);
635 switch (prop_id) {
636 case PROP_CABAC:
637 g_value_set_boolean (value, thiz->cabac);
638 break;
639 #ifndef GST_REMOVE_DEPRECATED
640 case PROP_LOW_POWER:
641 g_value_set_boolean (value, thiz->lowpower);
642 break;
643 #endif
644 case PROP_FRAME_PACKING:
645 g_value_set_enum (value, thiz->frame_packing);
646 break;
647 case PROP_RC_LA_DOWNSAMPLING:
648 g_value_set_enum (value, thiz->lookahead_ds);
649 break;
650 case PROP_TRELLIS:
651 g_value_set_flags (value, thiz->trellis);
652 break;
653 case PROP_MAX_SLICE_SIZE:
654 g_value_set_uint (value, thiz->max_slice_size);
655 break;
656 case PROP_B_PYRAMID:
657 g_value_set_boolean (value, thiz->b_pyramid);
658 break;
659 case PROP_TUNE_MODE:
660 g_value_set_enum (value, thiz->tune_mode);
661 break;
662 case PROP_P_PYRAMID:
663 g_value_set_boolean (value, thiz->p_pyramid);
664 break;
665 case PROP_MIN_QP:
666 g_value_set_uint (value, thiz->min_qp);
667 break;
668 case PROP_MAX_QP:
669 g_value_set_uint (value, thiz->max_qp);
670 break;
671 case PROP_INTRA_REFRESH_TYPE:
672 g_value_set_enum (value, thiz->intra_refresh_type);
673 break;
674 case PROP_DBLK_IDC:
675 g_value_set_uint (value, thiz->dblk_idc);
676 break;
677 default:
678 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
679 break;
680 }
681 GST_OBJECT_UNLOCK (thiz);
682 }
683
684 static gboolean
gst_msdkh264enc_need_reconfig(GstMsdkEnc * encoder,GstVideoCodecFrame * frame)685 gst_msdkh264enc_need_reconfig (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
686 {
687 GstMsdkH264Enc *h264enc = GST_MSDKH264ENC (encoder);
688
689 return gst_msdkenc_get_roi_params (encoder, frame, h264enc->roi);
690 }
691
692 static void
gst_msdkh264enc_set_extra_params(GstMsdkEnc * encoder,GstVideoCodecFrame * frame)693 gst_msdkh264enc_set_extra_params (GstMsdkEnc * encoder,
694 GstVideoCodecFrame * frame)
695 {
696 GstMsdkH264Enc *h264enc = GST_MSDKH264ENC (encoder);
697
698 if (h264enc->roi[0].NumROI)
699 gst_msdkenc_add_extra_param (encoder, (mfxExtBuffer *) & h264enc->roi[0]);
700 }
701
702 static void
gst_msdkh264enc_class_init(GstMsdkH264EncClass * klass)703 gst_msdkh264enc_class_init (GstMsdkH264EncClass * klass)
704 {
705 GObjectClass *gobject_class;
706 GstElementClass *element_class;
707 GstVideoEncoderClass *videoencoder_class;
708 GstMsdkEncClass *encoder_class;
709
710 gobject_class = G_OBJECT_CLASS (klass);
711 element_class = GST_ELEMENT_CLASS (klass);
712 videoencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
713 encoder_class = GST_MSDKENC_CLASS (klass);
714
715 gobject_class->dispose = gst_msdkh264enc_dispose;
716 gobject_class->finalize = gst_msdkh264enc_finalize;
717 gobject_class->set_property = gst_msdkh264enc_set_property;
718 gobject_class->get_property = gst_msdkh264enc_get_property;
719
720 videoencoder_class->pre_push = gst_msdkh264enc_pre_push;
721
722 encoder_class->set_format = gst_msdkh264enc_set_format;
723 encoder_class->configure = gst_msdkh264enc_configure;
724 encoder_class->set_src_caps = gst_msdkh264enc_set_src_caps;
725 encoder_class->need_reconfig = gst_msdkh264enc_need_reconfig;
726 encoder_class->set_extra_params = gst_msdkh264enc_set_extra_params;
727
728 gst_msdkenc_install_common_properties (encoder_class);
729
730 g_object_class_install_property (gobject_class, PROP_CABAC,
731 g_param_spec_boolean ("cabac", "CABAC", "Enable CABAC entropy coding",
732 PROP_CABAC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
733
734 #ifndef GST_REMOVE_DEPRECATED
735 g_object_class_install_property (gobject_class, PROP_LOW_POWER,
736 g_param_spec_boolean ("low-power", "Low power",
737 "Enable low power mode (DEPRECATED, use tune instead)",
738 PROP_LOWPOWER_DEFAULT,
739 G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
740 #endif
741
742 g_object_class_install_property (gobject_class, PROP_FRAME_PACKING,
743 g_param_spec_enum ("frame-packing", "Frame Packing",
744 "Set frame packing mode for Stereoscopic content",
745 gst_msdkh264enc_frame_packing_get_type (), PROP_FRAME_PACKING_DEFAULT,
746 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
747
748 g_object_class_install_property (gobject_class, PROP_RC_LA_DOWNSAMPLING,
749 g_param_spec_enum ("rc-lookahead-ds", "Look-ahead Downsampling",
750 "Down sampling mode in look ahead bitrate control",
751 gst_msdkenc_rc_lookahead_ds_get_type (),
752 PROP_RC_LA_DOWNSAMPLING_DEFAULT,
753 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
754
755 g_object_class_install_property (gobject_class, PROP_TRELLIS,
756 g_param_spec_flags ("trellis", "Trellis",
757 "Enable Trellis Quantization",
758 gst_msdkenc_trellis_quantization_get_type (), _MFX_TRELLIS_NONE,
759 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760
761 g_object_class_install_property (gobject_class, PROP_MAX_SLICE_SIZE,
762 g_param_spec_uint ("max-slice-size", "Max Slice Size",
763 "Maximum slice size in bytes (if enabled MSDK will ignore the control over num-slices)",
764 0, G_MAXUINT32, PROP_MAX_SLICE_SIZE_DEFAULT,
765 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
766
767 g_object_class_install_property (gobject_class, PROP_B_PYRAMID,
768 g_param_spec_boolean ("b-pyramid", "B-pyramid",
769 "Enable B-Pyramid Reference structure", FALSE,
770 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
771
772 g_object_class_install_property (gobject_class, PROP_TUNE_MODE,
773 g_param_spec_enum ("tune", "Encoder tuning",
774 "Encoder tuning option",
775 gst_msdkenc_tune_mode_get_type (), PROP_TUNE_MODE_DEFAULT,
776 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
777
778 g_object_class_install_property (gobject_class, PROP_P_PYRAMID,
779 g_param_spec_boolean ("p-pyramid", "P-pyramid",
780 "Enable P-Pyramid Reference structure", FALSE,
781 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
782
783 g_object_class_install_property (gobject_class, PROP_MIN_QP,
784 g_param_spec_uint ("min-qp", "Min QP",
785 "Minimal quantizer for I/P/B frames",
786 0, 51, PROP_MIN_QP_DEFAULT,
787 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
788
789 g_object_class_install_property (gobject_class, PROP_MAX_QP,
790 g_param_spec_uint ("max-qp", "Max QP",
791 "Maximum quantizer for I/P/B frames",
792 0, 51, PROP_MAX_QP_DEFAULT,
793 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
794
795 g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_TYPE,
796 g_param_spec_enum ("intra-refresh-type", "Intra refresh type",
797 "Set intra refresh type",
798 gst_msdkenc_intra_refresh_type_get_type (),
799 PROP_INTRA_REFRESH_TYPE_DEFAULT,
800 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
801
802 g_object_class_install_property (gobject_class, PROP_DBLK_IDC,
803 g_param_spec_uint ("dblk-idc", "Disable Deblocking Idc",
804 "Option of disable deblocking idc",
805 0, 2, PROP_DBLK_IDC_DEFAULT,
806 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
807
808 gst_element_class_set_static_metadata (element_class,
809 "Intel MSDK H264 encoder", "Codec/Encoder/Video/Hardware",
810 "H264 video encoder based on " MFX_API_SDK,
811 "Josep Torra <jtorra@oblong.com>");
812 gst_element_class_add_static_pad_template (element_class, &src_factory);
813 }
814
815 static void
gst_msdkh264enc_init(GstMsdkH264Enc * thiz)816 gst_msdkh264enc_init (GstMsdkH264Enc * thiz)
817 {
818 thiz->cabac = PROP_CABAC_DEFAULT;
819 thiz->lowpower = PROP_LOWPOWER_DEFAULT;
820 thiz->frame_packing = PROP_FRAME_PACKING_DEFAULT;
821 thiz->lookahead_ds = PROP_RC_LA_DOWNSAMPLING_DEFAULT;
822 thiz->trellis = PROP_TRELLIS_DEFAULT;
823 thiz->max_slice_size = PROP_MAX_SLICE_SIZE_DEFAULT;
824 thiz->b_pyramid = PROP_B_PYRAMID_DEFAULT;
825 thiz->tune_mode = PROP_TUNE_MODE_DEFAULT;
826 thiz->p_pyramid = PROP_P_PYRAMID_DEFAULT;
827 thiz->min_qp = PROP_MIN_QP_DEFAULT;
828 thiz->max_qp = PROP_MAX_QP_DEFAULT;
829 thiz->intra_refresh_type = PROP_INTRA_REFRESH_TYPE_DEFAULT;
830 thiz->dblk_idc = PROP_DBLK_IDC_DEFAULT;
831 }
832