• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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