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