• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer H265 encoder plugin
2  * Copyright (C) 2019 Yeongjin Jeong <yeongjin.jeong@navercorp.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:element-svthevcenc
22  * @title: svthevcenc
23  *
24  * This element encodes raw video into H265 compressed data.
25  *
26  **/
27 
28 #ifdef HAVE_CONFIG_H
29 #  include "config.h"
30 #endif
31 
32 #include "gstsvthevcenc.h"
33 
34 #include <gst/pbutils/pbutils.h>
35 #include <gst/video/video.h>
36 #include <gst/video/gstvideometa.h>
37 #include <gst/video/gstvideopool.h>
38 #include <gst/base/gstbitreader.h>
39 #include <gst/codecparsers/gsth265parser.h>
40 
41 #include <string.h>
42 #include <stdlib.h>
43 
44 GST_DEBUG_CATEGORY_STATIC (svthevc_enc_debug);
45 #define GST_CAT_DEFAULT svthevc_enc_debug
46 
47 enum
48 {
49   PROP_0,
50   PROP_INSERT_VUI,
51   PROP_AUD,
52   PROP_HIERARCHICAL_LEVEL,
53   PROP_LOOKAHEAD_DISTANCE,
54   PROP_ENCODER_MODE,
55   PROP_RC_MODE,
56   PROP_QP_I,
57   PROP_QP_MAX,
58   PROP_QP_MIN,
59   PROP_SCENE_CHANGE_DETECTION,
60   PROP_TUNE,
61   PROP_BASE_LAYER_SWITCH_MODE,
62   PROP_BITRATE,
63   PROP_KEY_INT_MAX,
64   PROP_ENABLE_OPEN_GOP,
65   PROP_CONFIG_INTERVAL,
66   PROP_CORES,
67   PROP_SOCKET,
68   PROP_TILE_ROW,
69   PROP_TILE_COL,
70   PROP_PRED_STRUCTURE,
71   PROP_VBV_MAX_RATE,
72   PROP_VBV_BUFFER_SIZE,
73 };
74 
75 #define PROP_INSERT_VUI_DEFAULT             FALSE
76 #define PROP_AUD_DEFAULT                    FALSE
77 #define PROP_HIERARCHICAL_LEVEL_DEFAULT     GST_SVTHEVC_ENC_B_PYRAMID_4LEVEL_HIERARCHY
78 #define PROP_LOOKAHEAD_DISTANCE_DEFAULT     40
79 #define PROP_ENCODER_MODE_DEFAULT           7
80 #define PROP_RC_MODE_DEFAULT                GST_SVTHEVC_ENC_RC_CQP
81 #define PROP_QP_I_DEFAULT                   25
82 #define PROP_QP_MAX_DEFAULT                 48
83 #define PROP_QP_MIN_DEFAULT                 10
84 #define PROP_SCENE_CHANGE_DETECTION_DEFAULT TRUE
85 #define PROP_TUNE_DEFAULT                   GST_SVTHEVC_ENC_TUNE_OQ
86 #define PROP_BASE_LAYER_SWITCH_MODE_DEFAULT GST_SVTHEVC_ENC_BASE_LAYER_MODE_BFRAME
87 #define PROP_BITRATE_DEFAULT                (7 * 1000)
88 #define PROP_KEY_INT_MAX_DEFAULT            -2
89 #define PROP_ENABLE_OPEN_GOP_DEFAULT        TRUE
90 #define PROP_CONFIG_INTERVAL_DEFAULT        0
91 #define PROP_CORES_DEFAULT                  0
92 #define PROP_SOCKET_DEFAULT                 -1
93 #define PROP_TILE_ROW_DEFAULT               1
94 #define PROP_TILE_COL_DEFAULT               1
95 #define PROP_PRED_STRUCTURE_DEFAULT         GST_SVTHEVC_ENC_PRED_STRUCT_RANDOM_ACCESS
96 #define PROP_VBV_MAX_RATE_DEFAULT           0
97 #define PROP_VBV_BUFFER_SIZE_DEFAULT        0
98 
99 #define PROFILE_DEFAULT                     2
100 #define LEVEL_DEFAULT                       0
101 #define TIER_DEFAULT                        0
102 
103 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
104 #define FORMATS "I420, Y42B, Y444, I420_10LE, I422_10LE, Y444_10LE"
105 #else
106 #define FORMATS "I420, Y42B, Y444, I420_10BE, I422_10BE, Y444_10BE"
107 #endif
108 
109 #define GST_SVTHEVC_ENC_B_PYRAMID_TYPE (gst_svthevc_enc_b_pyramid_get_type())
110 static GType
gst_svthevc_enc_b_pyramid_get_type(void)111 gst_svthevc_enc_b_pyramid_get_type (void)
112 {
113   static GType b_pyramid_type = 0;
114 
115   static const GEnumValue b_pyramid_types[] = {
116     {GST_SVTHEVC_ENC_B_PYRAMID_FLAT, "Flat", "flat"},
117     {GST_SVTHEVC_ENC_B_PYRAMID_2LEVEL_HIERARCHY, "2-Level Hierarchy",
118         "2-level-hierarchy"},
119     {GST_SVTHEVC_ENC_B_PYRAMID_3LEVEL_HIERARCHY, "3-Level Hierarchy",
120         "3-level-hierarchy"},
121     {GST_SVTHEVC_ENC_B_PYRAMID_4LEVEL_HIERARCHY, "4-Level Hierarchy",
122         "4-level-hierarchy"},
123     {0, NULL, NULL}
124   };
125 
126   if (!b_pyramid_type) {
127     b_pyramid_type =
128         g_enum_register_static ("GstSvtHevcEncBPyramid", b_pyramid_types);
129   }
130   return b_pyramid_type;
131 }
132 
133 #define GST_SVTHEVC_ENC_BASE_LAYER_MODE_TYPE (gst_svthevc_enc_base_layer_mode_get_type())
134 static GType
gst_svthevc_enc_base_layer_mode_get_type(void)135 gst_svthevc_enc_base_layer_mode_get_type (void)
136 {
137   static GType base_layer_mode_type = 0;
138 
139   static const GEnumValue base_layer_mode_types[] = {
140     {GST_SVTHEVC_ENC_BASE_LAYER_MODE_BFRAME,
141           "Use B-frames in the base layer pointing to the same past picture",
142         "B-frame"},
143     {GST_SVTHEVC_ENC_BASE_LAYER_MODE_PFRAME, "Use P-frames in the base layer",
144         "P-frame"},
145     {0, NULL, NULL}
146   };
147 
148   if (!base_layer_mode_type) {
149     base_layer_mode_type =
150         g_enum_register_static ("GstSvtHevcEncBaseLayerMode",
151         base_layer_mode_types);
152   }
153   return base_layer_mode_type;
154 }
155 
156 #define GST_SVTHEVC_ENC_RC_TYPE (gst_svthevc_enc_rc_get_type())
157 static GType
gst_svthevc_enc_rc_get_type(void)158 gst_svthevc_enc_rc_get_type (void)
159 {
160   static GType rc_type = 0;
161 
162   static const GEnumValue rc_types[] = {
163     {GST_SVTHEVC_ENC_RC_CQP, "Constant QP Control", "cqp"},
164     {GST_SVTHEVC_ENC_RC_VBR, "Variable Bitrate Contorol", "vbr"},
165     {0, NULL, NULL}
166   };
167 
168   if (!rc_type) {
169     rc_type = g_enum_register_static ("GstSvtHevcEncRC", rc_types);
170   }
171   return rc_type;
172 }
173 
174 #define GST_SVTHEVC_ENC_TUNE_TYPE (gst_svthevc_enc_tune_get_type())
175 static GType
gst_svthevc_enc_tune_get_type(void)176 gst_svthevc_enc_tune_get_type (void)
177 {
178   static GType tune_type = 0;
179 
180   static const GEnumValue tune_types[] = {
181     {GST_SVTHEVC_ENC_TUNE_SQ, "Visually Optimized Mode", "sq"},
182     {GST_SVTHEVC_ENC_TUNE_OQ, "PSNR/SSIM Optimized Mode", "oq"},
183     {GST_SVTHEVC_ENC_TUNE_VMAF, "VMAF Optimized Mode", "vmaf"},
184     {0, NULL, NULL}
185   };
186 
187   if (!tune_type) {
188     tune_type = g_enum_register_static ("GstSvtHevcEncTune", tune_types);
189   }
190   return tune_type;
191 }
192 
193 #define GST_SVTHEVC_ENC_PRED_STRUCT_TYPE (gst_svthevc_enc_pred_struct_get_type())
194 static GType
gst_svthevc_enc_pred_struct_get_type(void)195 gst_svthevc_enc_pred_struct_get_type (void)
196 {
197   static GType pred_struct_type = 0;
198 
199   static const GEnumValue pred_struct_types[] = {
200     {GST_SVTHEVC_ENC_PRED_STRUCT_LOW_DELAY_P,
201         "Low Delay Prediction Structure with P/p pictures", "low-delay-P"},
202     {GST_SVTHEVC_ENC_PRED_STRUCT_LOW_DELAY_B,
203         "Low Delay Prediction Structure with B/b pictures", "low-delay-B"},
204     {GST_SVTHEVC_ENC_PRED_STRUCT_RANDOM_ACCESS,
205         "Random Access Prediction Structure", "random-access"},
206     {0, NULL, NULL}
207   };
208 
209   if (!pred_struct_type) {
210     pred_struct_type =
211         g_enum_register_static ("GstSvtHevcEncPredStruct", pred_struct_types);
212   }
213   return pred_struct_type;
214 }
215 
216 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
217     GST_PAD_SINK,
218     GST_PAD_ALWAYS,
219     GST_STATIC_CAPS ("video/x-raw, "
220         "format = (string) { " FORMATS " }, "
221         "framerate = (fraction) [0, MAX], "
222         "width = (int) [ 64, 8192 ], " "height = (int) [ 64, 4320 ]")
223     );
224 
225 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
226     GST_PAD_SRC,
227     GST_PAD_ALWAYS,
228     GST_STATIC_CAPS ("video/x-h265, "
229         "framerate = (fraction) [0/1, MAX], "
230         "width = (int) [ 64, 8192 ], " "height = (int) [ 64, 4320 ], "
231         "stream-format = (string) byte-stream, "
232         "alignment = (string) au, "
233         "profile = (string) { main, main-10, main-422-10, main-444, main-444-10 }")
234     );
235 
236 static void gst_svthevc_enc_finalize (GObject * object);
237 static gboolean gst_svthevc_enc_start (GstVideoEncoder * encoder);
238 static gboolean gst_svthevc_enc_stop (GstVideoEncoder * encoder);
239 static gboolean gst_svthevc_enc_flush (GstVideoEncoder * encoder);
240 
241 static gboolean gst_svthevc_enc_init_encoder (GstSvtHevcEnc * encoder);
242 static void gst_svthevc_enc_close_encoder (GstSvtHevcEnc * encoder);
243 
244 static GstFlowReturn gst_svthevc_enc_finish (GstVideoEncoder * encoder);
245 static GstFlowReturn gst_svthevc_enc_handle_frame (GstVideoEncoder * encoder,
246     GstVideoCodecFrame * frame);
247 static GstFlowReturn gst_svthevc_enc_drain_encoder (GstSvtHevcEnc * encoder,
248     gboolean send);
249 static GstFlowReturn gst_svthevc_enc_send_frame (GstSvtHevcEnc * encoder,
250     GstVideoCodecFrame * frame);
251 static GstFlowReturn gst_svthevc_enc_receive_frame (GstSvtHevcEnc * encoder,
252     gboolean * got_packet, gboolean send);
253 static gboolean gst_svthevc_enc_set_format (GstVideoEncoder * video_enc,
254     GstVideoCodecState * state);
255 static gboolean gst_svthevc_enc_propose_allocation (GstVideoEncoder * encoder,
256     GstQuery * query);
257 
258 static void gst_svthevc_enc_set_property (GObject * object, guint prop_id,
259     const GValue * value, GParamSpec * pspec);
260 static void gst_svthevc_enc_get_property (GObject * object, guint prop_id,
261     GValue * value, GParamSpec * pspec);
262 
263 #define gst_svthevc_enc_parent_class parent_class
264 G_DEFINE_TYPE_WITH_CODE (GstSvtHevcEnc, gst_svthevc_enc, GST_TYPE_VIDEO_ENCODER,
265     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
266 
267 #define MAX_FORMAT_COUNT 6
268 typedef struct
269 {
270   const GstH265Profile gst_profile;
271   const guint svt_profile;
272   const GstVideoFormat formats[MAX_FORMAT_COUNT];
273 } GstSvtHevcEncProfileTable;
274 
275 static const GstSvtHevcEncProfileTable profile_table[] = {
276   {GST_H265_PROFILE_MAIN, 1, {GST_VIDEO_FORMAT_I420,}},
277   {GST_H265_PROFILE_MAIN_444, 4, {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B,
278           GST_VIDEO_FORMAT_Y444,}},
279 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
280   {GST_H265_PROFILE_MAIN_10, 2, {GST_VIDEO_FORMAT_I420,
281           GST_VIDEO_FORMAT_I420_10LE,}},
282   {GST_H265_PROFILE_MAIN_422_10, 4, {GST_VIDEO_FORMAT_I420,
283               GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420_10LE,
284           GST_VIDEO_FORMAT_I422_10LE,}},
285   {GST_H265_PROFILE_MAIN_444_10, 4, {GST_VIDEO_FORMAT_I420,
286               GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444,
287               GST_VIDEO_FORMAT_I420_10LE, GST_VIDEO_FORMAT_I422_10LE,
288           GST_VIDEO_FORMAT_Y444_10LE}}
289 #else
290   {GST_H265_PROFILE_MAIN_10, 2, {GST_VIDEO_FORMAT_I420,
291           GST_VIDEO_FORMAT_I420_10BE,}},
292   {GST_H265_PROFILE_MAIN_422_10, 4, {GST_VIDEO_FORMAT_I420,
293               GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420_10BE,
294           GST_VIDEO_FORMAT_I422_10BE,}},
295   {GST_H265_PROFILE_MAIN_444_10, 4, {GST_VIDEO_FORMAT_I420,
296               GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444,
297               GST_VIDEO_FORMAT_I420_10BE, GST_VIDEO_FORMAT_I422_10BE,
298           GST_VIDEO_FORMAT_Y444_10BE}}
299 #endif
300 };
301 
302 static void
set_array_val(GArray * arr,guint index,guint val)303 set_array_val (GArray * arr, guint index, guint val)
304 {
305   if (!arr)
306     return;
307 
308   if (index >= arr->len)
309     g_array_set_size (arr, index + 1);
310   arr->data[index] = val;
311 }
312 
313 static void
get_support_format_from_profile(GArray * formats,const gchar * profile_str)314 get_support_format_from_profile (GArray * formats, const gchar * profile_str)
315 {
316   GstH265Profile profile = gst_h265_profile_from_string (profile_str);
317   guint i, j;
318 
319   if (!formats)
320     return;
321 
322   for (i = 0; i < G_N_ELEMENTS (profile_table); i++) {
323     if (profile_table[i].gst_profile == profile) {
324       for (j = 0; j < MAX_FORMAT_COUNT; j++) {
325         if (profile_table[i].formats[j] > GST_VIDEO_FORMAT_UNKNOWN)
326           set_array_val (formats, profile_table[i].formats[j], 1);
327       }
328       break;
329     }
330   }
331 }
332 
333 static void
get_compatible_profile_from_format(GArray * profiles,const GstVideoFormat format)334 get_compatible_profile_from_format (GArray * profiles,
335     const GstVideoFormat format)
336 {
337   guint i, j;
338 
339   if (!profiles)
340     return;
341 
342   for (i = 0; i < G_N_ELEMENTS (profile_table); i++) {
343     for (j = 0; j < MAX_FORMAT_COUNT; j++) {
344       if (profile_table[i].formats[j] == format) {
345         set_array_val (profiles, profile_table[i].gst_profile, 1);
346       }
347     }
348   }
349 }
350 
351 static GstCaps *
gst_svthevc_enc_sink_getcaps(GstVideoEncoder * enc,GstCaps * filter)352 gst_svthevc_enc_sink_getcaps (GstVideoEncoder * enc, GstCaps * filter)
353 {
354   GstCaps *supported_incaps;
355   GstCaps *allowed_caps;
356   GstCaps *filter_caps, *fcaps;
357   gint i, j, k;
358 
359   supported_incaps = gst_static_pad_template_get_caps (&sink_factory);
360 
361   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (enc));
362 
363   if (!allowed_caps || gst_caps_is_empty (allowed_caps)
364       || gst_caps_is_any (allowed_caps)) {
365     fcaps = supported_incaps;
366     goto done;
367   }
368 
369   GST_LOG_OBJECT (enc, "template caps %" GST_PTR_FORMAT, supported_incaps);
370   GST_LOG_OBJECT (enc, "allowed caps %" GST_PTR_FORMAT, allowed_caps);
371 
372   filter_caps = gst_caps_new_empty ();
373 
374   for (i = 0; i < gst_caps_get_size (supported_incaps); i++) {
375     GQuark q_name =
376         gst_structure_get_name_id (gst_caps_get_structure (supported_incaps,
377             i));
378 
379     for (j = 0; j < gst_caps_get_size (allowed_caps); j++) {
380       const GstStructure *allowed_s = gst_caps_get_structure (allowed_caps, j);
381       const GValue *val;
382       GstStructure *s;
383 
384       s = gst_structure_new_id_empty (q_name);
385       if ((val = gst_structure_get_value (allowed_s, "width")))
386         gst_structure_set_value (s, "width", val);
387       if ((val = gst_structure_get_value (allowed_s, "height")))
388         gst_structure_set_value (s, "height", val);
389 
390       if ((val = gst_structure_get_value (allowed_s, "profile"))) {
391         GArray *formats = g_array_new (FALSE, TRUE, sizeof (guint));
392         GValue fmts = G_VALUE_INIT;
393         GValue fmt = G_VALUE_INIT;
394         guint i;
395 
396         g_value_init (&fmts, GST_TYPE_LIST);
397         g_value_init (&fmt, G_TYPE_STRING);
398 
399         if (G_VALUE_HOLDS_STRING (val)) {
400           get_support_format_from_profile (formats, g_value_get_string (val));
401         } else if (GST_VALUE_HOLDS_LIST (val)) {
402           for (k = 0; k < gst_value_list_get_size (val); k++) {
403             const GValue *vlist = gst_value_list_get_value (val, k);
404 
405             if (G_VALUE_HOLDS_STRING (vlist))
406               get_support_format_from_profile (formats,
407                   g_value_get_string (vlist));
408           }
409         }
410 
411         for (i = 0; i < formats->len; i++) {
412           if (formats->data[i]) {
413             g_value_set_string (&fmt,
414                 gst_video_format_to_string ((GstVideoFormat) i));
415             gst_value_list_append_value (&fmts, &fmt);
416           }
417         }
418 
419         g_array_free (formats, TRUE);
420 
421         if (gst_value_list_get_size (&fmts) != 0)
422           gst_structure_take_value (s, "format", &fmts);
423         else
424           g_value_unset (&fmts);
425 
426         g_value_unset (&fmt);
427       }
428 
429       filter_caps = gst_caps_merge_structure (filter_caps, s);
430     }
431   }
432 
433   fcaps = gst_caps_intersect (filter_caps, supported_incaps);
434   gst_caps_unref (filter_caps);
435   gst_caps_unref (supported_incaps);
436 
437   if (filter) {
438     GST_LOG_OBJECT (enc, "intersecting with %" GST_PTR_FORMAT, filter);
439     filter_caps = gst_caps_intersect (fcaps, filter);
440     gst_caps_unref (fcaps);
441     fcaps = filter_caps;
442   }
443 
444 done:
445   if (allowed_caps)
446     gst_caps_unref (allowed_caps);
447 
448   GST_LOG_OBJECT (enc, "proxy caps %" GST_PTR_FORMAT, fcaps);
449 
450   return fcaps;
451 }
452 
453 static void
gst_svthevc_enc_class_init(GstSvtHevcEncClass * klass)454 gst_svthevc_enc_class_init (GstSvtHevcEncClass * klass)
455 {
456   GObjectClass *gobject_class;
457   GstElementClass *element_class;
458   GstVideoEncoderClass *gstencoder_class;
459 
460   gobject_class = G_OBJECT_CLASS (klass);
461   element_class = GST_ELEMENT_CLASS (klass);
462   gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
463 
464   gobject_class->set_property = gst_svthevc_enc_set_property;
465   gobject_class->get_property = gst_svthevc_enc_get_property;
466   gobject_class->finalize = gst_svthevc_enc_finalize;
467 
468   gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_svthevc_enc_set_format);
469   gstencoder_class->handle_frame =
470       GST_DEBUG_FUNCPTR (gst_svthevc_enc_handle_frame);
471   gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_svthevc_enc_start);
472   gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_svthevc_enc_stop);
473   gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_svthevc_enc_flush);
474   gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_svthevc_enc_finish);
475   gstencoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_svthevc_enc_sink_getcaps);
476   gstencoder_class->propose_allocation =
477       GST_DEBUG_FUNCPTR (gst_svthevc_enc_propose_allocation);
478 
479   g_object_class_install_property (gobject_class, PROP_INSERT_VUI,
480       g_param_spec_boolean ("insert-vui", "Insert VUI",
481           "Insert VUI NAL in stream",
482           PROP_INSERT_VUI_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
483 
484   g_object_class_install_property (gobject_class, PROP_AUD,
485       g_param_spec_boolean ("aud", "AUD",
486           "Use AU (Access Unit) delimiter", PROP_AUD_DEFAULT,
487           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
488 
489   g_object_class_install_property (gobject_class, PROP_HIERARCHICAL_LEVEL,
490       g_param_spec_enum ("b-pyramid", "B Pyramid (Hierarchical Levels)",
491           "Number of hierarchical layers used to construct GOP",
492           GST_SVTHEVC_ENC_B_PYRAMID_TYPE, PROP_HIERARCHICAL_LEVEL_DEFAULT,
493           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
494 
495   g_object_class_install_property (gobject_class, PROP_LOOKAHEAD_DISTANCE,
496       g_param_spec_uint ("lookahead", "Lookahead Depth",
497           "Look ahead distance",
498           0, 250, PROP_LOOKAHEAD_DISTANCE_DEFAULT,
499           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
500 
501   g_object_class_install_property (gobject_class, PROP_ENCODER_MODE,
502       g_param_spec_uint ("speed", "speed (Encoder Mode)",
503           "Encoding preset [0, 11] (e.g. 0 is the highest quality mode, 11 is the highest), [0, 11] (for >= 4k resolution), [0, 10] (for >= 1080p resolution), [0, 9] (for all resolution)",
504           0, 11, PROP_ENCODER_MODE_DEFAULT,
505           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
506 
507   g_object_class_install_property (gobject_class, PROP_RC_MODE,
508       g_param_spec_enum ("rc", "Ratecontrol Mode",
509           "Bitrate control mode",
510           GST_SVTHEVC_ENC_RC_TYPE, PROP_RC_MODE_DEFAULT,
511           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
512 
513   g_object_class_install_property (gobject_class, PROP_QP_I,
514       g_param_spec_uint ("qp-i", "QP I",
515           "QP value for intra frames in CQP mode",
516           0, 51, PROP_QP_I_DEFAULT,
517           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
518 
519   g_object_class_install_property (gobject_class, PROP_QP_MAX,
520       g_param_spec_uint ("qp-max", "QP Max",
521           "Maximum QP value allowed for rate control use",
522           0, 51, PROP_QP_MAX_DEFAULT,
523           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
524 
525   g_object_class_install_property (gobject_class, PROP_QP_MIN,
526       g_param_spec_uint ("qp-min", "QP Min",
527           "Minimum QP value allowed for rate control use",
528           0, 50, PROP_QP_MIN_DEFAULT,
529           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
530 
531   g_object_class_install_property (gobject_class, PROP_SCENE_CHANGE_DETECTION,
532       g_param_spec_boolean ("enable-scd", "Scene Change Detection",
533           "Use the scene change detection algorithm",
534           PROP_SCENE_CHANGE_DETECTION_DEFAULT,
535           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
536 
537   g_object_class_install_property (gobject_class, PROP_TUNE,
538       g_param_spec_enum ("tune", "Tune",
539           "Quality tuning mode",
540           GST_SVTHEVC_ENC_TUNE_TYPE, PROP_TUNE_DEFAULT,
541           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
542 
543   g_object_class_install_property (gobject_class, PROP_BASE_LAYER_SWITCH_MODE,
544       g_param_spec_enum ("baselayer-mode", "Base Layer Switch Mode",
545           "Random Access Prediction Structure type setting",
546           GST_SVTHEVC_ENC_BASE_LAYER_MODE_TYPE,
547           PROP_BASE_LAYER_SWITCH_MODE_DEFAULT,
548           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
549 
550   g_object_class_install_property (gobject_class, PROP_BITRATE,
551       g_param_spec_uint ("bitrate", "Bitrate",
552           "Bitrate in kbit/sec",
553           1, G_MAXINT, PROP_BITRATE_DEFAULT,
554           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
555 
556   g_object_class_install_property (gobject_class, PROP_KEY_INT_MAX,
557       g_param_spec_int ("key-int-max", "Key-frame maximal interval",
558           "Distance Between Intra Frame inserted: -1=no intra update. -2=auto",
559           -2, 255, PROP_KEY_INT_MAX_DEFAULT,
560           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
561 
562   g_object_class_install_property (gobject_class, PROP_ENABLE_OPEN_GOP,
563       g_param_spec_boolean ("enable-open-gop", "Enable Open GOP",
564           "Allow intra-refresh using the CRA, not IDR",
565           PROP_ENABLE_OPEN_GOP_DEFAULT,
566           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
567 
568   g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL,
569       g_param_spec_uint ("config-interval", "VPS SPS PPS Send Interval",
570           "Send VPS, SPS and PPS Insertion Interval per every few IDR. 0: disabled",
571           0, UINT_MAX, PROP_CONFIG_INTERVAL_DEFAULT,
572           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
573 
574   g_object_class_install_property (gobject_class, PROP_CORES,
575       g_param_spec_uint ("cores", "Number of logical cores",
576           "Number of logical cores to be used. 0: auto",
577           0, UINT_MAX, PROP_CORES_DEFAULT,
578           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
579 
580   g_object_class_install_property (gobject_class, PROP_SOCKET,
581       g_param_spec_int ("socket", "Target socket",
582           "Target socket to run on. -1: all available",
583           -1, 1, PROP_SOCKET_DEFAULT,
584           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
585 
586   g_object_class_install_property (gobject_class, PROP_TILE_ROW,
587       g_param_spec_uint ("tile-row", "Tile Row Count",
588           "Tile count in the Row",
589           1, 16, PROP_TILE_ROW_DEFAULT,
590           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
591 
592   g_object_class_install_property (gobject_class, PROP_TILE_COL,
593       g_param_spec_uint ("tile-col", "Tile Column Count",
594           "Tile count in the Column",
595           1, 16, PROP_TILE_COL_DEFAULT,
596           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
597 
598   g_object_class_install_property (gobject_class, PROP_PRED_STRUCTURE,
599       g_param_spec_enum ("pred-struct", "Prediction Structure",
600           "Prediction Structure used to construct GOP",
601           GST_SVTHEVC_ENC_PRED_STRUCT_TYPE, PROP_PRED_STRUCTURE_DEFAULT,
602           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
603 
604   g_object_class_install_property (gobject_class, PROP_VBV_MAX_RATE,
605       g_param_spec_uint ("vbv-max-rate", "VBV Maxrate",
606           "VBV maxrate in kbit/sec for VBR mode",
607           0, G_MAXINT, PROP_VBV_MAX_RATE_DEFAULT,
608           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
609 
610   g_object_class_install_property (gobject_class, PROP_VBV_BUFFER_SIZE,
611       g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
612           "VBV buffer size in kbits for VBR mode",
613           0, G_MAXINT, PROP_VBV_BUFFER_SIZE_DEFAULT,
614           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
615 
616 
617   gst_element_class_set_static_metadata (element_class,
618       "svthevcenc", "Codec/Encoder/Video",
619       "Scalable Video Technology for HEVC Encoder (SVT-HEVC Encoder)",
620       "Yeongjin Jeong <yeongjin.jeong@navercorp.com>");
621 
622   gst_element_class_add_static_pad_template (element_class, &sink_factory);
623   gst_element_class_add_static_pad_template (element_class, &src_factory);
624 }
625 
626 static void
gst_svthevc_enc_init(GstSvtHevcEnc * encoder)627 gst_svthevc_enc_init (GstSvtHevcEnc * encoder)
628 {
629   EB_H265_ENC_INPUT *in_data;
630 
631   encoder->in_buf = g_slice_new0 (EB_BUFFERHEADERTYPE);
632   in_data = g_slice_new0 (EB_H265_ENC_INPUT);
633   encoder->in_buf->pBuffer = (unsigned char *) in_data;
634   encoder->in_buf->nSize = sizeof (*encoder->in_buf);
635   encoder->in_buf->pAppPrivate = NULL;
636 
637   encoder->insert_vui = PROP_INSERT_VUI_DEFAULT;
638   encoder->aud = PROP_AUD_DEFAULT;
639   encoder->hierarchical_level = PROP_HIERARCHICAL_LEVEL_DEFAULT;
640   encoder->la_depth = PROP_LOOKAHEAD_DISTANCE_DEFAULT;
641   encoder->enc_mode = PROP_ENCODER_MODE_DEFAULT;
642   encoder->rc_mode = PROP_RC_MODE_DEFAULT;
643   encoder->qp_i = PROP_QP_I_DEFAULT;
644   encoder->qp_max = PROP_QP_MAX_DEFAULT;
645   encoder->qp_min = PROP_QP_MIN_DEFAULT;
646   encoder->scene_change_detection = PROP_SCENE_CHANGE_DETECTION_DEFAULT;
647   encoder->tune = PROP_TUNE_DEFAULT;
648   encoder->base_layer_switch_mode = PROP_BASE_LAYER_SWITCH_MODE_DEFAULT;
649   encoder->bitrate = PROP_BITRATE_DEFAULT;
650   encoder->keyintmax = PROP_KEY_INT_MAX_DEFAULT;
651   encoder->enable_open_gop = PROP_ENABLE_OPEN_GOP_DEFAULT;
652   encoder->config_interval = PROP_CONFIG_INTERVAL_DEFAULT;
653   encoder->cores = PROP_CORES_DEFAULT;
654   encoder->socket = PROP_SOCKET_DEFAULT;
655   encoder->tile_row = PROP_TILE_ROW_DEFAULT;
656   encoder->tile_col = PROP_TILE_COL_DEFAULT;
657   encoder->pred_structure = PROP_PRED_STRUCTURE_DEFAULT;
658   encoder->vbv_maxrate = PROP_VBV_MAX_RATE_DEFAULT;
659   encoder->vbv_bufsize = PROP_VBV_BUFFER_SIZE_DEFAULT;
660 
661   encoder->profile = PROFILE_DEFAULT;
662   encoder->tier = TIER_DEFAULT;
663   encoder->level = LEVEL_DEFAULT;
664 
665   encoder->svthevc_version =
666       g_strdup_printf ("%d.%d.%d", SVT_VERSION_MAJOR, SVT_VERSION_MINOR,
667       SVT_VERSION_PATCHLEVEL);
668   encoder->push_header = TRUE;
669   encoder->first_buffer = TRUE;
670   encoder->update_latency = TRUE;
671 
672   encoder->internal_pool = NULL;
673   encoder->aligned_info = NULL;
674 
675   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (encoder));
676 }
677 
678 static gboolean
gst_svthevc_enc_start(GstVideoEncoder * encoder)679 gst_svthevc_enc_start (GstVideoEncoder * encoder)
680 {
681   GstSvtHevcEnc *svthevcenc = GST_SVTHEVC_ENC (encoder);
682 
683   GST_INFO_OBJECT (svthevcenc, "start encoder");
684 
685   /* make sure that we have enough time for first DTS,
686      this is probably overkill for most streams */
687   gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
688 
689   return TRUE;
690 }
691 
692 static gboolean
gst_svthevc_enc_stop(GstVideoEncoder * encoder)693 gst_svthevc_enc_stop (GstVideoEncoder * encoder)
694 {
695   GstSvtHevcEnc *svthevcenc = GST_SVTHEVC_ENC (encoder);
696 
697   GST_INFO_OBJECT (encoder, "stop encoder");
698 
699   /* Always drain SVT-HEVC encoder before releasing SVT-HEVC.
700    * Otherwise, randomly block happens when releasing SVT-HEVC. */
701   gst_svthevc_enc_drain_encoder (svthevcenc, FALSE);
702   gst_svthevc_enc_close_encoder (svthevcenc);
703 
704   if (svthevcenc->input_state)
705     gst_video_codec_state_unref (svthevcenc->input_state);
706   svthevcenc->input_state = NULL;
707 
708   if (svthevcenc->internal_pool)
709     gst_object_unref (svthevcenc->internal_pool);
710   svthevcenc->internal_pool = NULL;
711 
712   if (svthevcenc->aligned_info)
713     gst_video_info_free (svthevcenc->aligned_info);
714   svthevcenc->aligned_info = NULL;
715 
716   return TRUE;
717 }
718 
719 
720 static gboolean
gst_svthevc_enc_flush(GstVideoEncoder * encoder)721 gst_svthevc_enc_flush (GstVideoEncoder * encoder)
722 {
723   GstSvtHevcEnc *svthevcenc = GST_SVTHEVC_ENC (encoder);
724 
725   GST_INFO_OBJECT (encoder, "flushing encoder");
726 
727   /* Always drain SVT-HEVC encoder before releasing SVT-HEVC.
728    * Otherwise, randomly block happens when releasing SVT-HEVC. */
729   gst_svthevc_enc_drain_encoder (svthevcenc, FALSE);
730   gst_svthevc_enc_close_encoder (svthevcenc);
731 
732   GST_OBJECT_LOCK (encoder);
733   if (!gst_svthevc_enc_init_encoder (svthevcenc)) {
734     GST_OBJECT_UNLOCK (encoder);
735     return FALSE;
736   }
737   GST_OBJECT_UNLOCK (encoder);
738 
739   return TRUE;
740 }
741 
742 static void
gst_svthevc_enc_finalize(GObject * object)743 gst_svthevc_enc_finalize (GObject * object)
744 {
745   GstSvtHevcEnc *encoder = GST_SVTHEVC_ENC (object);
746 
747   if (encoder->in_buf) {
748     EB_H265_ENC_INPUT *in_data = (EB_H265_ENC_INPUT *) encoder->in_buf->pBuffer;
749     if (in_data)
750       g_slice_free (EB_H265_ENC_INPUT, in_data);
751     g_slice_free (EB_BUFFERHEADERTYPE, encoder->in_buf);
752   }
753 
754   g_free ((gpointer) encoder->svthevc_version);
755 
756   G_OBJECT_CLASS (parent_class)->finalize (object);
757 }
758 
759 static gint
gst_svthevc_enc_gst_to_svthevc_video_format(GstVideoFormat format,gint * nplanes)760 gst_svthevc_enc_gst_to_svthevc_video_format (GstVideoFormat format,
761     gint * nplanes)
762 {
763   switch (format) {
764     case GST_VIDEO_FORMAT_I420:
765     case GST_VIDEO_FORMAT_YV12:
766     case GST_VIDEO_FORMAT_I420_10LE:
767     case GST_VIDEO_FORMAT_I420_10BE:
768       if (nplanes)
769         *nplanes = 3;
770       return EB_YUV420;
771     case GST_VIDEO_FORMAT_Y42B:
772     case GST_VIDEO_FORMAT_I422_10LE:
773     case GST_VIDEO_FORMAT_I422_10BE:
774       if (nplanes)
775         *nplanes = 3;
776       return EB_YUV422;
777     case GST_VIDEO_FORMAT_Y444:
778     case GST_VIDEO_FORMAT_Y444_10LE:
779     case GST_VIDEO_FORMAT_Y444_10BE:
780       if (nplanes)
781         *nplanes = 3;
782       return EB_YUV444;
783     default:
784       g_return_val_if_reached (GST_VIDEO_FORMAT_UNKNOWN);
785   }
786 }
787 
788 static void
config_enc_params(GstSvtHevcEnc * encoder,EB_H265_ENC_CONFIGURATION * param)789 config_enc_params (GstSvtHevcEnc * encoder, EB_H265_ENC_CONFIGURATION * param)
790 {
791   GstVideoInfo *info;
792 
793   info = &encoder->input_state->info;
794 
795   param->sourceWidth = info->width;
796   param->sourceHeight = info->height;
797 
798   if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10) {
799     GST_DEBUG_OBJECT (encoder, "Encoder 10 bits depth input");
800     /* Disable Compressed 10-bit format default.
801      * SVT-HEVC support a compressed 10-bit format allowing the
802      * software to achieve a higher speed and channel density levels.
803      * The conversion between the 10-bit I420 and the compressed
804      * 10-bit format is a lossless operation.
805      */
806     param->compressedTenBitFormat = 0;
807     param->encoderBitDepth = 10;
808   }
809   /* Update param from options */
810   param->hierarchicalLevels = encoder->hierarchical_level;
811   param->encMode = encoder->enc_mode;
812   param->profile = encoder->profile;
813   param->tier = encoder->tier;
814   param->level = encoder->level;
815   param->rateControlMode = encoder->rc_mode;
816   param->sceneChangeDetection = encoder->scene_change_detection;
817   param->tune = encoder->tune;
818   param->latencyMode = 0;
819   param->baseLayerSwitchMode = encoder->base_layer_switch_mode;
820   param->qp = encoder->qp_i;
821   param->accessUnitDelimiter = encoder->aud;
822 
823   param->targetBitRate = encoder->bitrate * 1000;
824   param->intraPeriodLength =
825       encoder->keyintmax > 0 ? encoder->keyintmax - 1 : encoder->keyintmax;
826 
827   if (info->fps_d == 0 || info->fps_n == 0) {
828     param->frameRateNumerator = 0;
829     param->frameRateDenominator = 1;
830   } else {
831     param->frameRateNumerator = info->fps_n;
832     param->frameRateDenominator = info->fps_d;
833   }
834 
835   if (param->rateControlMode) {
836     param->maxQpAllowed = encoder->qp_max;
837     param->minQpAllowed = encoder->qp_min;
838   }
839 
840   if (encoder->enable_open_gop)
841     param->intraRefreshType = -1;
842   else
843     param->intraRefreshType = encoder->config_interval;
844 
845   param->logicalProcessors = encoder->cores;
846   param->targetSocket = encoder->socket;
847 
848   param->tileRowCount = encoder->tile_row;
849   param->tileColumnCount = encoder->tile_col;
850 
851   param->predStructure = encoder->pred_structure;
852 
853   if (encoder->vbv_maxrate)
854     param->vbvMaxrate = encoder->vbv_maxrate * 1000;
855 
856   if (encoder->vbv_bufsize)
857     param->vbvBufsize = encoder->vbv_bufsize * 1000;
858 
859   /*
860    * NOTE: codeVpsSpsPps flag allows the VPS, SPS and PPS Insertion and
861    * sending in first IDR frame. But in the SVT-HEVC specific version,
862    * If codeVpsSpsPps enabled and using the EbH265EncStreamHeader API
863    * before receiving encoded packets, It cause bug which encoded packets
864    * are not output.
865    */
866   if (SVT_CHECK_VERSION (1, 4, 1))
867     param->codeVpsSpsPps = 1;
868   else
869     param->codeVpsSpsPps = 0;
870 
871   param->codeEosNal = 1;
872 
873   if (encoder->insert_vui)
874     param->videoUsabilityInfo = encoder->insert_vui;
875 
876   if (encoder->la_depth != -1)
877     param->lookAheadDistance = encoder->la_depth;
878 
879   param->encoderColorFormat =
880       gst_svthevc_enc_gst_to_svthevc_video_format (info->finfo->format, NULL);
881 }
882 
883 static void
read_in_data(EB_H265_ENC_CONFIGURATION * config,GstVideoFrame * vframe,EB_BUFFERHEADERTYPE * headerPtr)884 read_in_data (EB_H265_ENC_CONFIGURATION * config,
885     GstVideoFrame * vframe, EB_BUFFERHEADERTYPE * headerPtr)
886 {
887   EB_H265_ENC_INPUT *in_data = (EB_H265_ENC_INPUT *) headerPtr->pBuffer;
888 
889   in_data->luma = GST_VIDEO_FRAME_PLANE_DATA (vframe, 0);
890   in_data->cb = GST_VIDEO_FRAME_PLANE_DATA (vframe, 1);
891   in_data->cr = GST_VIDEO_FRAME_PLANE_DATA (vframe, 2);
892 
893   in_data->yStride =
894       GST_VIDEO_FRAME_COMP_STRIDE (vframe,
895       0) / GST_VIDEO_FRAME_COMP_PSTRIDE (vframe, 0);
896   in_data->cbStride =
897       GST_VIDEO_FRAME_COMP_STRIDE (vframe,
898       1) / GST_VIDEO_FRAME_COMP_PSTRIDE (vframe, 1);
899   in_data->crStride =
900       GST_VIDEO_FRAME_COMP_STRIDE (vframe,
901       2) / GST_VIDEO_FRAME_COMP_PSTRIDE (vframe, 2);
902 
903   headerPtr->nAllocLen = headerPtr->nFilledLen = GST_VIDEO_FRAME_SIZE (vframe);
904 }
905 
906 /*
907  * gst_svthevc_enc_init_encoder
908  * @encoder:  Encoder which should be initialized.
909  *
910  * Initialize svthevc encoder.
911  *
912  */
913 static gboolean
gst_svthevc_enc_init_encoder(GstSvtHevcEnc * encoder)914 gst_svthevc_enc_init_encoder (GstSvtHevcEnc * encoder)
915 {
916   EB_ERRORTYPE svt_ret;
917 
918   if (!encoder->input_state) {
919     GST_DEBUG_OBJECT (encoder, "Have no input state yet");
920     return FALSE;
921   }
922 
923   /* make sure that the encoder is closed */
924   gst_svthevc_enc_close_encoder (encoder);
925 
926   encoder->svt_eos_flag = EOS_NOT_REACHED;
927 
928   /* set up encoder parameters */
929   svt_ret = EbInitHandle (&encoder->svt_handle, encoder, &encoder->enc_params);
930   if (svt_ret != EB_ErrorNone) {
931     GST_DEBUG_OBJECT (encoder, "Error init encoder handle");
932     goto failed;
933   }
934 
935   config_enc_params (encoder, &encoder->enc_params);
936 
937   svt_ret = EbH265EncSetParameter (encoder->svt_handle, &encoder->enc_params);
938   if (svt_ret != EB_ErrorNone) {
939     GST_DEBUG_OBJECT (encoder, "Error setting encoder parameters");
940     goto failed_init_handle;
941   }
942 
943   svt_ret = EbInitEncoder (encoder->svt_handle);
944   if (svt_ret != EB_ErrorNone) {
945     GST_DEBUG_OBJECT (encoder, "Error init encoder");
946     goto failed_init_handle;
947   }
948 
949   encoder->push_header = TRUE;
950   encoder->first_buffer = TRUE;
951   encoder->update_latency = TRUE;
952   encoder->reconfig = FALSE;
953 
954   /* good start, will be corrected if needed */
955   encoder->dts_offset = 0;
956   encoder->first_frame = NULL;
957 
958   return TRUE;
959 
960 failed_init_handle:
961   EbDeinitHandle (encoder->svt_handle);
962 failed:
963   encoder->svt_handle = NULL;
964 
965   return FALSE;
966 }
967 
968 /* gst_svthevc_enc_close_encoder
969  * @encoder:  Encoder which should close.
970  *
971  * Close svthevc encoder.
972  */
973 static void
gst_svthevc_enc_close_encoder(GstSvtHevcEnc * encoder)974 gst_svthevc_enc_close_encoder (GstSvtHevcEnc * encoder)
975 {
976   if (encoder->svt_handle != NULL) {
977     EbDeinitEncoder (encoder->svt_handle);
978     EbDeinitHandle (encoder->svt_handle);
979     encoder->svt_handle = NULL;
980   }
981 }
982 
983 static EB_BUFFERHEADERTYPE *
gst_svthevc_enc_bytestream_to_nal(GstSvtHevcEnc * encoder,EB_BUFFERHEADERTYPE * input)984 gst_svthevc_enc_bytestream_to_nal (GstSvtHevcEnc * encoder,
985     EB_BUFFERHEADERTYPE * input)
986 {
987   EB_BUFFERHEADERTYPE *output;
988   int i, j, zeros;
989   int offset = 4;
990 
991   output = g_malloc (sizeof (EB_BUFFERHEADERTYPE));
992 
993   /* skip access unit delimiter */
994   if (encoder->aud)
995     offset += 7;
996 
997   output->pBuffer = g_malloc (input->nFilledLen - offset);
998   output->nFilledLen = input->nFilledLen - offset;
999 
1000   zeros = 0;
1001   for (i = offset, j = 0; i < input->nFilledLen; (i++, j++)) {
1002     if (input->pBuffer[i] == 0x00) {
1003       zeros++;
1004     } else if (input->pBuffer[i] == 0x03 && zeros == 2) {
1005       zeros = 0;
1006       j--;
1007       output->nFilledLen--;
1008       continue;
1009     } else {
1010       zeros = 0;
1011     }
1012     output->pBuffer[j] = input->pBuffer[i];
1013   }
1014 
1015   return output;
1016 }
1017 
1018 static void
svthevc_nal_free(EB_BUFFERHEADERTYPE * nal)1019 svthevc_nal_free (EB_BUFFERHEADERTYPE * nal)
1020 {
1021   g_free (nal->pBuffer);
1022   g_free (nal);
1023 }
1024 
1025 static gboolean
gst_svthevc_enc_set_level_tier_and_profile(GstSvtHevcEnc * encoder,GstCaps * caps)1026 gst_svthevc_enc_set_level_tier_and_profile (GstSvtHevcEnc * encoder,
1027     GstCaps * caps)
1028 {
1029   EB_BUFFERHEADERTYPE *headerPtr = NULL, *nal = NULL;
1030   EB_ERRORTYPE svt_ret;
1031   const gchar *level, *tier, *profile;
1032   GstStructure *s;
1033   GstCaps *allowed_caps;
1034   GstStructure *s2;
1035   const gchar *allowed_profile;
1036 
1037   GST_DEBUG_OBJECT (encoder, "set profile, level and tier");
1038 
1039   svt_ret = EbH265EncStreamHeader (encoder->svt_handle, &headerPtr);
1040   if (svt_ret != EB_ErrorNone) {
1041     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
1042         ("Encode svthevc header failed."),
1043         ("svthevc_encoder_headers return code=%d", svt_ret));
1044     return FALSE;
1045   }
1046 
1047   GST_MEMDUMP ("ENCODER_HEADER", headerPtr->pBuffer, headerPtr->nFilledLen);
1048 
1049   nal = gst_svthevc_enc_bytestream_to_nal (encoder, headerPtr);
1050 
1051   gst_codec_utils_h265_caps_set_level_tier_and_profile (caps,
1052       nal->pBuffer + 6, nal->nFilledLen - 6);
1053 
1054   svthevc_nal_free (nal);
1055 
1056   s = gst_caps_get_structure (caps, 0);
1057   profile = gst_structure_get_string (s, "profile");
1058   tier = gst_structure_get_string (s, "tier");
1059   level = gst_structure_get_string (s, "level");
1060 
1061   GST_DEBUG_OBJECT (encoder, "profile : %s", (profile) ? profile : "---");
1062   GST_DEBUG_OBJECT (encoder, "tier    : %s", (tier) ? tier : "---");
1063   GST_DEBUG_OBJECT (encoder, "level   : %s", (level) ? level : "---");
1064 
1065   /* Relaxing the profile condition since libSvtHevcEnc can generate
1066    * wrong bitstream indication for conformance to profile than requested one.
1067    * See : https://github.com/OpenVisualCloud/SVT-HEVC/pull/320
1068    */
1069   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1070 
1071   if (allowed_caps == NULL)
1072     goto no_peer;
1073 
1074   if (!gst_caps_can_intersect (allowed_caps, caps)) {
1075     GArray *peer_formats = g_array_new (FALSE, TRUE, sizeof (guint));
1076     GArray *enc_formats = g_array_new (FALSE, TRUE, sizeof (guint));
1077     gboolean is_subset = TRUE;
1078     guint i, j;
1079 
1080     allowed_caps = gst_caps_make_writable (allowed_caps);
1081     allowed_caps = gst_caps_truncate (allowed_caps);
1082     s2 = gst_caps_get_structure (allowed_caps, 0);
1083     gst_structure_fixate_field_string (s2, "profile", profile);
1084     allowed_profile = gst_structure_get_string (s2, "profile");
1085 
1086     get_support_format_from_profile (peer_formats, allowed_profile);
1087     get_support_format_from_profile (enc_formats, profile);
1088 
1089     for (i = 0; i < enc_formats->len; i++) {
1090       if (enc_formats->data[i]) {
1091         gboolean is_support = FALSE;
1092         for (j = 0; j < peer_formats->len; j++) {
1093           if (peer_formats->data[j] && (i == j))
1094             is_support = TRUE;
1095         }
1096         if (!is_support) {
1097           is_subset = FALSE;
1098           break;
1099         }
1100       }
1101     }
1102 
1103     GST_INFO_OBJECT (encoder, "downstream requested %s profile but "
1104         "encoder will now output %s profile (which is a %s), so relaxing the "
1105         "profile condition for negotiation",
1106         allowed_profile, profile, is_subset ? "subset" : "not subset");
1107 
1108     gst_structure_set (s, "profile", G_TYPE_STRING, allowed_profile, NULL);
1109 
1110     g_array_free (peer_formats, TRUE);
1111     g_array_free (enc_formats, TRUE);
1112   }
1113   gst_caps_unref (allowed_caps);
1114 
1115 no_peer:
1116   return TRUE;
1117 }
1118 
1119 static GstBuffer *
gst_svthevc_enc_get_header_buffer(GstSvtHevcEnc * encoder)1120 gst_svthevc_enc_get_header_buffer (GstSvtHevcEnc * encoder)
1121 {
1122   EB_BUFFERHEADERTYPE *headerPtr = NULL;
1123   EB_ERRORTYPE svt_ret;
1124   GstBuffer *buf;
1125 
1126   svt_ret = EbH265EncStreamHeader (encoder->svt_handle, &headerPtr);
1127   if (svt_ret != EB_ErrorNone) {
1128     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
1129         ("Encode svthevc header failed."),
1130         ("svthevc_encoder_headers return code=%d", svt_ret));
1131     return FALSE;
1132   }
1133 
1134   buf = gst_buffer_new_allocate (NULL, headerPtr->nFilledLen, NULL);
1135   gst_buffer_fill (buf, 0, headerPtr->pBuffer, headerPtr->nFilledLen);
1136 
1137   return buf;
1138 }
1139 
1140 /* gst_svthevc_enc_set_src_caps
1141  * Returns: TRUE on success.
1142  */
1143 static gboolean
gst_svthevc_enc_set_src_caps(GstSvtHevcEnc * encoder,GstCaps * caps)1144 gst_svthevc_enc_set_src_caps (GstSvtHevcEnc * encoder, GstCaps * caps)
1145 {
1146   GstCaps *outcaps;
1147   GstStructure *structure;
1148   GstVideoCodecState *state;
1149   GstTagList *tags;
1150 
1151   outcaps = gst_caps_new_empty_simple ("video/x-h265");
1152   structure = gst_caps_get_structure (outcaps, 0);
1153 
1154   gst_structure_set (structure, "stream-format", G_TYPE_STRING, "byte-stream",
1155       NULL);
1156   gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
1157 
1158   if (!gst_svthevc_enc_set_level_tier_and_profile (encoder, outcaps)) {
1159     gst_caps_unref (outcaps);
1160     return FALSE;
1161   }
1162 
1163   state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder),
1164       outcaps, encoder->input_state);
1165   GST_LOG_OBJECT (encoder, "output caps: %" GST_PTR_FORMAT, state->caps);
1166   gst_video_codec_state_unref (state);
1167 
1168   tags = gst_tag_list_new_empty ();
1169   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "svthevc",
1170       GST_TAG_ENCODER_VERSION, encoder->svthevc_version, NULL);
1171   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder), tags,
1172       GST_TAG_MERGE_REPLACE);
1173   gst_tag_list_unref (tags);
1174 
1175   return TRUE;
1176 }
1177 
1178 static void
gst_svthevc_enc_set_latency(GstSvtHevcEnc * encoder)1179 gst_svthevc_enc_set_latency (GstSvtHevcEnc * encoder)
1180 {
1181   GstVideoInfo *info = &encoder->input_state->info;
1182   guint max_delayed_frames;
1183   GstClockTime latency;
1184 
1185   if (encoder->first_buffer) {
1186     /* FIXME get a real value from the encoder, this is currently not exposed */
1187     max_delayed_frames = 5;
1188   } else {
1189     GList *frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (encoder));
1190     max_delayed_frames = g_list_length (frames);
1191     g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
1192   }
1193 
1194   if (info->fps_n) {
1195     latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
1196         max_delayed_frames, info->fps_n);
1197   } else {
1198     /* FIXME: Assume 25fps. This is better than reporting no latency at
1199      * all and then later failing in live pipelines
1200      */
1201     latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
1202         max_delayed_frames, 25);
1203   }
1204 
1205   GST_INFO_OBJECT (encoder,
1206       "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
1207       GST_TIME_ARGS (latency), max_delayed_frames);
1208 
1209   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (encoder), latency, latency);
1210 }
1211 
1212 static const guint
gst_svthevc_enc_profile_from_gst(const GstH265Profile profile)1213 gst_svthevc_enc_profile_from_gst (const GstH265Profile profile)
1214 {
1215   gint i;
1216 
1217   for (i = 0; i < G_N_ELEMENTS (profile_table); i++) {
1218     if (profile == profile_table[i].gst_profile)
1219       return profile_table[i].svt_profile;
1220   }
1221 
1222   GST_WARNING ("Unsupported profile string '%s'",
1223       gst_h265_profile_to_string (profile));
1224   return 0;
1225 }
1226 
1227 static guint
gst_svthevc_enc_level_from_gst(const gchar * level)1228 gst_svthevc_enc_level_from_gst (const gchar * level)
1229 {
1230   if (g_str_equal (level, "1"))
1231     return 10;
1232   else if (g_str_equal (level, "2"))
1233     return 20;
1234   else if (g_str_equal (level, "2.1"))
1235     return 21;
1236   else if (g_str_equal (level, "3"))
1237     return 30;
1238   else if (g_str_equal (level, "3.1"))
1239     return 31;
1240   else if (g_str_equal (level, "4"))
1241     return 40;
1242   else if (g_str_equal (level, "4.1"))
1243     return 41;
1244   else if (g_str_equal (level, "5"))
1245     return 50;
1246   else if (g_str_equal (level, "5.1"))
1247     return 51;
1248   else if (g_str_equal (level, "5.2"))
1249     return 52;
1250   else if (g_str_equal (level, "6"))
1251     return 60;
1252   else if (g_str_equal (level, "6.1"))
1253     return 61;
1254   else if (g_str_equal (level, "6.2"))
1255     return 62;
1256 
1257   GST_WARNING ("Unsupported level string '%s'", level);
1258   return LEVEL_DEFAULT;
1259 }
1260 
1261 static guint
gst_svthevc_enc_tier_from_gst(const gchar * level)1262 gst_svthevc_enc_tier_from_gst (const gchar * level)
1263 {
1264   if (g_str_equal (level, "main"))
1265     return 0;
1266   else if (g_str_equal (level, "high"))
1267     return 1;
1268 
1269   GST_WARNING ("Unsupported tier string '%s'", level);
1270   return TIER_DEFAULT;
1271 }
1272 
1273 static gboolean
gst_svthevc_enc_set_format(GstVideoEncoder * video_enc,GstVideoCodecState * state)1274 gst_svthevc_enc_set_format (GstVideoEncoder * video_enc,
1275     GstVideoCodecState * state)
1276 {
1277   GstSvtHevcEnc *encoder = GST_SVTHEVC_ENC (video_enc);
1278   GstVideoInfo *info = &state->info;
1279   GstCaps *template_caps;
1280   GstCaps *allowed_caps;
1281 
1282   /* If the encoder is initialized, do not reinitialize it again if not
1283    * necessary */
1284   if (encoder->svt_handle) {
1285     GstVideoInfo *old = &encoder->input_state->info;
1286 
1287     if (info->finfo->format == old->finfo->format
1288         && info->width == old->width && info->height == old->height
1289         && info->fps_n == old->fps_n && info->fps_d == old->fps_d
1290         && info->par_n == old->par_n && info->par_d == old->par_d) {
1291       gst_video_codec_state_unref (encoder->input_state);
1292       encoder->input_state = gst_video_codec_state_ref (state);
1293       return TRUE;
1294     }
1295 
1296     /* clear out pending frames */
1297     gst_svthevc_enc_drain_encoder (encoder, TRUE);
1298   }
1299 
1300   if (encoder->input_state)
1301     gst_video_codec_state_unref (encoder->input_state);
1302   encoder->input_state = gst_video_codec_state_ref (state);
1303 
1304   template_caps = gst_static_pad_template_get_caps (&src_factory);
1305   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1306 
1307   if (allowed_caps == template_caps) {
1308     GST_INFO_OBJECT (encoder, "downstream has ANY caps");
1309 
1310     /* SVT-HEVC encoder does not yet support auto profile selecting.
1311      * So we should be set the profile from input format */
1312     encoder->profile = GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 8 ? 1 : 2;
1313     switch (GST_VIDEO_INFO_FORMAT (info)) {
1314       case GST_VIDEO_FORMAT_Y42B:
1315       case GST_VIDEO_FORMAT_I422_10LE:
1316       case GST_VIDEO_FORMAT_I422_10BE:
1317       case GST_VIDEO_FORMAT_Y444:
1318       case GST_VIDEO_FORMAT_Y444_10LE:
1319       case GST_VIDEO_FORMAT_Y444_10BE:
1320         encoder->profile = 4;
1321       default:
1322         break;
1323     }
1324 
1325     gst_caps_unref (allowed_caps);
1326   } else if (allowed_caps) {
1327     GstStructure *s;
1328     const gchar *profile;
1329     const gchar *level;
1330     const gchar *tier;
1331 
1332     GST_LOG_OBJECT (encoder, "allowed caps %" GST_PTR_FORMAT, allowed_caps);
1333 
1334     if (gst_caps_is_empty (allowed_caps)) {
1335       gst_caps_unref (template_caps);
1336       gst_caps_unref (allowed_caps);
1337       return FALSE;
1338     }
1339 
1340     s = gst_caps_get_structure (allowed_caps, 0);
1341 
1342     if (gst_structure_has_field (s, "profile")) {
1343       const GValue *v = gst_structure_get_value (s, "profile");
1344       GArray *profiles = g_array_new (FALSE, TRUE, sizeof (guint));
1345       GstH265Profile gst_profile;
1346       guint svt_profile = 0;
1347 
1348       get_compatible_profile_from_format (profiles,
1349           GST_VIDEO_INFO_FORMAT (info));
1350 
1351       if (GST_VALUE_HOLDS_LIST (v)) {
1352         const gint list_size = gst_value_list_get_size (v);
1353         gint i, j;
1354 
1355         for (i = 0; i < list_size; i++) {
1356           const GValue *list_val = gst_value_list_get_value (v, i);
1357           profile = g_value_get_string (list_val);
1358 
1359           if (profile) {
1360             gst_profile =
1361                 gst_h265_profile_from_string (g_value_get_string (list_val));
1362 
1363             for (j = 0; j < profiles->len; j++) {
1364               if (profiles->data[j] && (j == gst_profile)) {
1365                 svt_profile = gst_svthevc_enc_profile_from_gst (j);
1366                 break;
1367               }
1368             }
1369           }
1370 
1371           if (svt_profile != 0)
1372             break;
1373         }
1374       } else if (G_VALUE_HOLDS_STRING (v)) {
1375         gint i;
1376         profile = g_value_get_string (v);
1377 
1378         if (profile) {
1379           gst_profile = gst_h265_profile_from_string (g_value_get_string (v));
1380 
1381           for (i = 0; i < profiles->len; i++) {
1382             if (profiles->data[i] && (i == gst_profile)) {
1383               svt_profile = gst_svthevc_enc_profile_from_gst (i);
1384               break;
1385             }
1386           }
1387         }
1388       }
1389 
1390       g_array_free (profiles, TRUE);
1391 
1392       if (svt_profile == 0) {
1393         GST_ERROR_OBJECT (encoder, "Could't apply peer profile");
1394         gst_caps_unref (template_caps);
1395         gst_caps_unref (allowed_caps);
1396         return FALSE;
1397       }
1398 
1399       encoder->profile = svt_profile;
1400     }
1401 
1402     level = gst_structure_get_string (s, "level");
1403     if (level)
1404       encoder->level = gst_svthevc_enc_level_from_gst (level);
1405 
1406     tier = gst_structure_get_string (s, "tier");
1407     if (tier)
1408       encoder->tier = gst_svthevc_enc_tier_from_gst (tier);
1409 
1410     gst_caps_unref (allowed_caps);
1411   }
1412   gst_caps_unref (template_caps);
1413 
1414   GST_INFO_OBJECT (encoder, "Using profile %d, tier %d, level %d",
1415       encoder->profile, encoder->tier, encoder->level);
1416 
1417   GST_OBJECT_LOCK (encoder);
1418   if (!gst_svthevc_enc_init_encoder (encoder)) {
1419     GST_OBJECT_UNLOCK (encoder);
1420     return FALSE;
1421   }
1422   GST_OBJECT_UNLOCK (encoder);
1423 
1424   if (!gst_svthevc_enc_set_src_caps (encoder, state->caps)) {
1425     gst_svthevc_enc_close_encoder (encoder);
1426     return FALSE;
1427   }
1428 
1429   {
1430     /* The SVT-HEVC uses stride in pixel, not in bytes, while upstream can
1431      * provide aligned stride in bytes. So there is no guaranty
1432      * that a stride is multiple of PSTRIDE, we should ensure internal pool
1433      * to use when converting frames. */
1434     GstVideoAlignment video_align;
1435     GstAllocationParams params = { 0, 15, 0, 0 };
1436     GstCaps *caps;
1437     GstBufferPool *pool;
1438     GstStructure *config;
1439     guint i, size;
1440 
1441     if (encoder->internal_pool)
1442       gst_object_unref (encoder->internal_pool);
1443     encoder->internal_pool = NULL;
1444 
1445     if (encoder->aligned_info)
1446       gst_video_info_free (encoder->aligned_info);
1447     encoder->aligned_info = gst_video_info_copy (info);
1448 
1449     caps = gst_video_info_to_caps (info);
1450     pool = gst_video_buffer_pool_new ();
1451 
1452     size = GST_VIDEO_INFO_SIZE (info);
1453     GST_INFO_OBJECT (encoder,
1454         "create internal buffer pool size %u, caps %" GST_PTR_FORMAT, size,
1455         caps);
1456 
1457     config = gst_buffer_pool_get_config (pool);
1458     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
1459     gst_buffer_pool_config_set_allocator (config, NULL, &params);
1460 
1461     gst_caps_unref (caps);
1462 
1463     /* set stride align */
1464     gst_video_alignment_reset (&video_align);
1465     for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++)
1466       video_align.stride_align[i] = GST_VIDEO_INFO_COMP_PSTRIDE (info, i) - 1;
1467     gst_video_info_align (encoder->aligned_info, &video_align);
1468 
1469     gst_buffer_pool_config_add_option (config,
1470         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1471     gst_buffer_pool_config_set_video_alignment (config, &video_align);
1472 
1473     if (!gst_buffer_pool_set_config (pool, config)) {
1474       if (pool)
1475         gst_object_unref (pool);
1476       pool = NULL;
1477     }
1478     gst_buffer_pool_set_active (pool, TRUE);
1479 
1480     encoder->internal_pool = pool;
1481   }
1482 
1483   gst_svthevc_enc_set_latency (encoder);
1484 
1485   return TRUE;
1486 }
1487 
1488 static GstFlowReturn
gst_svthevc_enc_finish(GstVideoEncoder * encoder)1489 gst_svthevc_enc_finish (GstVideoEncoder * encoder)
1490 {
1491   GST_INFO_OBJECT (encoder, "finish encoder");
1492 
1493   gst_svthevc_enc_drain_encoder (GST_SVTHEVC_ENC (encoder), TRUE);
1494   return GST_FLOW_OK;
1495 }
1496 
1497 static gboolean
gst_svthevc_enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)1498 gst_svthevc_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1499 {
1500   GstSvtHevcEnc *svthevcenc = GST_SVTHEVC_ENC (encoder);
1501   GstCaps *caps;
1502   GstVideoInfo info;
1503   GstVideoAlignment video_align;
1504   GstBufferPool *pool;
1505   GstStructure *config;
1506   guint i, size, min, max;
1507 
1508   GST_INFO_OBJECT (svthevcenc, "propose allocation");
1509 
1510   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1511 
1512   gst_query_parse_allocation (query, &caps, NULL);
1513 
1514   if (caps == NULL)
1515     goto done;
1516 
1517   if (!gst_video_info_from_caps (&info, caps))
1518     goto done;
1519 
1520   /* We should propose to specify required stride alignments. */
1521   gst_video_alignment_reset (&video_align);
1522   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++)
1523     video_align.stride_align[i] = GST_VIDEO_INFO_COMP_PSTRIDE (&info, i) - 1;
1524   gst_video_info_align (&info, &video_align);
1525 
1526   if (gst_query_get_n_allocation_pools (query) > 0) {
1527     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1528     config = gst_buffer_pool_get_config (pool);
1529 
1530     /* set stride align */
1531     gst_buffer_pool_config_add_option (config,
1532         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1533     gst_buffer_pool_config_set_video_alignment (config, &video_align);
1534 
1535     gst_buffer_pool_set_config (pool, config);
1536     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1537   } else {
1538     GstAllocator *allocator = NULL;
1539     GstAllocationParams params = { 0, 15, 0, 0 };
1540 
1541     size = GST_VIDEO_INFO_SIZE (&info);
1542     GST_INFO_OBJECT (svthevcenc,
1543         "create buffer pool size %u, caps %" GST_PTR_FORMAT, size, caps);
1544 
1545     if (gst_query_get_n_allocation_params (query) > 0)
1546       gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
1547     else
1548       gst_query_add_allocation_param (query, allocator, &params);
1549 
1550     pool = gst_video_buffer_pool_new ();
1551 
1552     config = gst_buffer_pool_get_config (pool);
1553     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
1554     gst_buffer_pool_config_set_allocator (config, allocator, &params);
1555 
1556     /* set stride align */
1557     gst_buffer_pool_config_add_option (config,
1558         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1559     gst_buffer_pool_config_set_video_alignment (config, &video_align);
1560 
1561     if (allocator)
1562       gst_object_unref (allocator);
1563 
1564     if (!gst_buffer_pool_set_config (pool, config))
1565       goto done;
1566 
1567     gst_query_add_allocation_pool (query, pool, size, 0, 0);
1568   }
1569 
1570 done:
1571   if (pool)
1572     gst_object_unref (pool);
1573 
1574   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1575       query);
1576 }
1577 
1578 /* chain function
1579  * this function does the actual processing
1580  */
1581 static GstFlowReturn
gst_svthevc_enc_handle_frame(GstVideoEncoder * video_enc,GstVideoCodecFrame * frame)1582 gst_svthevc_enc_handle_frame (GstVideoEncoder * video_enc,
1583     GstVideoCodecFrame * frame)
1584 {
1585   GstSvtHevcEnc *encoder = GST_SVTHEVC_ENC (video_enc);
1586   GstFlowReturn ret = GST_FLOW_OK;
1587   gboolean got_packet;
1588 
1589   if (G_UNLIKELY (encoder->svt_handle == NULL))
1590     goto not_inited;
1591 
1592   ret = gst_svthevc_enc_send_frame (encoder, frame);
1593 
1594   if (ret != GST_FLOW_OK)
1595     goto encode_fail;
1596 
1597   do {
1598     ret = gst_svthevc_enc_receive_frame (encoder, &got_packet, TRUE);
1599     GST_LOG_OBJECT (encoder, "ret %d, got_packet %d", ret, got_packet);
1600     if (ret != GST_FLOW_OK)
1601       break;
1602   } while (got_packet);
1603 
1604 done:
1605   return ret;
1606 
1607 /* ERRORS */
1608 not_inited:
1609   {
1610     GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1611     return GST_FLOW_NOT_NEGOTIATED;
1612   }
1613 encode_fail:
1614   {
1615     /* avoid frame (and ts etc) piling up */
1616     if (frame)
1617       ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (encoder), frame);
1618     goto done;
1619   }
1620 }
1621 
1622 static gboolean
gst_svthevc_enc_convert_frame(GstSvtHevcEnc * encoder,GstVideoCodecFrame * frame)1623 gst_svthevc_enc_convert_frame (GstSvtHevcEnc * encoder,
1624     GstVideoCodecFrame * frame)
1625 {
1626   GstVideoInfo *info = &encoder->input_state->info;
1627   GstVideoFrame src_frame, aligned_frame;
1628   GstBuffer *aligned_buffer;
1629 
1630   if (encoder->internal_pool == NULL)
1631     return FALSE;
1632 
1633   if (gst_buffer_pool_acquire_buffer (encoder->internal_pool, &aligned_buffer,
1634           NULL) != GST_FLOW_OK) {
1635     GST_ERROR_OBJECT (encoder, "Failed to acquire a buffer from pool");
1636     return FALSE;
1637   }
1638 
1639   if (!gst_video_frame_map (&src_frame, info, frame->input_buffer,
1640           GST_MAP_READ)) {
1641     GST_ERROR_OBJECT (encoder, "Failed to map the frame for aligned buffer");
1642     goto error;
1643   }
1644 
1645   /* FIXME: need to adjust video info align?? */
1646   if (!gst_video_frame_map (&aligned_frame, encoder->aligned_info,
1647           aligned_buffer, GST_MAP_WRITE)) {
1648     GST_ERROR_OBJECT (encoder, "Failed to map the frame for aligned buffer");
1649     gst_video_frame_unmap (&src_frame);
1650     goto error;
1651   }
1652 
1653   if (!gst_video_frame_copy (&aligned_frame, &src_frame)) {
1654     GST_ERROR_OBJECT (encoder, "Failed to copy frame");
1655     gst_video_frame_unmap (&src_frame);
1656     gst_video_frame_unmap (&aligned_frame);
1657     goto error;
1658   }
1659 
1660   gst_video_frame_unmap (&src_frame);
1661   gst_video_frame_unmap (&aligned_frame);
1662 
1663   gst_buffer_replace (&frame->input_buffer, aligned_buffer);
1664   gst_buffer_unref (aligned_buffer);
1665 
1666   return TRUE;
1667 
1668 error:
1669   if (aligned_buffer)
1670     gst_buffer_unref (aligned_buffer);
1671   return FALSE;
1672 }
1673 
1674 static GstFlowReturn
gst_svthevc_enc_send_frame(GstSvtHevcEnc * encoder,GstVideoCodecFrame * frame)1675 gst_svthevc_enc_send_frame (GstSvtHevcEnc * encoder, GstVideoCodecFrame * frame)
1676 {
1677   GstFlowReturn ret = GST_FLOW_OK;
1678   EB_BUFFERHEADERTYPE *headerPtr = NULL;
1679   GstVideoInfo *info = &encoder->input_state->info;
1680   GstVideoFrame vframe;
1681   EB_ERRORTYPE svt_ret;
1682   guint i;
1683 
1684   if (encoder->svt_eos_flag == EOS_REACHED) {
1685     if (frame)
1686       gst_video_codec_frame_unref (frame);
1687     return GST_FLOW_OK;
1688   }
1689 
1690   if (encoder->svt_eos_flag == EOS_TOTRIGGER) {
1691     if (frame)
1692       gst_video_codec_frame_unref (frame);
1693     return GST_FLOW_EOS;
1694   }
1695 
1696   if (!frame)
1697     goto out;
1698 
1699   headerPtr = encoder->in_buf;
1700 
1701   /* Check that stride is a multiple of pstride, otherwise convert to
1702    * desired stride from SVT-HEVC.*/
1703   for (i = 0; i < 3; i++) {
1704     if (GST_VIDEO_INFO_COMP_STRIDE (info,
1705             i) % GST_VIDEO_INFO_COMP_PSTRIDE (info, i)) {
1706       GST_LOG_OBJECT (encoder, "need to convert frame");
1707       if (!gst_svthevc_enc_convert_frame (encoder, frame)) {
1708         if (frame)
1709           gst_video_codec_frame_unref (frame);
1710       }
1711       break;
1712     }
1713   }
1714 
1715   if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ)) {
1716     GST_ERROR_OBJECT (encoder, "Failed to map frame");
1717     if (frame)
1718       gst_video_codec_frame_unref (frame);
1719     return GST_FLOW_ERROR;
1720   }
1721 
1722   read_in_data (&encoder->enc_params, &vframe, headerPtr);
1723 
1724   headerPtr->nFlags = 0;
1725   headerPtr->sliceType = EB_INVALID_PICTURE;
1726   headerPtr->pAppPrivate = NULL;
1727   headerPtr->pts = frame->pts;
1728 
1729   if (encoder->reconfig && frame) {
1730     /* svthevc_encoder_reconfig is not yet implemented thus we shut down and re-create encoder */
1731     GST_INFO_OBJECT (encoder, "reconfigure encoder");
1732     gst_svthevc_enc_drain_encoder (encoder, TRUE);
1733     GST_OBJECT_LOCK (encoder);
1734     if (!gst_svthevc_enc_init_encoder (encoder)) {
1735       GST_OBJECT_UNLOCK (encoder);
1736       return GST_FLOW_ERROR;
1737     }
1738     GST_OBJECT_UNLOCK (encoder);
1739   }
1740 
1741   if (headerPtr && frame) {
1742     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1743       GST_INFO_OBJECT (encoder, "Forcing key frame");
1744       headerPtr->sliceType = EB_IDR_PICTURE;
1745     }
1746   }
1747 
1748 out:
1749   if (!headerPtr) {
1750     EB_BUFFERHEADERTYPE headerPtrLast;
1751 
1752     if (encoder->first_buffer) {
1753       GST_DEBUG_OBJECT (encoder, "No need to send eos buffer");
1754       encoder->svt_eos_flag = EOS_TOTRIGGER;
1755       return GST_FLOW_OK;
1756     }
1757 
1758     headerPtrLast.nAllocLen = 0;
1759     headerPtrLast.nFilledLen = 0;
1760     headerPtrLast.nTickCount = 0;
1761     headerPtrLast.pAppPrivate = NULL;
1762     headerPtrLast.pBuffer = NULL;
1763     headerPtrLast.nFlags = EB_BUFFERFLAG_EOS;
1764 
1765     GST_DEBUG_OBJECT (encoder, "drain frame");
1766     svt_ret = EbH265EncSendPicture (encoder->svt_handle, &headerPtrLast);
1767     encoder->svt_eos_flag = EOS_REACHED;
1768   } else {
1769     GST_LOG_OBJECT (encoder, "encode frame");
1770     svt_ret = EbH265EncSendPicture (encoder->svt_handle, headerPtr);
1771     encoder->first_buffer = FALSE;
1772   }
1773 
1774   GST_LOG_OBJECT (encoder, "encoder result (%d)", svt_ret);
1775 
1776   if (svt_ret != EB_ErrorNone) {
1777     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
1778         ("Encode svthevc frame failed."),
1779         ("svthevc_encoder_encode return code=%d", svt_ret));
1780     ret = GST_FLOW_ERROR;
1781   }
1782 
1783   /* Input frame is now queued */
1784   if (frame) {
1785     gst_video_frame_unmap (&vframe);
1786     gst_video_codec_frame_unref (frame);
1787   }
1788 
1789   return ret;
1790 }
1791 
1792 static GstVideoCodecFrame *
gst_svthevc_encoder_get_frame(GstVideoEncoder * encoder,GstClockTime ts)1793 gst_svthevc_encoder_get_frame (GstVideoEncoder * encoder, GstClockTime ts)
1794 {
1795   GList *g;
1796   GList *frames;
1797   GstVideoCodecFrame *frame = NULL;
1798 
1799   GST_LOG_OBJECT (encoder, "timestamp : %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1800 
1801   frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (encoder));
1802 
1803   for (g = frames; g; g = g->next) {
1804     GstVideoCodecFrame *tmp = g->data;
1805 
1806     if (tmp->pts == ts) {
1807       frame = gst_video_codec_frame_ref (tmp);
1808       break;
1809     }
1810   }
1811 
1812   g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
1813 
1814   return frame;
1815 }
1816 
1817 static GstClockTime
gst_svthevc_encoder_get_oldest_pts(GstVideoEncoder * encoder)1818 gst_svthevc_encoder_get_oldest_pts (GstVideoEncoder * encoder)
1819 {
1820   GList *g;
1821   GList *frames;
1822   GstClockTime min_ts = GST_CLOCK_TIME_NONE;
1823   gboolean seen_none = FALSE;
1824 
1825   frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (encoder));
1826 
1827   /* find the lowest unsent PTS */
1828   for (g = frames; g; g = g->next) {
1829     GstVideoCodecFrame *tmp = g->data;
1830 
1831     if (!GST_CLOCK_TIME_IS_VALID (tmp->abidata.ABI.ts)) {
1832       seen_none = TRUE;
1833       continue;
1834     }
1835 
1836     if (!GST_CLOCK_TIME_IS_VALID (min_ts) || tmp->abidata.ABI.ts < min_ts) {
1837       if (!seen_none)
1838         min_ts = tmp->abidata.ABI.ts;
1839     }
1840   }
1841 
1842   g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
1843 
1844   return min_ts;
1845 }
1846 
1847 static GstFlowReturn
gst_svthevc_enc_receive_frame(GstSvtHevcEnc * encoder,gboolean * got_packet,gboolean send)1848 gst_svthevc_enc_receive_frame (GstSvtHevcEnc * encoder,
1849     gboolean * got_packet, gboolean send)
1850 {
1851   GstVideoCodecFrame *frame = NULL;
1852   GstBuffer *out_buf = NULL;
1853   GstFlowReturn ret = GST_FLOW_OK;
1854   EB_BUFFERHEADERTYPE *output_buffer = NULL;
1855   EB_ERRORTYPE svt_ret;
1856 
1857   *got_packet = FALSE;
1858 
1859   if (encoder->svt_eos_flag == EOS_TOTRIGGER)
1860     return GST_FLOW_EOS;
1861 
1862   svt_ret =
1863       EbH265GetPacket (encoder->svt_handle, &output_buffer,
1864       encoder->svt_eos_flag);
1865 
1866   if (svt_ret == EB_NoErrorEmptyQueue) {
1867     GST_DEBUG_OBJECT (encoder, "no output yet");
1868     return GST_FLOW_OK;
1869   }
1870 
1871   if (svt_ret != EB_ErrorNone || !output_buffer) {
1872     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
1873         ("Encode svthevc frame failed."),
1874         ("EbH265GetPacket return code=%d", svt_ret));
1875     return GST_FLOW_ERROR;
1876   }
1877 
1878   GST_LOG_OBJECT (encoder, "got %d from svt", output_buffer->nFlags);
1879 
1880   *got_packet = TRUE;
1881 
1882   frame =
1883       gst_svthevc_encoder_get_frame (GST_VIDEO_ENCODER (encoder),
1884       output_buffer->pts);
1885 
1886   if (!frame && send) {
1887     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
1888         ("Encode svthevc frame failed."), ("Frame not found."));
1889     ret = GST_FLOW_ERROR;
1890     goto out;
1891   }
1892 
1893   if (!send || !frame) {
1894     GST_DEBUG_OBJECT (encoder, "not sending (%d) or frame not found (%d)", send,
1895         frame != NULL);
1896     ret = GST_FLOW_OK;
1897     goto out;
1898   }
1899 
1900   GST_LOG_OBJECT (encoder,
1901       "output picture ready system=%d frame found %d",
1902       frame->system_frame_number, frame != NULL);
1903 
1904   if (encoder->update_latency) {
1905     gst_svthevc_enc_set_latency (encoder);
1906     encoder->update_latency = FALSE;
1907   }
1908 
1909   out_buf = gst_buffer_new_allocate (NULL, output_buffer->nFilledLen, NULL);
1910   gst_buffer_fill (out_buf, 0, output_buffer->pBuffer,
1911       output_buffer->nFilledLen);
1912 
1913   frame->output_buffer = out_buf;
1914 
1915   if (output_buffer->sliceType == EB_IDR_PICTURE)
1916     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1917   else
1918     GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
1919 
1920   if (encoder->push_header) {
1921     GstBuffer *header;
1922 
1923     header = gst_svthevc_enc_get_header_buffer (encoder);
1924     frame->output_buffer = gst_buffer_append (header, frame->output_buffer);
1925     encoder->push_header = FALSE;
1926   }
1927 
1928   frame->pts = output_buffer->pts;
1929 
1930   if (encoder->pred_structure) {
1931     /* Since the SVT-HEVC does not support adjust dts when bframe was enabled,
1932      * output pts can be smaller than dts. The maximum difference between DTS and PTS can be calculated
1933      * using the PTS difference between the first frame and the second frame.
1934      */
1935     if (encoder->dts_offset == 0) {
1936       if (encoder->first_frame) {
1937         if (frame->pts > encoder->first_frame->pts) {
1938           encoder->dts_offset = frame->pts - encoder->first_frame->pts;
1939         } else {
1940           GstVideoInfo *info = &encoder->input_state->info;
1941           GstClockTime duration;
1942           gdouble framerate;
1943 
1944           GST_WARNING_OBJECT (encoder, "Could not calculate DTS offset");
1945 
1946           /* No way to get maximum bframe count since SVT-HEVC does not support it,
1947            * so using keyframe interval instead.
1948            */
1949           if (info->fps_d == 0 || info->fps_n == 0) {
1950             /* No way to get duration, assume 60fps. */
1951             duration = gst_util_uint64_scale (1, GST_SECOND, 60);
1952             framerate = 60;
1953           } else {
1954             duration =
1955                 gst_util_uint64_scale (info->fps_d, GST_SECOND, info->fps_n);
1956             gst_util_fraction_to_double (info->fps_n, info->fps_d, &framerate);
1957           }
1958 
1959           if (encoder->keyintmax > 0) {
1960             encoder->dts_offset = duration * encoder->keyintmax;
1961           } else {
1962             /* The SVT-HEVC sets the default gop-size the closest possible to
1963              * 1 second without breaking the minigop.
1964              */
1965             gint mini_gop = (1 << (encoder->hierarchical_level));
1966             gint keyintmin = ((int) ((framerate) / mini_gop) * (mini_gop));
1967             gint keyintmax =
1968                 ((int) ((framerate + mini_gop) / mini_gop) * (mini_gop));
1969             gint keyint =
1970                 (ABS ((framerate - keyintmax)) >
1971                 ABS ((framerate - keyintmin))) ? keyintmin : keyintmax;
1972 
1973             if (encoder->enable_open_gop)
1974               keyint -= 1;
1975 
1976             encoder->dts_offset = duration * keyint;
1977           }
1978         }
1979 
1980         GST_INFO_OBJECT (encoder, "Calculated DTS offset %" GST_TIME_FORMAT,
1981             GST_TIME_ARGS (encoder->dts_offset));
1982 
1983         encoder->first_frame->dts =
1984             gst_svthevc_encoder_get_oldest_pts (GST_VIDEO_ENCODER (encoder));
1985         if (GST_CLOCK_TIME_IS_VALID (encoder->first_frame->dts))
1986           encoder->first_frame->dts -= encoder->dts_offset;
1987 
1988         GST_LOG_OBJECT (encoder,
1989             "output: frame dts %" GST_TIME_FORMAT " pts %" GST_TIME_FORMAT,
1990             GST_TIME_ARGS (encoder->first_frame->dts),
1991             GST_TIME_ARGS (encoder->first_frame->pts));
1992 
1993         ret =
1994             gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (encoder),
1995             encoder->first_frame);
1996         encoder->first_frame = NULL;
1997       } else {
1998         encoder->first_frame = frame;
1999         frame = NULL;
2000         goto out;
2001       }
2002     }
2003 
2004     frame->dts =
2005         gst_svthevc_encoder_get_oldest_pts (GST_VIDEO_ENCODER (encoder));
2006     if (GST_CLOCK_TIME_IS_VALID (frame->dts))
2007       frame->dts -= encoder->dts_offset;
2008   }
2009 
2010   GST_LOG_OBJECT (encoder,
2011       "output: frame dts %" GST_TIME_FORMAT " pts %" GST_TIME_FORMAT,
2012       GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->pts));
2013 
2014 out:
2015   if (output_buffer->nFlags == EB_BUFFERFLAG_EOS)
2016     encoder->svt_eos_flag = EOS_TOTRIGGER;
2017 
2018   if (output_buffer)
2019     EbH265ReleaseOutBuffer (&output_buffer);
2020 
2021   if (frame)
2022     ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (encoder), frame);
2023 
2024   return ret;
2025 }
2026 
2027 static GstFlowReturn
gst_svthevc_enc_drain_encoder(GstSvtHevcEnc * encoder,gboolean send)2028 gst_svthevc_enc_drain_encoder (GstSvtHevcEnc * encoder, gboolean send)
2029 {
2030   GstFlowReturn ret = GST_FLOW_OK;
2031   gboolean got_packet;
2032 
2033   /* first send the remaining frames */
2034 
2035   if (G_UNLIKELY (encoder->svt_handle == NULL) ||
2036       G_UNLIKELY (encoder->svt_eos_flag == EOS_TOTRIGGER))
2037     goto done;
2038 
2039   ret = gst_svthevc_enc_send_frame (encoder, NULL);
2040 
2041   if (ret != GST_FLOW_OK)
2042     goto done;
2043 
2044   do {
2045     ret = gst_svthevc_enc_receive_frame (encoder, &got_packet, send);
2046     GST_LOG_OBJECT (encoder, "ret %d, got_packet %d", ret, got_packet);
2047     if (ret != GST_FLOW_OK)
2048       break;
2049   } while (got_packet);
2050 
2051 done:
2052   if (encoder->first_frame) {
2053     GST_LOG_OBJECT (encoder,
2054         "output: frame dts %" GST_TIME_FORMAT " pts %" GST_TIME_FORMAT,
2055         GST_TIME_ARGS (encoder->first_frame->dts),
2056         GST_TIME_ARGS (encoder->first_frame->pts));
2057     gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (encoder),
2058         encoder->first_frame);
2059     encoder->first_frame = NULL;
2060   }
2061 
2062   return ret;
2063 }
2064 
2065 static void
gst_svthevc_enc_reconfig(GstSvtHevcEnc * encoder)2066 gst_svthevc_enc_reconfig (GstSvtHevcEnc * encoder)
2067 {
2068   encoder->reconfig = TRUE;
2069 }
2070 
2071 static void
gst_svthevc_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2072 gst_svthevc_enc_set_property (GObject * object, guint prop_id,
2073     const GValue * value, GParamSpec * pspec)
2074 {
2075   GstSvtHevcEnc *encoder;
2076   GstState state;
2077 
2078   encoder = GST_SVTHEVC_ENC (object);
2079 
2080   GST_OBJECT_LOCK (encoder);
2081 
2082   state = GST_STATE (encoder);
2083   if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
2084       !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
2085     goto wrong_state;
2086 
2087   switch (prop_id) {
2088     case PROP_INSERT_VUI:
2089       encoder->insert_vui = g_value_get_boolean (value);
2090       break;
2091     case PROP_AUD:
2092       encoder->aud = g_value_get_boolean (value);
2093       break;
2094     case PROP_HIERARCHICAL_LEVEL:
2095       encoder->hierarchical_level = g_value_get_enum (value);
2096       break;
2097     case PROP_LOOKAHEAD_DISTANCE:
2098       encoder->la_depth = g_value_get_uint (value);
2099       break;
2100     case PROP_ENCODER_MODE:
2101       encoder->enc_mode = g_value_get_uint (value);
2102       break;
2103     case PROP_RC_MODE:
2104       encoder->rc_mode = g_value_get_enum (value);
2105       break;
2106     case PROP_QP_I:
2107       encoder->qp_i = g_value_get_uint (value);
2108       break;
2109     case PROP_QP_MAX:
2110       encoder->qp_max = g_value_get_uint (value);
2111       break;
2112     case PROP_QP_MIN:
2113       encoder->qp_min = g_value_get_uint (value);
2114       break;
2115     case PROP_SCENE_CHANGE_DETECTION:
2116       encoder->scene_change_detection = g_value_get_boolean (value);
2117       break;
2118     case PROP_TUNE:
2119       encoder->tune = g_value_get_enum (value);
2120       break;
2121     case PROP_BASE_LAYER_SWITCH_MODE:
2122       encoder->base_layer_switch_mode = g_value_get_enum (value);
2123       break;
2124     case PROP_BITRATE:
2125       encoder->bitrate = g_value_get_uint (value);
2126       break;
2127     case PROP_KEY_INT_MAX:
2128       encoder->keyintmax = g_value_get_int (value);
2129       break;
2130     case PROP_ENABLE_OPEN_GOP:
2131       encoder->enable_open_gop = g_value_get_boolean (value);
2132       break;
2133     case PROP_CONFIG_INTERVAL:
2134       encoder->config_interval = g_value_get_uint (value);
2135       break;
2136     case PROP_CORES:
2137       encoder->cores = g_value_get_uint (value);
2138       break;
2139     case PROP_SOCKET:
2140       encoder->socket = g_value_get_int (value);
2141       break;
2142     case PROP_TILE_ROW:
2143       encoder->tile_row = g_value_get_uint (value);
2144       break;
2145     case PROP_TILE_COL:
2146       encoder->tile_col = g_value_get_uint (value);
2147       break;
2148     case PROP_PRED_STRUCTURE:
2149       encoder->pred_structure = g_value_get_enum (value);
2150       break;
2151     case PROP_VBV_MAX_RATE:
2152       encoder->vbv_maxrate = g_value_get_uint (value);
2153       break;
2154     case PROP_VBV_BUFFER_SIZE:
2155       encoder->vbv_bufsize = g_value_get_uint (value);
2156       break;
2157     default:
2158       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2159       break;
2160   }
2161 
2162   gst_svthevc_enc_reconfig (encoder);
2163   GST_OBJECT_UNLOCK (encoder);
2164   return;
2165 
2166 wrong_state:
2167   {
2168     GST_WARNING_OBJECT (encoder, "setting property in wrong state");
2169     GST_OBJECT_UNLOCK (encoder);
2170   }
2171 }
2172 
2173 static void
gst_svthevc_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2174 gst_svthevc_enc_get_property (GObject * object, guint prop_id,
2175     GValue * value, GParamSpec * pspec)
2176 {
2177   GstSvtHevcEnc *encoder;
2178 
2179   encoder = GST_SVTHEVC_ENC (object);
2180 
2181   GST_OBJECT_LOCK (encoder);
2182   switch (prop_id) {
2183     case PROP_INSERT_VUI:
2184       g_value_set_boolean (value, encoder->insert_vui);
2185       break;
2186     case PROP_AUD:
2187       g_value_set_boolean (value, encoder->aud);
2188       break;
2189     case PROP_HIERARCHICAL_LEVEL:
2190       g_value_set_enum (value, encoder->hierarchical_level);
2191       break;
2192     case PROP_LOOKAHEAD_DISTANCE:
2193       g_value_set_uint (value, encoder->la_depth);
2194       break;
2195     case PROP_ENCODER_MODE:
2196       g_value_set_uint (value, encoder->enc_mode);
2197       break;
2198     case PROP_RC_MODE:
2199       g_value_set_enum (value, encoder->rc_mode);
2200       break;
2201     case PROP_QP_I:
2202       g_value_set_uint (value, encoder->qp_i);
2203       break;
2204     case PROP_QP_MAX:
2205       g_value_set_uint (value, encoder->qp_max);
2206       break;
2207     case PROP_QP_MIN:
2208       g_value_set_uint (value, encoder->qp_min);
2209       break;
2210     case PROP_SCENE_CHANGE_DETECTION:
2211       g_value_set_boolean (value, encoder->scene_change_detection);
2212       break;
2213     case PROP_TUNE:
2214       g_value_set_enum (value, encoder->tune);
2215       break;
2216     case PROP_BASE_LAYER_SWITCH_MODE:
2217       g_value_set_enum (value, encoder->base_layer_switch_mode);
2218       break;
2219     case PROP_BITRATE:
2220       g_value_set_uint (value, encoder->bitrate);
2221       break;
2222     case PROP_KEY_INT_MAX:
2223       g_value_set_int (value, encoder->keyintmax);
2224       break;
2225     case PROP_ENABLE_OPEN_GOP:
2226       g_value_set_boolean (value, encoder->enable_open_gop);
2227       break;
2228     case PROP_CONFIG_INTERVAL:
2229       g_value_set_uint (value, encoder->config_interval);
2230       break;
2231     case PROP_CORES:
2232       g_value_set_uint (value, encoder->cores);
2233       break;
2234     case PROP_SOCKET:
2235       g_value_set_int (value, encoder->socket);
2236       break;
2237     case PROP_TILE_ROW:
2238       g_value_set_uint (value, encoder->tile_row);
2239       break;
2240     case PROP_TILE_COL:
2241       g_value_set_uint (value, encoder->tile_col);
2242       break;
2243     case PROP_PRED_STRUCTURE:
2244       g_value_set_enum (value, encoder->pred_structure);
2245       break;
2246     case PROP_VBV_MAX_RATE:
2247       g_value_set_uint (value, encoder->vbv_maxrate);
2248       break;
2249     case PROP_VBV_BUFFER_SIZE:
2250       g_value_set_uint (value, encoder->vbv_bufsize);
2251       break;
2252     default:
2253       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2254       break;
2255   }
2256   GST_OBJECT_UNLOCK (encoder);
2257 }
2258 
2259 static gboolean
plugin_init(GstPlugin * plugin)2260 plugin_init (GstPlugin * plugin)
2261 {
2262   GST_DEBUG_CATEGORY_INIT (svthevc_enc_debug, "svthevcenc", 0,
2263       "h265 encoding element");
2264 
2265   return gst_element_register (plugin, "svthevcenc",
2266       GST_RANK_PRIMARY, GST_TYPE_SVTHEVC_ENC);
2267 }
2268 
2269 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2270     GST_VERSION_MINOR,
2271     svthevcenc,
2272     "svt-hevc encoder based H265 plugins",
2273     plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
2274