taglist, plugins: fix compiler warnings with GLib >= 2.76
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / msdk / gstmsdkh265enc.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-msdkh265enc
34  * @title: msdkh265enc
35  * @short_description: Intel MSDK H265 encoder
36  *
37  * H265 video encoder based on Intel MFX
38  *
39  * ## Example launch line
40  * ```
41  * gst-launch-1.0 videotestsrc num-buffers=90 ! msdkh265enc ! h265parse ! filesink location=output.h265
42  * ```
43  *
44  * Since: 1.12
45  *
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #  include <config.h>
50 #endif
51
52 #include <gst/allocators/gstdmabuf.h>
53
54 #include "gstmsdkh265enc.h"
55
56 GST_DEBUG_CATEGORY_EXTERN (gst_msdkh265enc_debug);
57 #define GST_CAT_DEFAULT gst_msdkh265enc_debug
58
59 enum
60 {
61 #ifndef GST_REMOVE_DEPRECATED
62   PROP_LOW_POWER = GST_MSDKENC_PROP_MAX,
63   PROP_TILE_ROW,
64 #else
65   PROP_TILE_ROW = GST_MSDKENC_PROP_MAX,
66 #endif
67   PROP_TILE_COL,
68   PROP_MAX_SLICE_SIZE,
69   PROP_TUNE_MODE,
70   PROP_TRANSFORM_SKIP,
71   PROP_B_PYRAMID,
72   PROP_P_PYRAMID,
73   PROP_MIN_QP,
74   PROP_MAX_QP,
75   PROP_INTRA_REFRESH_TYPE,
76   PROP_INTRA_REFRESH_CYCLE_SIZE,
77   PROP_INTRA_REFRESH_QP_DELTA,
78   PROP_INTRA_REFRESH_CYCLE_DIST,
79   PROP_DBLK_IDC,
80 };
81
82 enum
83 {
84   GST_MSDK_FLAG_LOW_POWER = 1 << 0,
85   GST_MSDK_FLAG_TUNE_MODE = 1 << 1,
86 };
87
88 #define PROP_LOWPOWER_DEFAULT                 FALSE
89 #define PROP_TILE_ROW_DEFAULT                 1
90 #define PROP_TILE_COL_DEFAULT                 1
91 #define PROP_MAX_SLICE_SIZE_DEFAULT           0
92 #define PROP_TUNE_MODE_DEFAULT                MFX_CODINGOPTION_UNKNOWN
93 #define PROP_TRANSFORM_SKIP_DEFAULT           MFX_CODINGOPTION_UNKNOWN
94 #define PROP_B_PYRAMID_DEFAULT                FALSE
95 #define PROP_P_PYRAMID_DEFAULT                FALSE
96 #define PROP_MIN_QP_DEFAULT                   0
97 #define PROP_MAX_QP_DEFAULT                   0
98 #define PROP_INTRA_REFRESH_TYPE_DEFAULT       MFX_REFRESH_NO
99 #define PROP_INTRA_REFRESH_CYCLE_SIZE_DEFAULT 0
100 #define PROP_INTRA_REFRESH_QP_DELTA_DEFAULT   0
101 #define PROP_INTRA_REFRESH_CYCLE_DIST_DEFAULT 0
102 #define PROP_DBLK_IDC_DEFAULT                 0
103
104 #define RAW_FORMATS "NV12, I420, YV12, YUY2, UYVY, BGRA, BGR10A2_LE, P010_10LE, VUYA"
105 #define PROFILES    "main, main-10, main-444, main-still-picture, main-10-still-picture"
106 #define COMMON_FORMAT "{ " RAW_FORMATS " }"
107 #define PRFOLIE_STR   "{ " PROFILES " }"
108
109
110 #if (MFX_VERSION >= 1027)
111 #undef  COMMON_FORMAT
112 #undef  PRFOLIE_STR
113 #define FORMATS_1027    RAW_FORMATS ", Y410, Y210"
114 #define PROFILES_1027   PROFILES ", main-444-10, main-422-10"
115 #define COMMON_FORMAT   "{ " FORMATS_1027 " }"
116 #define PRFOLIE_STR     "{ " PROFILES_1027 " }"
117 #endif
118
119 #if (MFX_VERSION >= 1031)
120 #undef  COMMON_FORMAT
121 #undef  PRFOLIE_STR
122 #define FORMATS_1031    FORMATS_1027 ", P012_LE"
123 #define PROFILES_1031   PROFILES_1027  ", main-12"
124 #define COMMON_FORMAT   "{ " FORMATS_1031 " }"
125 #define PRFOLIE_STR     "{ " PROFILES_1031 " }"
126 #endif
127
128 #if (MFX_VERSION >= 1032)
129 #undef  COMMON_FORMAT
130 #undef  PRFOLIE_STR
131 #define FORMATS_1032    FORMATS_1031
132 #define PROFILES_1032   PROFILES_1031  ", screen-extended-main, " \
133   "screen-extended-main-10, screen-extended-main-444, " \
134   "screen-extended-main-444-10"
135 #define COMMON_FORMAT   "{ " FORMATS_1032 " }"
136 #define PRFOLIE_STR     "{ " PROFILES_1032 " }"
137 #endif
138
139 #ifdef _WIN32
140 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
141     GST_PAD_SINK,
142     GST_PAD_ALWAYS,
143     GST_STATIC_CAPS (GST_MSDK_CAPS_STR (COMMON_FORMAT,
144             "{ NV12, P010_10LE }") "; "
145         GST_MSDK_CAPS_MAKE_WITH_D3D11_FEATURE ("{ NV12, P010_10LE }")));
146 #else
147 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
148     GST_PAD_SINK,
149     GST_PAD_ALWAYS,
150     GST_STATIC_CAPS (GST_MSDK_CAPS_STR (COMMON_FORMAT,
151             "{ NV12, P010_10LE }") "; "
152         GST_MSDK_CAPS_MAKE_WITH_VA_FEATURE ("NV12")));
153 #endif
154
155 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
156     GST_PAD_SRC,
157     GST_PAD_ALWAYS,
158     GST_STATIC_CAPS ("video/x-h265, "
159         "framerate = (fraction) [0/1, MAX], "
160         "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ], "
161         "stream-format = (string) byte-stream , alignment = (string) au , "
162         "profile = (string) " PRFOLIE_STR)
163     );
164
165 #define gst_msdkh265enc_parent_class parent_class
166 G_DEFINE_TYPE (GstMsdkH265Enc, gst_msdkh265enc, GST_TYPE_MSDKENC);
167
168 static void
169 gst_msdkh265enc_insert_sei (GstMsdkH265Enc * thiz, GstVideoCodecFrame * frame,
170     GstMemory * sei_mem)
171 {
172   GstBuffer *new_buffer;
173
174   if (!thiz->parser)
175     thiz->parser = gst_h265_parser_new ();
176
177   new_buffer = gst_h265_parser_insert_sei (thiz->parser,
178       frame->output_buffer, sei_mem);
179
180   if (!new_buffer) {
181     GST_WARNING_OBJECT (thiz, "Cannot insert SEI nal into AU buffer");
182     return;
183   }
184
185   gst_buffer_unref (frame->output_buffer);
186   frame->output_buffer = new_buffer;
187 }
188
189 static void
190 gst_msdkh265enc_add_cc (GstMsdkH265Enc * thiz, GstVideoCodecFrame * frame)
191 {
192   GstVideoCaptionMeta *cc_meta;
193   gpointer iter = NULL;
194   GstBuffer *in_buf = frame->input_buffer;
195   GstMemory *mem = NULL;
196
197   if (thiz->cc_sei_array)
198     g_array_set_size (thiz->cc_sei_array, 0);
199
200   while ((cc_meta =
201           (GstVideoCaptionMeta *) gst_buffer_iterate_meta_filtered (in_buf,
202               &iter, GST_VIDEO_CAPTION_META_API_TYPE))) {
203     GstH265SEIMessage sei;
204     GstH265RegisteredUserData *rud;
205     guint8 *data;
206
207     if (cc_meta->caption_type != GST_VIDEO_CAPTION_TYPE_CEA708_RAW)
208       continue;
209
210     memset (&sei, 0, sizeof (GstH265SEIMessage));
211     sei.payloadType = GST_H265_SEI_REGISTERED_USER_DATA;
212     rud = &sei.payload.registered_user_data;
213
214     rud->country_code = 181;
215     rud->size = cc_meta->size + 10;
216
217     data = g_malloc (rud->size);
218     memcpy (data + 9, cc_meta->data, cc_meta->size);
219
220     data[0] = 0;                /* 16-bits itu_t_t35_provider_code */
221     data[1] = 49;
222     data[2] = 'G';              /* 32-bits ATSC_user_identifier */
223     data[3] = 'A';
224     data[4] = '9';
225     data[5] = '4';
226     data[6] = 3;                /* 8-bits ATSC1_data_user_data_type_code */
227     /* 8-bits:
228      * 1 bit process_em_data_flag (0)
229      * 1 bit process_cc_data_flag (1)
230      * 1 bit additional_data_flag (0)
231      * 5-bits cc_count
232      */
233     data[7] = ((cc_meta->size / 3) & 0x1f) | 0x40;
234     data[8] = 255;              /* 8 bits em_data, unused */
235     data[cc_meta->size + 9] = 255;      /* 8 marker bits */
236
237     rud->data = data;
238
239     if (!thiz->cc_sei_array) {
240       thiz->cc_sei_array =
241           g_array_new (FALSE, FALSE, sizeof (GstH265SEIMessage));
242       g_array_set_clear_func (thiz->cc_sei_array,
243           (GDestroyNotify) gst_h265_sei_free);
244     }
245
246     g_array_append_val (thiz->cc_sei_array, sei);
247   }
248
249   if (!thiz->cc_sei_array || !thiz->cc_sei_array->len)
250     return;
251
252   /* layer_id and temporal_id will be updated by parser later */
253   mem = gst_h265_create_sei_memory (0, 1, 4, thiz->cc_sei_array);
254
255   if (!mem) {
256     GST_WARNING_OBJECT (thiz, "Cannot create SEI nal unit");
257     return;
258   }
259
260   GST_DEBUG_OBJECT (thiz,
261       "Inserting %d closed caption SEI message(s)", thiz->cc_sei_array->len);
262
263   gst_msdkh265enc_insert_sei (thiz, frame, mem);
264   gst_memory_unref (mem);
265 }
266
267 static void
268 gst_msdkh265enc_add_mdcv_sei (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
269 {
270   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (encoder);
271   GstVideoMasteringDisplayInfo *mastering_display_info
272       = encoder->input_state->mastering_display_info;
273   GstH265SEIMessage sei;
274   GstH265MasteringDisplayColourVolume *mdcv;
275   GstMemory *mem = NULL;
276   guint i = 0;
277
278   memset (&sei, 0, sizeof (GstH265SEIMessage));
279   sei.payloadType = GST_H265_SEI_MASTERING_DISPLAY_COLOUR_VOLUME;
280   mdcv = &sei.payload.mastering_display_colour_volume;
281
282   for (i = 0; i < 3; i++) {
283     mdcv->display_primaries_x[i] =
284         mastering_display_info->display_primaries[i].x;
285     mdcv->display_primaries_y[i] =
286         mastering_display_info->display_primaries[i].y;
287   }
288
289   mdcv->white_point_x = mastering_display_info->white_point.x;
290   mdcv->white_point_y = mastering_display_info->white_point.y;
291   mdcv->max_display_mastering_luminance =
292       mastering_display_info->max_display_mastering_luminance;
293   mdcv->min_display_mastering_luminance =
294       mastering_display_info->min_display_mastering_luminance;
295
296   if (!thiz->cc_sei_array)
297     thiz->cc_sei_array = g_array_new (FALSE, FALSE, sizeof (GstH265SEIMessage));
298   else
299     g_array_set_size (thiz->cc_sei_array, 0);
300
301   g_array_append_val (thiz->cc_sei_array, sei);
302
303   if (!thiz->cc_sei_array || !thiz->cc_sei_array->len)
304     return;
305
306   /* layer_id and temporal_id will be updated by parser later */
307   mem = gst_h265_create_sei_memory (0, 1, 4, thiz->cc_sei_array);
308
309   if (!mem) {
310     GST_WARNING_OBJECT (thiz, "Cannot create SEI nal unit");
311     return;
312   }
313
314   GST_DEBUG_OBJECT (thiz,
315       "Inserting %d mastering display colout volume SEI message(s)",
316       thiz->cc_sei_array->len);
317
318   gst_msdkh265enc_insert_sei (thiz, frame, mem);
319   gst_memory_unref (mem);
320 }
321
322 static void
323 gst_msdkh265enc_add_cll_sei (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
324 {
325   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (encoder);
326   GstVideoContentLightLevel *content_light_level
327       = encoder->input_state->content_light_level;
328   GstH265ContentLightLevel *cll;
329   GstH265SEIMessage sei;
330   GstMemory *mem = NULL;
331
332   memset (&sei, 0, sizeof (GstH265SEIMessage));
333   sei.payloadType = GST_H265_SEI_CONTENT_LIGHT_LEVEL;
334   cll = &sei.payload.content_light_level;
335
336   cll->max_content_light_level = content_light_level->max_content_light_level;
337   cll->max_pic_average_light_level =
338       content_light_level->max_frame_average_light_level;
339
340   if (!thiz->cc_sei_array)
341     thiz->cc_sei_array = g_array_new (FALSE, FALSE, sizeof (GstH265SEIMessage));
342   else
343     g_array_set_size (thiz->cc_sei_array, 0);
344
345   g_array_append_val (thiz->cc_sei_array, sei);
346
347   if (!thiz->cc_sei_array || !thiz->cc_sei_array->len)
348     return;
349
350   /* layer_id and temporal_id will be updated by parser later */
351   mem = gst_h265_create_sei_memory (0, 1, 4, thiz->cc_sei_array);
352
353   if (!mem) {
354     GST_WARNING_OBJECT (thiz, "Cannot create SEI nal unit");
355     return;
356   }
357
358   GST_DEBUG_OBJECT (thiz,
359       "Inserting %d content light level SEI message(s)",
360       thiz->cc_sei_array->len);
361
362   gst_msdkh265enc_insert_sei (thiz, frame, mem);
363   gst_memory_unref (mem);
364 }
365
366 static GstFlowReturn
367 gst_msdkh265enc_pre_push (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
368 {
369   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (encoder);
370   GstMsdkEnc *msdk_encoder = GST_MSDKENC (encoder);
371
372   gst_msdkh265enc_add_cc (thiz, frame);
373
374   if (msdk_encoder->input_state->mastering_display_info)
375     gst_msdkh265enc_add_mdcv_sei (msdk_encoder, frame);
376
377   if (msdk_encoder->input_state->content_light_level)
378     gst_msdkh265enc_add_cll_sei (msdk_encoder, frame);
379
380   return GST_FLOW_OK;
381 }
382
383 static gboolean
384 gst_msdkh265enc_set_format (GstMsdkEnc * encoder)
385 {
386   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (encoder);
387   GstCaps *template_caps, *allowed_caps;
388
389   g_free (thiz->profile_name);
390   thiz->profile_name = NULL;
391
392   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
393
394   if (!allowed_caps || gst_caps_is_empty (allowed_caps)) {
395     if (allowed_caps)
396       gst_caps_unref (allowed_caps);
397     return FALSE;
398   }
399
400   template_caps = gst_static_pad_template_get_caps (&src_factory);
401
402   if (gst_caps_is_equal (allowed_caps, template_caps)) {
403     GST_INFO_OBJECT (thiz,
404         "downstream have the same caps, profile set to auto");
405   } else {
406     GstStructure *s;
407     const gchar *profile;
408
409     allowed_caps = gst_caps_make_writable (allowed_caps);
410     allowed_caps = gst_caps_fixate (allowed_caps);
411     s = gst_caps_get_structure (allowed_caps, 0);
412     profile = gst_structure_get_string (s, "profile");
413
414     if (profile) {
415       thiz->profile_name = g_strdup (profile);
416     }
417   }
418
419   gst_caps_unref (allowed_caps);
420   gst_caps_unref (template_caps);
421
422   return TRUE;
423 }
424
425 static gboolean
426 gst_msdkh265enc_configure (GstMsdkEnc * encoder)
427 {
428   GstMsdkH265Enc *h265enc = GST_MSDKH265ENC (encoder);
429   mfxSession session;
430   const mfxPluginUID *uid;
431
432   session = gst_msdk_context_get_session (encoder->context);
433
434   if (encoder->hardware)
435     uid = &MFX_PLUGINID_HEVCE_HW;
436   else
437     uid = &MFX_PLUGINID_HEVCE_SW;
438
439   if (!gst_msdk_load_plugin (session, uid, 1, "msdkh265enc"))
440     return FALSE;
441
442   encoder->param.mfx.CodecId = MFX_CODEC_HEVC;
443
444   if (h265enc->profile_name) {
445     encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN;
446
447     if (!strcmp (h265enc->profile_name, "main-10"))
448       encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN10;
449     else if (!strcmp (h265enc->profile_name, "main-still-picture"))
450       encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAINSP;
451     else if (!strcmp (h265enc->profile_name, "main-10-still-picture")) {
452       encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN10;
453       h265enc->ext_param.Header.BufferId = MFX_EXTBUFF_HEVC_PARAM;
454       h265enc->ext_param.Header.BufferSz = sizeof (h265enc->ext_param);
455       h265enc->ext_param.GeneralConstraintFlags =
456           MFX_HEVC_CONSTR_REXT_ONE_PICTURE_ONLY;
457       gst_msdkenc_add_extra_param (encoder,
458           (mfxExtBuffer *) & h265enc->ext_param);
459     } else if (!strcmp (h265enc->profile_name, "main-444") ||
460         !strcmp (h265enc->profile_name, "main-422-10") ||
461         !strcmp (h265enc->profile_name, "main-444-10") ||
462         !strcmp (h265enc->profile_name, "main-12"))
463       encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_REXT;
464
465 #if (MFX_VERSION >= 1032)
466     else if (!strcmp (h265enc->profile_name, "screen-extended-main") ||
467         !strcmp (h265enc->profile_name, "screen-extended-main-10") ||
468         !strcmp (h265enc->profile_name, "screen-extended-main-444") ||
469         !strcmp (h265enc->profile_name, "screen-extended-main-444-10"))
470       encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_SCC;
471 #endif
472   } else {
473     switch (encoder->param.mfx.FrameInfo.FourCC) {
474       case MFX_FOURCC_P010:
475         encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN10;
476         break;
477       case MFX_FOURCC_AYUV:
478       case MFX_FOURCC_YUY2:
479       case MFX_FOURCC_A2RGB10:
480 #if (MFX_VERSION >= 1027)
481       case MFX_FOURCC_Y410:
482       case MFX_FOURCC_Y210:
483 #endif
484 #if (MFX_VERSION >= 1031)
485       case MFX_FOURCC_P016:
486 #endif
487         encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_REXT;
488         break;
489       default:
490         encoder->param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN;
491     }
492   }
493
494   /* IdrInterval field of MediaSDK HEVC encoder behaves differently
495    * than other encoders. IdrInteval == 1 indicate every
496    * I-frame should be an IDR, IdrInteval == 2 means every other
497    * I-frame is an IDR etc. So we generalize the behaviour of property
498    * "i-frames" by incrementing the value by one in each case*/
499   encoder->param.mfx.IdrInterval += 1;
500
501   /* Enable Extended coding options */
502   encoder->option2.MaxSliceSize = h265enc->max_slice_size;
503   encoder->option2.MinQPI = encoder->option2.MinQPP = encoder->option2.MinQPB =
504       h265enc->min_qp;
505   encoder->option2.MaxQPI = encoder->option2.MaxQPP = encoder->option2.MaxQPB =
506       h265enc->max_qp;
507   encoder->option2.DisableDeblockingIdc = h265enc->dblk_idc;
508
509   if (h265enc->tune_mode == 16 || h265enc->lowpower) {
510     encoder->option2.IntRefType = h265enc->intra_refresh_type;
511     encoder->option2.IntRefCycleSize = h265enc->intra_refresh_cycle_size;
512     encoder->option2.IntRefQPDelta = h265enc->intra_refresh_qp_delta;
513     encoder->option3.IntRefCycleDist = h265enc->intra_refresh_cycle_dist;
514     encoder->enable_extopt3 = TRUE;
515   } else if (h265enc->intra_refresh_type || h265enc->intra_refresh_cycle_size
516       || h265enc->intra_refresh_qp_delta || h265enc->intra_refresh_cycle_dist) {
517     GST_WARNING_OBJECT (h265enc,
518         "Intra refresh is only supported under lowpower mode, ingoring...");
519   }
520 #if (MFX_VERSION >= 1026)
521   if (h265enc->transform_skip != MFX_CODINGOPTION_UNKNOWN) {
522     encoder->option3.TransformSkip = h265enc->transform_skip;
523     encoder->enable_extopt3 = TRUE;
524   }
525 #endif
526
527   if (h265enc->b_pyramid) {
528     encoder->option2.BRefType = MFX_B_REF_PYRAMID;
529     /* Don't define Gop structure for B-pyramid, otherwise EncodeInit
530      * will throw Invalid param error */
531     encoder->param.mfx.GopRefDist = 0;
532   }
533
534   if (h265enc->p_pyramid) {
535     encoder->option3.PRefType = MFX_P_REF_PYRAMID;
536     /* MFX_P_REF_PYRAMID is available for GopRefDist = 1 */
537     encoder->param.mfx.GopRefDist = 1;
538     /* SDK decides the DPB size for P pyramid */
539     encoder->param.mfx.NumRefFrame = 0;
540     encoder->enable_extopt3 = TRUE;
541   }
542
543   if (encoder->option3.LowDelayBRC == MFX_CODINGOPTION_ON) {
544     h265enc->option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION;
545     h265enc->option.Header.BufferSz = sizeof (h265enc->option);
546     h265enc->option.NalHrdConformance = MFX_CODINGOPTION_OFF;
547     gst_msdkenc_add_extra_param (encoder, (mfxExtBuffer *) & h265enc->option);
548   }
549
550   gst_msdkenc_ensure_extended_coding_options (encoder);
551
552   if (h265enc->num_tile_rows > 1 || h265enc->num_tile_cols > 1) {
553     h265enc->ext_tiles.Header.BufferId = MFX_EXTBUFF_HEVC_TILES;
554     h265enc->ext_tiles.Header.BufferSz = sizeof (h265enc->ext_tiles);
555     h265enc->ext_tiles.NumTileRows = h265enc->num_tile_rows;
556     h265enc->ext_tiles.NumTileColumns = h265enc->num_tile_cols;
557
558     gst_msdkenc_add_extra_param (encoder,
559         (mfxExtBuffer *) & h265enc->ext_tiles);
560
561     /* Set a valid value to NumSlice */
562     if (encoder->param.mfx.NumSlice == 0)
563       encoder->param.mfx.NumSlice =
564           h265enc->num_tile_rows * h265enc->num_tile_cols;
565   }
566
567   encoder->param.mfx.LowPower = h265enc->tune_mode;
568
569   return TRUE;
570 }
571
572 static inline const gchar *
573 level_to_string (gint level)
574 {
575   switch (level) {
576     case MFX_LEVEL_HEVC_1:
577       return "1";
578     case MFX_LEVEL_HEVC_2:
579       return "2";
580     case MFX_LEVEL_HEVC_21:
581       return "2.1";
582     case MFX_LEVEL_HEVC_3:
583       return "3";
584     case MFX_LEVEL_HEVC_31:
585       return "3.1";
586     case MFX_LEVEL_HEVC_4:
587       return "4";
588     case MFX_LEVEL_HEVC_41:
589       return "4.1";
590     case MFX_LEVEL_HEVC_5:
591       return "5";
592     case MFX_LEVEL_HEVC_51:
593       return "5.1";
594     case MFX_LEVEL_HEVC_52:
595       return "5.2";
596     case MFX_LEVEL_HEVC_6:
597       return "6";
598     case MFX_LEVEL_HEVC_61:
599       return "6.1";
600     case MFX_LEVEL_HEVC_62:
601       return "6.2";
602     default:
603       break;
604   }
605
606   return NULL;
607 }
608
609 static GstCaps *
610 gst_msdkh265enc_set_src_caps (GstMsdkEnc * encoder)
611 {
612   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (encoder);
613   GstCaps *caps;
614   GstStructure *structure;
615   const gchar *level;
616
617   caps = gst_caps_new_empty_simple ("video/x-h265");
618   structure = gst_caps_get_structure (caps, 0);
619
620   gst_structure_set (structure, "stream-format", G_TYPE_STRING, "byte-stream",
621       NULL);
622
623   gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
624
625   if (thiz->profile_name)
626     gst_structure_set (structure, "profile", G_TYPE_STRING, thiz->profile_name,
627         NULL);
628   else {
629     switch (encoder->param.mfx.FrameInfo.FourCC) {
630       case MFX_FOURCC_P010:
631         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-10",
632             NULL);
633         break;
634       case MFX_FOURCC_AYUV:
635         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-444",
636             NULL);
637         break;
638       case MFX_FOURCC_YUY2:
639         /* The profile is main-422-10 for 8-bit 422 */
640         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-422-10",
641             NULL);
642         break;
643       case MFX_FOURCC_A2RGB10:
644         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-444-10",
645             NULL);
646         break;
647 #if (MFX_VERSION >= 1027)
648       case MFX_FOURCC_Y410:
649         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-444-10",
650             NULL);
651         break;
652       case MFX_FOURCC_Y210:
653         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-422-10",
654             NULL);
655         break;
656 #endif
657 #if (MFX_VERSION >= 1031)
658       case MFX_FOURCC_P016:
659         gst_structure_set (structure, "profile", G_TYPE_STRING, "main-12",
660             NULL);
661         break;
662 #endif
663       default:
664         gst_structure_set (structure, "profile", G_TYPE_STRING, "main", NULL);
665         break;
666     }
667   }
668
669   level = level_to_string (encoder->param.mfx.CodecLevel);
670   if (level)
671     gst_structure_set (structure, "level", G_TYPE_STRING, level, NULL);
672
673   return caps;
674 }
675
676 static void
677 gst_msdkh265enc_finalize (GObject * object)
678 {
679   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (object);
680
681   if (thiz->parser)
682     gst_h265_parser_free (thiz->parser);
683   if (thiz->cc_sei_array)
684     g_array_unref (thiz->cc_sei_array);
685
686   g_free (thiz->profile_name);
687
688   G_OBJECT_CLASS (parent_class)->finalize (object);
689 }
690
691 static void
692 gst_msdkh265enc_set_property (GObject * object, guint prop_id,
693     const GValue * value, GParamSpec * pspec)
694 {
695   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (object);
696
697   if (gst_msdkenc_set_common_property (object, prop_id, value, pspec))
698     return;
699
700   GST_OBJECT_LOCK (thiz);
701
702   switch (prop_id) {
703 #ifndef GST_REMOVE_DEPRECATED
704     case PROP_LOW_POWER:
705       thiz->lowpower = g_value_get_boolean (value);
706       thiz->prop_flag |= GST_MSDK_FLAG_LOW_POWER;
707
708       /* Ignore it if user set tune mode explicitly */
709       if (!(thiz->prop_flag & GST_MSDK_FLAG_TUNE_MODE))
710         thiz->tune_mode =
711             thiz->lowpower ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
712
713       break;
714 #endif
715
716     case PROP_TILE_ROW:
717       thiz->num_tile_rows = g_value_get_uint (value);
718       break;
719
720     case PROP_TILE_COL:
721       thiz->num_tile_cols = g_value_get_uint (value);
722       break;
723
724     case PROP_MAX_SLICE_SIZE:
725       thiz->max_slice_size = g_value_get_uint (value);
726       break;
727
728     case PROP_TUNE_MODE:
729       thiz->tune_mode = g_value_get_enum (value);
730       thiz->prop_flag |= GST_MSDK_FLAG_TUNE_MODE;
731       break;
732
733     case PROP_TRANSFORM_SKIP:
734       thiz->transform_skip = g_value_get_enum (value);
735       break;
736
737     case PROP_B_PYRAMID:
738       thiz->b_pyramid = g_value_get_boolean (value);
739       break;
740
741     case PROP_P_PYRAMID:
742       thiz->p_pyramid = g_value_get_boolean (value);
743       break;
744
745     case PROP_MIN_QP:
746       thiz->min_qp = g_value_get_uint (value);
747       break;
748
749     case PROP_MAX_QP:
750       thiz->max_qp = g_value_get_uint (value);
751       break;
752
753     case PROP_INTRA_REFRESH_TYPE:
754       thiz->intra_refresh_type = g_value_get_enum (value);
755       break;
756
757     case PROP_INTRA_REFRESH_CYCLE_SIZE:
758       thiz->intra_refresh_cycle_size = g_value_get_uint (value);
759       break;
760
761     case PROP_INTRA_REFRESH_QP_DELTA:
762       thiz->intra_refresh_qp_delta = g_value_get_int (value);
763       break;
764
765     case PROP_INTRA_REFRESH_CYCLE_DIST:
766       thiz->intra_refresh_cycle_dist = g_value_get_uint (value);
767       break;
768
769     case PROP_DBLK_IDC:
770       thiz->dblk_idc = g_value_get_uint (value);
771       break;
772
773     default:
774       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
775       break;
776   }
777   GST_OBJECT_UNLOCK (thiz);
778 }
779
780 static void
781 gst_msdkh265enc_get_property (GObject * object, guint prop_id, GValue * value,
782     GParamSpec * pspec)
783 {
784   GstMsdkH265Enc *thiz = GST_MSDKH265ENC (object);
785
786   if (gst_msdkenc_get_common_property (object, prop_id, value, pspec))
787     return;
788
789   GST_OBJECT_LOCK (thiz);
790   switch (prop_id) {
791 #ifndef GST_REMOVE_DEPRECATED
792     case PROP_LOW_POWER:
793       g_value_set_boolean (value, thiz->lowpower);
794       break;
795 #endif
796
797     case PROP_TILE_ROW:
798       g_value_set_uint (value, thiz->num_tile_rows);
799       break;
800
801     case PROP_TILE_COL:
802       g_value_set_uint (value, thiz->num_tile_cols);
803       break;
804
805     case PROP_MAX_SLICE_SIZE:
806       g_value_set_uint (value, thiz->max_slice_size);
807       break;
808
809     case PROP_TUNE_MODE:
810       g_value_set_enum (value, thiz->tune_mode);
811       break;
812
813     case PROP_TRANSFORM_SKIP:
814       g_value_set_enum (value, thiz->transform_skip);
815       break;
816
817     case PROP_B_PYRAMID:
818       g_value_set_boolean (value, thiz->b_pyramid);
819       break;
820
821     case PROP_P_PYRAMID:
822       g_value_set_boolean (value, thiz->p_pyramid);
823       break;
824
825     case PROP_MIN_QP:
826       g_value_set_uint (value, thiz->min_qp);
827       break;
828
829     case PROP_MAX_QP:
830       g_value_set_uint (value, thiz->max_qp);
831       break;
832
833     case PROP_INTRA_REFRESH_TYPE:
834       g_value_set_enum (value, thiz->intra_refresh_type);
835       break;
836
837     case PROP_INTRA_REFRESH_CYCLE_SIZE:
838       g_value_set_uint (value, thiz->intra_refresh_cycle_size);
839       break;
840
841     case PROP_INTRA_REFRESH_QP_DELTA:
842       g_value_set_int (value, thiz->intra_refresh_qp_delta);
843       break;
844
845     case PROP_INTRA_REFRESH_CYCLE_DIST:
846       g_value_set_uint (value, thiz->intra_refresh_cycle_dist);
847       break;
848
849     case PROP_DBLK_IDC:
850       g_value_set_uint (value, thiz->dblk_idc);
851       break;
852
853     default:
854       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
855       break;
856   }
857   GST_OBJECT_UNLOCK (thiz);
858 }
859
860 static gboolean
861 gst_msdkh265enc_need_reconfig (GstMsdkEnc * encoder, GstVideoCodecFrame * frame)
862 {
863   GstMsdkH265Enc *h265enc = GST_MSDKH265ENC (encoder);
864
865   return gst_msdkenc_get_roi_params (encoder, frame, h265enc->roi);
866 }
867
868 static void
869 gst_msdkh265enc_set_extra_params (GstMsdkEnc * encoder,
870     GstVideoCodecFrame * frame)
871 {
872   GstMsdkH265Enc *h265enc = GST_MSDKH265ENC (encoder);
873
874   if (h265enc->roi[0].NumROI)
875     gst_msdkenc_add_extra_param (encoder, (mfxExtBuffer *) & h265enc->roi[0]);
876 }
877
878 static gboolean
879 gst_msdkh265enc_need_conversion (GstMsdkEnc * encoder, GstVideoInfo * info,
880     GstVideoFormat * out_format)
881 {
882   GstMsdkH265Enc *h265enc = GST_MSDKH265ENC (encoder);
883
884   switch (GST_VIDEO_INFO_FORMAT (info)) {
885     case GST_VIDEO_FORMAT_NV12:
886     case GST_VIDEO_FORMAT_BGR10A2_LE:
887     case GST_VIDEO_FORMAT_P010_10LE:
888     case GST_VIDEO_FORMAT_VUYA:
889 #if (MFX_VERSION >= 1027)
890     case GST_VIDEO_FORMAT_Y410:
891     case GST_VIDEO_FORMAT_Y210:
892 #endif
893 #if (MFX_VERSION >= 1031)
894     case GST_VIDEO_FORMAT_P012_LE:
895 #endif
896       return FALSE;
897
898     case GST_VIDEO_FORMAT_YUY2:
899 #if (MFX_VERSION >= 1027)
900       if (encoder->codename >= MFX_PLATFORM_ICELAKE &&
901           h265enc->tune_mode == MFX_CODINGOPTION_OFF)
902         return FALSE;
903 #endif
904     default:
905       if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10)
906         *out_format = GST_VIDEO_FORMAT_P010_10LE;
907       else
908         *out_format = GST_VIDEO_FORMAT_NV12;
909       return TRUE;
910   }
911 }
912
913 static void
914 gst_msdkh265enc_class_init (GstMsdkH265EncClass * klass)
915 {
916   GObjectClass *gobject_class;
917   GstElementClass *element_class;
918   GstVideoEncoderClass *videoencoder_class;
919   GstMsdkEncClass *encoder_class;
920
921   gobject_class = G_OBJECT_CLASS (klass);
922   element_class = GST_ELEMENT_CLASS (klass);
923   videoencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
924   encoder_class = GST_MSDKENC_CLASS (klass);
925
926   gobject_class->finalize = gst_msdkh265enc_finalize;
927   gobject_class->set_property = gst_msdkh265enc_set_property;
928   gobject_class->get_property = gst_msdkh265enc_get_property;
929
930   videoencoder_class->pre_push = gst_msdkh265enc_pre_push;
931
932   encoder_class->set_format = gst_msdkh265enc_set_format;
933   encoder_class->configure = gst_msdkh265enc_configure;
934   encoder_class->set_src_caps = gst_msdkh265enc_set_src_caps;
935   encoder_class->need_reconfig = gst_msdkh265enc_need_reconfig;
936   encoder_class->set_extra_params = gst_msdkh265enc_set_extra_params;
937   encoder_class->need_conversion = gst_msdkh265enc_need_conversion;
938
939   gst_msdkenc_install_common_properties (encoder_class);
940
941 #ifndef GST_REMOVE_DEPRECATED
942   g_object_class_install_property (gobject_class, PROP_LOW_POWER,
943       g_param_spec_boolean ("low-power", "Low power",
944           "Enable low power mode (DEPRECATED, use tune instead)",
945           PROP_LOWPOWER_DEFAULT,
946           G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
947 #endif
948
949   g_object_class_install_property (gobject_class, PROP_TILE_ROW,
950       g_param_spec_uint ("num-tile-rows", "number of rows for tiled encoding",
951           "number of rows for tiled encoding",
952           1, 8192, PROP_TILE_ROW_DEFAULT,
953           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
954
955   g_object_class_install_property (gobject_class, PROP_TILE_COL,
956       g_param_spec_uint ("num-tile-cols",
957           "number of columns for tiled encoding",
958           "number of columns for tiled encoding", 1, 8192,
959           PROP_TILE_COL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
960
961   g_object_class_install_property (gobject_class, PROP_MAX_SLICE_SIZE,
962       g_param_spec_uint ("max-slice-size", "Max Slice Size",
963           "Maximum slice size in bytes (if enabled MSDK will ignore the control over num-slices)",
964           0, G_MAXUINT32, PROP_MAX_SLICE_SIZE_DEFAULT,
965           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
966
967   g_object_class_install_property (gobject_class, PROP_TUNE_MODE,
968       g_param_spec_enum ("tune", "Encoder tuning",
969           "Encoder tuning option",
970           gst_msdkenc_tune_mode_get_type (), PROP_TUNE_MODE_DEFAULT,
971           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
972
973   g_object_class_install_property (gobject_class, PROP_TRANSFORM_SKIP,
974       g_param_spec_enum ("transform-skip", "Transform Skip",
975           "Transform Skip option",
976           gst_msdkenc_transform_skip_get_type (), PROP_TRANSFORM_SKIP_DEFAULT,
977           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
978
979   g_object_class_install_property (gobject_class, PROP_B_PYRAMID,
980       g_param_spec_boolean ("b-pyramid", "B-pyramid",
981           "Enable B-Pyramid Reference structure", FALSE,
982           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
983
984   g_object_class_install_property (gobject_class, PROP_P_PYRAMID,
985       g_param_spec_boolean ("p-pyramid", "P-pyramid",
986           "Enable P-Pyramid Reference structure", FALSE,
987           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
988
989   g_object_class_install_property (gobject_class, PROP_MIN_QP,
990       g_param_spec_uint ("min-qp", "Min QP",
991           "Minimal quantizer for I/P/B frames",
992           0, 51, PROP_MIN_QP_DEFAULT,
993           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
994
995   g_object_class_install_property (gobject_class, PROP_MAX_QP,
996       g_param_spec_uint ("max-qp", "Max QP",
997           "Maximum quantizer for I/P/B frames",
998           0, 51, PROP_MAX_QP_DEFAULT,
999           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1000
1001   g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_TYPE,
1002       g_param_spec_enum ("intra-refresh-type", "Intra refresh type",
1003           "Set intra refresh type",
1004           gst_msdkenc_intra_refresh_type_get_type (),
1005           PROP_INTRA_REFRESH_TYPE_DEFAULT,
1006           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1007
1008   g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_CYCLE_SIZE,
1009       g_param_spec_uint ("intra-refresh-cycle-size", "Intra refresh cycle size",
1010           "Set intra refresh cycle size, valid value starts from 2, only available when tune=low-power",
1011           0, G_MAXUINT16, PROP_INTRA_REFRESH_CYCLE_SIZE_DEFAULT,
1012           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1013
1014   g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_QP_DELTA,
1015       g_param_spec_int ("intra-refresh-qp-delta", "Intra refresh qp delta",
1016           "Set intra refresh qp delta, only available when tune=low-power",
1017           -51, 51, PROP_INTRA_REFRESH_QP_DELTA_DEFAULT,
1018           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1019
1020   g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_CYCLE_DIST,
1021       g_param_spec_uint ("intra-refresh-cycle-dist", "Intra refresh cycle dist",
1022           "Set intra refresh cycle dist, only available when tune=low-power",
1023           0, G_MAXUINT16, PROP_INTRA_REFRESH_CYCLE_DIST_DEFAULT,
1024           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1025
1026   g_object_class_install_property (gobject_class, PROP_DBLK_IDC,
1027       g_param_spec_uint ("dblk-idc", "Disable Deblocking Idc",
1028           "Option of disable deblocking idc",
1029           0, 2, PROP_DBLK_IDC_DEFAULT,
1030           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1031
1032   gst_element_class_set_static_metadata (element_class,
1033       "Intel MSDK H265 encoder",
1034       "Codec/Encoder/Video/Hardware",
1035       "H265 video encoder based on " MFX_API_SDK,
1036       "Josep Torra <jtorra@oblong.com>");
1037
1038   gst_element_class_add_static_pad_template (element_class, &sink_factory);
1039   gst_element_class_add_static_pad_template (element_class, &src_factory);
1040 }
1041
1042 static void
1043 gst_msdkh265enc_init (GstMsdkH265Enc * thiz)
1044 {
1045   GstMsdkEnc *msdk_enc = (GstMsdkEnc *) thiz;
1046   thiz->lowpower = PROP_LOWPOWER_DEFAULT;
1047   thiz->num_tile_rows = PROP_TILE_ROW_DEFAULT;
1048   thiz->num_tile_cols = PROP_TILE_COL_DEFAULT;
1049   thiz->max_slice_size = PROP_MAX_SLICE_SIZE_DEFAULT;
1050   thiz->tune_mode = PROP_TUNE_MODE_DEFAULT;
1051   thiz->transform_skip = PROP_TRANSFORM_SKIP_DEFAULT;
1052   thiz->b_pyramid = PROP_B_PYRAMID_DEFAULT;
1053   thiz->p_pyramid = PROP_P_PYRAMID_DEFAULT;
1054   thiz->min_qp = PROP_MIN_QP_DEFAULT;
1055   thiz->max_qp = PROP_MAX_QP_DEFAULT;
1056   thiz->intra_refresh_type = PROP_INTRA_REFRESH_TYPE_DEFAULT;
1057   thiz->intra_refresh_cycle_size = PROP_INTRA_REFRESH_CYCLE_SIZE_DEFAULT;
1058   thiz->intra_refresh_qp_delta = PROP_INTRA_REFRESH_QP_DELTA_DEFAULT;
1059   thiz->intra_refresh_cycle_dist = PROP_INTRA_REFRESH_CYCLE_DIST_DEFAULT;
1060   thiz->dblk_idc = PROP_DBLK_IDC_DEFAULT;
1061   msdk_enc->num_extra_frames = 1;
1062 }