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, ¶ms);
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, ¶ms);
1547 else
1548 gst_query_add_allocation_param (query, allocator, ¶ms);
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, ¶ms);
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