2 * Copyright (c) 2014, Ericsson AB. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or other
12 * materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 #include "gstopenh264elements.h"
31 #include "gstopenh264enc.h"
33 #include <gst/pbutils/pbutils.h>
35 #include <gst/base/base.h>
36 #include <gst/video/video.h>
37 #include <gst/video/gstvideoencoder.h>
40 GST_DEBUG_CATEGORY_STATIC (gst_openh264enc_debug_category);
41 #define GST_CAT_DEFAULT gst_openh264enc_debug_category
43 /* FIXME: we should not really directly use the enums from the openh264 API
44 * here, since it might change or be removed */
45 #define GST_TYPE_USAGE_TYPE (gst_openh264enc_usage_type_get_type ())
47 gst_openh264enc_usage_type_get_type (void)
49 static GType usage_type = 0;
52 static const GEnumValue usage_types[] = {
53 {CAMERA_VIDEO_REAL_TIME, "video from camera", "camera"},
54 {SCREEN_CONTENT_REAL_TIME, "screen content", "screen"},
58 usage_type = g_enum_register_static ("EUsageType", usage_types);
64 #define GST_TYPE_RC_MODES (gst_openh264enc_rc_modes_get_type ())
66 gst_openh264enc_rc_modes_get_type (void)
68 static GType rc_modes_type = 0;
71 static const GEnumValue rc_modes_types[] = {
72 {RC_QUALITY_MODE, "Quality mode", "quality"},
73 {RC_BITRATE_MODE, "Bitrate mode", "bitrate"},
74 {RC_BUFFERBASED_MODE, "No bitrate control, just using buffer status",
76 {RC_OFF_MODE, "Rate control off mode", "off"},
80 rc_modes_type = g_enum_register_static ("RC_MODES", rc_modes_types);
86 #define GST_TYPE_OPENH264ENC_DEBLOCKING_MODE (gst_openh264enc_deblocking_mode_get_type ())
88 gst_openh264enc_deblocking_mode_get_type (void)
90 static const GEnumValue types[] = {
91 {GST_OPENH264_DEBLOCKING_ON, "Deblocking on", "on"},
92 {GST_OPENH264_DEBLOCKING_OFF, "Deblocking off", "off"},
93 {GST_OPENH264_DEBLOCKING_NOT_SLICE_BOUNDARIES,
94 "Deblocking on, except for slice boundaries", "not-slice-boundaries"},
99 if (g_once_init_enter (&id)) {
100 GType _id = g_enum_register_static ("GstOpenh264encDeblockingModes", types);
101 g_once_init_leave (&id, _id);
107 #define GST_TYPE_OPENH264ENC_SLICE_MODE (gst_openh264enc_slice_mode_get_type ())
109 gst_openh264enc_slice_mode_get_type (void)
111 static const GEnumValue types[] = {
112 {GST_OPENH264_SLICE_MODE_N_SLICES, "Fixed number of slices", "n-slices"},
113 {GST_OPENH264_SLICE_MODE_AUTO,
114 "Number of slices equal to number of threads", "auto"},
119 if (g_once_init_enter (&id)) {
120 GType _id = g_enum_register_static ("GstOpenh264EncSliceModes", types);
121 g_once_init_leave (&id, _id);
127 #define GST_TYPE_OPENH264ENC_COMPLEXITY (gst_openh264enc_complexity_get_type ())
129 gst_openh264enc_complexity_get_type (void)
131 static const GEnumValue types[] = {
132 {LOW_COMPLEXITY, "Low complexity / high speed encoding", "low"},
133 {MEDIUM_COMPLEXITY, "Medium complexity / medium speed encoding", "medium"},
134 {HIGH_COMPLEXITY, "High complexity / low speed encoding", "high"},
139 if (g_once_init_enter (&id)) {
140 GType _id = g_enum_register_static ("GstOpenh264encComplexity", types);
141 g_once_init_leave (&id, _id);
149 static void gst_openh264enc_set_property (GObject * object,
150 guint property_id, const GValue * value, GParamSpec * pspec);
151 static void gst_openh264enc_get_property (GObject * object,
152 guint property_id, GValue * value, GParamSpec * pspec);
153 static void gst_openh264enc_finalize (GObject * object);
154 static gboolean gst_openh264enc_start (GstVideoEncoder * encoder);
155 static gboolean gst_openh264enc_stop (GstVideoEncoder * encoder);
156 static gboolean gst_openh264enc_set_format (GstVideoEncoder * encoder,
157 GstVideoCodecState * state);
158 static GstFlowReturn gst_openh264enc_handle_frame (GstVideoEncoder * encoder,
159 GstVideoCodecFrame * frame);
160 static GstFlowReturn gst_openh264enc_finish (GstVideoEncoder * encoder);
161 static gboolean gst_openh264enc_propose_allocation (GstVideoEncoder * encoder,
163 static void gst_openh264enc_set_usage_type (GstOpenh264Enc * openh264enc,
165 static void gst_openh264enc_set_rate_control (GstOpenh264Enc * openh264enc,
167 static gboolean openh264enc_element_init (GstPlugin * plugin);
170 #define DEFAULT_BITRATE (128000)
171 #define DEFAULT_MAX_BITRATE (UNSPECIFIED_BIT_RATE)
172 #define DEFAULT_GOP_SIZE (90)
173 #define DEFAULT_MAX_SLICE_SIZE (1500000)
174 #define START_FRAMERATE 30
175 #define DEFAULT_USAGE_TYPE CAMERA_VIDEO_REAL_TIME
176 #define DEFAULT_RATE_CONTROL RC_QUALITY_MODE
177 #define DEFAULT_MULTI_THREAD 0
178 #define DEFAULT_ENABLE_DENOISE FALSE
179 #define DEFAULT_ENABLE_FRAME_SKIP FALSE
180 #define DEFAULT_DEBLOCKING_MODE GST_OPENH264_DEBLOCKING_ON
181 #define DEFAULT_BACKGROUND_DETECTION TRUE
182 #define DEFAULT_ADAPTIVE_QUANTIZATION TRUE
183 #define DEFAULT_SCENE_CHANGE_DETECTION TRUE
184 #define DEFAULT_SLICE_MODE GST_OPENH264_SLICE_MODE_N_SLICES
185 #define DEFAULT_NUM_SLICES 1
186 #define DEFAULT_COMPLEXITY MEDIUM_COMPLEXITY
187 #define DEFAULT_QP_MIN 0
188 #define DEFAULT_QP_MAX 51
201 PROP_ENABLE_FRAME_SKIP,
202 PROP_DEBLOCKING_MODE,
203 PROP_BACKGROUND_DETECTION,
204 PROP_ADAPTIVE_QUANTIZATION,
205 PROP_SCENE_CHANGE_DETECTION,
216 static GstStaticPadTemplate gst_openh264enc_sink_template =
217 GST_STATIC_PAD_TEMPLATE ("sink",
220 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
223 static GstStaticPadTemplate gst_openh264enc_src_template =
224 GST_STATIC_PAD_TEMPLATE ("src",
229 "stream-format=(string)\"byte-stream\", alignment=(string)\"au\","
230 "profile = (string) { constrained-baseline, baseline, main, constrained-high, high }"
234 /* class initialization */
236 G_DEFINE_TYPE_WITH_CODE (GstOpenh264Enc, gst_openh264enc,
237 GST_TYPE_VIDEO_ENCODER,
238 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL);
239 GST_DEBUG_CATEGORY_INIT (gst_openh264enc_debug_category, "openh264enc", 0,
240 "debug category for openh264enc element"));
241 GST_ELEMENT_REGISTER_DEFINE_CUSTOM (openh264enc, openh264enc_element_init);
244 gst_openh264enc_class_init (GstOpenh264EncClass * klass)
246 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
247 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
249 /* Setting up pads and setting metadata should be moved to
250 base_class_init if you intend to subclass this class. */
251 gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
252 &gst_openh264enc_src_template);
253 gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
254 &gst_openh264enc_sink_template);
256 gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
257 "OpenH264 video encoder", "Encoder/Video", "OpenH264 video encoder",
258 "Ericsson AB, http://www.ericsson.com");
260 gobject_class->set_property = gst_openh264enc_set_property;
261 gobject_class->get_property = gst_openh264enc_get_property;
262 gobject_class->finalize = gst_openh264enc_finalize;
263 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_openh264enc_start);
264 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_openh264enc_stop);
265 video_encoder_class->set_format =
266 GST_DEBUG_FUNCPTR (gst_openh264enc_set_format);
267 video_encoder_class->handle_frame =
268 GST_DEBUG_FUNCPTR (gst_openh264enc_handle_frame);
269 video_encoder_class->propose_allocation =
270 GST_DEBUG_FUNCPTR (gst_openh264enc_propose_allocation);
271 video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_openh264enc_finish);
273 /* define properties */
274 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_USAGE_TYPE,
275 g_param_spec_enum ("usage-type", "Usage type",
276 "Type of video content",
277 GST_TYPE_USAGE_TYPE, CAMERA_VIDEO_REAL_TIME,
278 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
280 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RATE_CONTROL,
281 g_param_spec_enum ("rate-control", "Rate control",
283 GST_TYPE_RC_MODES, RC_QUALITY_MODE,
284 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
286 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MULTI_THREAD,
287 g_param_spec_uint ("multi-thread", "Number of threads",
288 "The number of threads.",
289 0, G_MAXUINT, DEFAULT_MULTI_THREAD,
290 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
292 g_object_class_install_property (gobject_class, PROP_ENABLE_DENOISE,
293 g_param_spec_boolean ("enable-denoise", "Denoise Control",
295 FALSE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
297 g_object_class_install_property (gobject_class, PROP_ENABLE_FRAME_SKIP,
298 g_param_spec_boolean ("enable-frame-skip", "Skip Frames",
299 "Skip frames to reach target bitrate",
300 FALSE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
302 g_object_class_install_property (gobject_class, PROP_BITRATE,
303 g_param_spec_uint ("bitrate", "Bitrate",
304 "Bitrate (in bits per second)",
305 0, G_MAXUINT, DEFAULT_BITRATE,
306 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
307 GST_PARAM_MUTABLE_PLAYING)));
309 g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
310 g_param_spec_uint ("max-bitrate", "Max Bitrate",
311 "Maximum Bitrate (in bits per second)",
312 0, G_MAXUINT, DEFAULT_MAX_BITRATE,
313 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
314 GST_PARAM_MUTABLE_PLAYING)));
316 g_object_class_install_property (gobject_class, PROP_QP_MIN,
317 g_param_spec_uint ("qp-min", "Minimum Quantizer",
318 "Minimum quantizer", 0, 51, DEFAULT_QP_MIN,
319 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
321 g_object_class_install_property (gobject_class, PROP_QP_MAX,
322 g_param_spec_uint ("qp-max", "Maximum Quantizer",
323 "Maximum quantizer", 0, 51, DEFAULT_QP_MAX,
324 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
326 g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
327 g_param_spec_uint ("gop-size", "GOP size",
328 "Number of frames between intra frames",
329 0, G_MAXUINT, DEFAULT_GOP_SIZE,
330 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
332 g_object_class_install_property (gobject_class, PROP_MAX_SLICE_SIZE,
333 g_param_spec_uint ("max-slice-size", "Max slice size",
334 "The maximum size of one slice (in bytes).",
335 0, G_MAXUINT, DEFAULT_MAX_SLICE_SIZE,
336 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
338 g_object_class_install_property (G_OBJECT_CLASS (klass),
339 PROP_DEBLOCKING_MODE, g_param_spec_enum ("deblocking",
340 "Deblocking mode", "Deblocking mode",
341 GST_TYPE_OPENH264ENC_DEBLOCKING_MODE, DEFAULT_DEBLOCKING_MODE,
342 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
344 g_object_class_install_property (gobject_class, PROP_BACKGROUND_DETECTION,
345 g_param_spec_boolean ("background-detection", "Background detection",
346 "Background detection", DEFAULT_BACKGROUND_DETECTION,
347 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
349 g_object_class_install_property (gobject_class, PROP_ADAPTIVE_QUANTIZATION,
350 g_param_spec_boolean ("adaptive-quantization", "Adaptive quantization",
351 "Adaptive quantization", DEFAULT_ADAPTIVE_QUANTIZATION,
352 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
354 g_object_class_install_property (gobject_class, PROP_SCENE_CHANGE_DETECTION,
355 g_param_spec_boolean ("scene-change-detection",
356 "Scene change detection", "Scene change detection",
357 DEFAULT_SCENE_CHANGE_DETECTION,
358 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
360 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLICE_MODE,
361 g_param_spec_enum ("slice-mode", "Slice mode", "Slice mode",
362 GST_TYPE_OPENH264ENC_SLICE_MODE, DEFAULT_SLICE_MODE,
363 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
365 g_object_class_install_property (gobject_class, PROP_NUM_SLICES,
366 g_param_spec_uint ("num-slices", "Number of slices",
367 "The number of slices (needs slice-mode=n-slices)",
368 0, G_MAXUINT, DEFAULT_NUM_SLICES,
369 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
371 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
372 g_param_spec_enum ("complexity", "Complexity / quality / speed tradeoff",
373 "Complexity", GST_TYPE_OPENH264ENC_COMPLEXITY, DEFAULT_COMPLEXITY,
374 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
376 gst_type_mark_as_plugin_api (GST_TYPE_OPENH264ENC_COMPLEXITY, (GstPluginAPIFlags) 0);
377 gst_type_mark_as_plugin_api (GST_TYPE_OPENH264ENC_DEBLOCKING_MODE, (GstPluginAPIFlags) 0);
378 gst_type_mark_as_plugin_api (GST_TYPE_OPENH264ENC_SLICE_MODE, (GstPluginAPIFlags) 0);
379 gst_type_mark_as_plugin_api (GST_TYPE_RC_MODES, (GstPluginAPIFlags) 0);
380 gst_type_mark_as_plugin_api (GST_TYPE_USAGE_TYPE, (GstPluginAPIFlags) 0);
384 gst_openh264enc_init (GstOpenh264Enc * openh264enc)
386 openh264enc->gop_size = DEFAULT_GOP_SIZE;
387 openh264enc->usage_type = DEFAULT_USAGE_TYPE;
388 openh264enc->rate_control = DEFAULT_RATE_CONTROL;
389 openh264enc->multi_thread = DEFAULT_MULTI_THREAD;
390 openh264enc->max_slice_size = DEFAULT_MAX_SLICE_SIZE;
391 openh264enc->bitrate = DEFAULT_BITRATE;
392 openh264enc->max_bitrate = DEFAULT_MAX_BITRATE;
393 openh264enc->qp_min = DEFAULT_QP_MIN;
394 openh264enc->qp_max = DEFAULT_QP_MAX;
395 openh264enc->framerate = START_FRAMERATE;
396 openh264enc->input_state = NULL;
397 openh264enc->time_per_frame = GST_SECOND / openh264enc->framerate;
398 openh264enc->frame_count = 0;
399 openh264enc->previous_timestamp = 0;
400 openh264enc->enable_denoise = DEFAULT_ENABLE_DENOISE;
401 openh264enc->enable_frame_skip = DEFAULT_ENABLE_FRAME_SKIP;
402 openh264enc->deblocking_mode = DEFAULT_DEBLOCKING_MODE;
403 openh264enc->background_detection = DEFAULT_BACKGROUND_DETECTION;
404 openh264enc->adaptive_quantization = DEFAULT_ADAPTIVE_QUANTIZATION;
405 openh264enc->scene_change_detection = DEFAULT_SCENE_CHANGE_DETECTION;
406 openh264enc->slice_mode = DEFAULT_SLICE_MODE;
407 openh264enc->num_slices = DEFAULT_NUM_SLICES;
408 openh264enc->encoder = NULL;
409 openh264enc->complexity = DEFAULT_COMPLEXITY;
410 openh264enc->bitrate_changed = FALSE;
411 openh264enc->max_bitrate_changed = FALSE;
412 gst_openh264enc_set_usage_type (openh264enc, CAMERA_VIDEO_REAL_TIME);
413 gst_openh264enc_set_rate_control (openh264enc, RC_QUALITY_MODE);
417 gst_openh264enc_set_usage_type (GstOpenh264Enc * openh264enc, gint usage_type)
419 switch (usage_type) {
420 case CAMERA_VIDEO_REAL_TIME:
421 openh264enc->usage_type = CAMERA_VIDEO_REAL_TIME;
423 case SCREEN_CONTENT_REAL_TIME:
424 openh264enc->usage_type = SCREEN_CONTENT_REAL_TIME;
427 g_assert_not_reached ();
432 gst_openh264enc_set_rate_control (GstOpenh264Enc * openh264enc, gint rc_mode)
435 case RC_QUALITY_MODE:
436 openh264enc->rate_control = RC_QUALITY_MODE;
438 case RC_BITRATE_MODE:
439 openh264enc->rate_control = RC_BITRATE_MODE;
441 case RC_BUFFERBASED_MODE:
442 openh264enc->rate_control = RC_BUFFERBASED_MODE;
445 openh264enc->rate_control = RC_OFF_MODE;
448 g_assert_not_reached ();
453 gst_openh264enc_set_property (GObject * object, guint property_id,
454 const GValue * value, GParamSpec * pspec)
456 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
458 GST_DEBUG_OBJECT (openh264enc, "set_property");
460 switch (property_id) {
462 GST_OBJECT_LOCK (openh264enc);
463 if (openh264enc->bitrate != g_value_get_uint (value)) {
464 openh264enc->bitrate = g_value_get_uint (value);
465 openh264enc->bitrate_changed = TRUE;
467 GST_OBJECT_UNLOCK (openh264enc);
470 case PROP_MAX_BITRATE:
471 GST_OBJECT_LOCK (openh264enc);
472 if (openh264enc->max_bitrate != g_value_get_uint (value)) {
473 openh264enc->max_bitrate = g_value_get_uint (value);
474 openh264enc->max_bitrate_changed = TRUE;
476 GST_OBJECT_UNLOCK (openh264enc);
480 openh264enc->qp_min = g_value_get_uint (value);
484 openh264enc->qp_max = g_value_get_uint (value);
487 case PROP_MULTI_THREAD:
488 openh264enc->multi_thread = g_value_get_uint (value);
491 case PROP_USAGE_TYPE:
492 gst_openh264enc_set_usage_type (openh264enc, g_value_get_enum (value));
495 case PROP_ENABLE_DENOISE:
496 openh264enc->enable_denoise = g_value_get_boolean (value);
499 case PROP_ENABLE_FRAME_SKIP:
500 openh264enc->enable_frame_skip = g_value_get_boolean (value);
503 case PROP_RATE_CONTROL:
504 gst_openh264enc_set_rate_control (openh264enc, g_value_get_enum (value));
508 openh264enc->gop_size = g_value_get_uint (value);
511 case PROP_MAX_SLICE_SIZE:
512 openh264enc->max_slice_size = g_value_get_uint (value);
515 case PROP_DEBLOCKING_MODE:
516 openh264enc->deblocking_mode =
517 (GstOpenh264encDeblockingMode) g_value_get_enum (value);
520 case PROP_BACKGROUND_DETECTION:
521 openh264enc->background_detection = g_value_get_boolean (value);
524 case PROP_ADAPTIVE_QUANTIZATION:
525 openh264enc->adaptive_quantization = g_value_get_boolean (value);
528 case PROP_SCENE_CHANGE_DETECTION:
529 openh264enc->scene_change_detection = g_value_get_boolean (value);
532 case PROP_SLICE_MODE:
533 openh264enc->slice_mode =
534 (GstOpenh264EncSliceMode) g_value_get_enum (value);
537 case PROP_NUM_SLICES:
538 openh264enc->num_slices = g_value_get_uint (value);
541 case PROP_COMPLEXITY:
542 openh264enc->complexity = (ECOMPLEXITY_MODE) g_value_get_enum (value);
546 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
552 gst_openh264enc_get_property (GObject * object, guint property_id,
553 GValue * value, GParamSpec * pspec)
555 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
557 GST_DEBUG_OBJECT (openh264enc, "get_property");
559 switch (property_id) {
560 case PROP_USAGE_TYPE:
561 g_value_set_enum (value, openh264enc->usage_type);
564 case PROP_RATE_CONTROL:
565 g_value_set_enum (value, openh264enc->rate_control);
569 g_value_set_uint (value, openh264enc->bitrate);
572 case PROP_MAX_BITRATE:
573 g_value_set_uint (value, openh264enc->max_bitrate);
577 g_value_set_uint (value, openh264enc->qp_min);
581 g_value_set_uint (value, openh264enc->qp_max);
584 case PROP_ENABLE_DENOISE:
585 g_value_set_boolean (value, openh264enc->enable_denoise);
588 case PROP_ENABLE_FRAME_SKIP:
589 g_value_set_boolean (value, openh264enc->enable_frame_skip);
592 case PROP_MULTI_THREAD:
593 g_value_set_uint (value, openh264enc->multi_thread);
597 g_value_set_uint (value, openh264enc->gop_size);
600 case PROP_MAX_SLICE_SIZE:
601 g_value_set_uint (value, openh264enc->max_slice_size);
604 case PROP_DEBLOCKING_MODE:
605 g_value_set_enum (value, openh264enc->deblocking_mode);
608 case PROP_BACKGROUND_DETECTION:
609 g_value_set_boolean (value, openh264enc->background_detection);
612 case PROP_ADAPTIVE_QUANTIZATION:
613 g_value_set_boolean (value, openh264enc->adaptive_quantization);
616 case PROP_SCENE_CHANGE_DETECTION:
617 g_value_set_boolean (value, openh264enc->scene_change_detection);
620 case PROP_SLICE_MODE:
621 g_value_set_enum (value, openh264enc->slice_mode);
624 case PROP_NUM_SLICES:
625 g_value_set_uint (value, openh264enc->num_slices);
628 case PROP_COMPLEXITY:
629 g_value_set_enum (value, openh264enc->complexity);
633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
639 gst_openh264enc_finalize (GObject * object)
641 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
643 GST_DEBUG_OBJECT (openh264enc, "finalize");
645 /* clean up object here */
647 if (openh264enc->input_state) {
648 gst_video_codec_state_unref (openh264enc->input_state);
650 openh264enc->input_state = NULL;
652 G_OBJECT_CLASS (gst_openh264enc_parent_class)->finalize (object);
656 gst_openh264enc_start (GstVideoEncoder * encoder)
658 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
659 GST_DEBUG_OBJECT (openh264enc, "start");
665 gst_openh264enc_stop (GstVideoEncoder * encoder)
667 GstOpenh264Enc *openh264enc;
669 openh264enc = GST_OPENH264ENC (encoder);
671 if (openh264enc->encoder != NULL) {
672 openh264enc->encoder->Uninitialize ();
673 WelsDestroySVCEncoder (openh264enc->encoder);
674 openh264enc->encoder = NULL;
676 openh264enc->encoder = NULL;
678 if (openh264enc->input_state) {
679 gst_video_codec_state_unref (openh264enc->input_state);
681 openh264enc->input_state = NULL;
683 GST_DEBUG_OBJECT (openh264enc, "openh264_enc_stop called");
689 gst_openh264enc_get_level_from_caps (GstCaps *outcaps, GstCaps *allowed_caps)
691 GstStructure *s = gst_caps_get_structure (outcaps, 0);
692 const gchar * level = gst_structure_get_string (gst_caps_get_structure (allowed_caps, 0), "level");
695 return LEVEL_UNKNOWN;
697 gst_structure_set (s, "level", G_TYPE_STRING, level, NULL);
698 return gst_codec_utils_h264_get_level_idc (level);
702 gst_openh264enc_get_profile_from_caps (GstCaps *outcaps, GstCaps *allowed_caps)
704 EProfileIdc oh264_profile = PRO_BASELINE;
705 GstStructure *allowed_s = gst_caps_get_structure (allowed_caps, 0);
706 GstStructure *s = gst_caps_get_structure (outcaps, 0);
707 const gchar *profile = gst_structure_get_string (allowed_s, "profile");
710 return oh264_profile;
712 gst_structure_set (s, "profile", G_TYPE_STRING, profile, NULL);
713 if (!g_strcmp0 (profile, "constrained-baseline") ||
714 !g_strcmp0 (profile, "baseline"))
716 else if (!g_strcmp0 (profile, "main"))
718 else if (!g_strcmp0 (profile, "high") ||
719 !g_strcmp0 (profile, "constrained-high"))
722 g_assert_not_reached ();
727 gst_openh264enc_set_format (GstVideoEncoder * encoder,
728 GstVideoCodecState * state)
730 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
732 guint width, height, fps_n, fps_d;
733 SEncParamExt enc_params;
734 SliceModeEnum slice_mode = SM_SINGLE_SLICE;
738 GstVideoCodecState *output_state;
739 openh264enc->frame_count = 0;
740 int video_format = videoFormatI420;
741 GstCaps *allowed_caps = NULL;
743 debug_caps = gst_caps_to_string (state->caps);
744 GST_DEBUG_OBJECT (openh264enc, "gst_e26d4_enc_set_format called, caps: %s",
748 gst_openh264enc_stop (encoder);
750 if (openh264enc->input_state) {
751 gst_video_codec_state_unref (openh264enc->input_state);
753 openh264enc->input_state = gst_video_codec_state_ref (state);
755 width = GST_VIDEO_INFO_WIDTH (&state->info);
756 height = GST_VIDEO_INFO_HEIGHT (&state->info);
757 fps_n = GST_VIDEO_INFO_FPS_N (&state->info);
758 fps_d = GST_VIDEO_INFO_FPS_D (&state->info);
760 if (openh264enc->encoder != NULL) {
761 openh264enc->encoder->Uninitialize ();
762 WelsDestroySVCEncoder (openh264enc->encoder);
763 openh264enc->encoder = NULL;
765 WelsCreateSVCEncoder (&openh264enc->encoder);
766 unsigned int uiTraceLevel = WELS_LOG_ERROR;
767 openh264enc->encoder->SetOption (ENCODER_OPTION_TRACE_LEVEL, &uiTraceLevel);
769 outcaps = gst_static_pad_template_get_caps (&gst_openh264enc_src_template);
770 outcaps = gst_caps_make_writable (outcaps);
771 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
772 allowed_caps = gst_caps_make_writable (allowed_caps);
773 allowed_caps = gst_caps_fixate (allowed_caps);
775 GST_OBJECT_LOCK (openh264enc);
777 openh264enc->encoder->GetDefaultParams (&enc_params);
779 enc_params.iUsageType = openh264enc->usage_type;
780 enc_params.iPicWidth = width;
781 enc_params.iPicHeight = height;
782 enc_params.iTargetBitrate = openh264enc->bitrate;
783 enc_params.iMaxBitrate = openh264enc->max_bitrate;
784 enc_params.iMaxQp = openh264enc->qp_max;
785 enc_params.iMinQp = openh264enc->qp_min;
786 enc_params.iRCMode = openh264enc->rate_control;
787 enc_params.iTemporalLayerNum = 1;
788 enc_params.iSpatialLayerNum = 1;
789 enc_params.iLtrMarkPeriod = 30;
790 enc_params.iMultipleThreadIdc = openh264enc->multi_thread;
791 enc_params.bEnableDenoise = openh264enc->enable_denoise;
792 enc_params.iComplexityMode = openh264enc->complexity;
793 enc_params.uiIntraPeriod = openh264enc->gop_size;
794 enc_params.bEnableBackgroundDetection = openh264enc->background_detection;
795 enc_params.bEnableAdaptiveQuant = openh264enc->adaptive_quantization;
796 enc_params.bEnableSceneChangeDetect = openh264enc->scene_change_detection;
797 enc_params.bEnableFrameSkip = openh264enc->enable_frame_skip;
798 enc_params.bEnableLongTermReference = 0;
799 #if (OPENH264_MAJOR > 1 || (OPENH264_MAJOR == 1 && OPENH264_MINOR >= 4))
800 enc_params.eSpsPpsIdStrategy = CONSTANT_ID;
802 enc_params.bEnableSpsPpsIdAddition = 0;
804 enc_params.bPrefixNalAddingCtrl = 0;
805 enc_params.fMaxFrameRate = fps_n * 1.0 / fps_d;
806 enc_params.iLoopFilterDisableIdc = openh264enc->deblocking_mode;
807 enc_params.sSpatialLayers[0].uiProfileIdc = gst_openh264enc_get_profile_from_caps (outcaps, allowed_caps);
808 enc_params.sSpatialLayers[0].uiLevelIdc = (ELevelIdc) gst_openh264enc_get_level_from_caps (outcaps, allowed_caps);
809 enc_params.sSpatialLayers[0].iVideoWidth = enc_params.iPicWidth;
810 enc_params.sSpatialLayers[0].iVideoHeight = enc_params.iPicHeight;
811 enc_params.sSpatialLayers[0].fFrameRate = fps_n * 1.0 / fps_d;
812 enc_params.sSpatialLayers[0].iSpatialBitrate = enc_params.iTargetBitrate;
813 enc_params.sSpatialLayers[0].iMaxSpatialBitrate = enc_params.iMaxBitrate;
815 gst_clear_caps (&allowed_caps);
817 if (openh264enc->slice_mode == GST_OPENH264_SLICE_MODE_N_SLICES) {
818 if (openh264enc->num_slices == 1)
819 slice_mode = SM_SINGLE_SLICE;
821 slice_mode = SM_FIXEDSLCNUM_SLICE;
822 n_slices = openh264enc->num_slices;
823 } else if (openh264enc->slice_mode == GST_OPENH264_SLICE_MODE_AUTO) {
824 #if OPENH264_MAJOR == 1 && OPENH264_MINOR < 6
825 slice_mode = SM_AUTO_SLICE;
827 slice_mode = SM_FIXEDSLCNUM_SLICE;
831 GST_ERROR_OBJECT (openh264enc, "unexpected slice mode %d",
832 openh264enc->slice_mode);
833 slice_mode = SM_SINGLE_SLICE;
836 #if OPENH264_MAJOR == 1 && OPENH264_MINOR < 6
837 enc_params.sSpatialLayers[0].sSliceCfg.uiSliceMode = slice_mode;
838 enc_params.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = n_slices;
840 enc_params.sSpatialLayers[0].sSliceArgument.uiSliceMode = slice_mode;
841 enc_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = n_slices;
844 openh264enc->framerate = (1 + fps_n / fps_d);
846 ret = openh264enc->encoder->InitializeExt (&enc_params);
848 openh264enc->bitrate_changed = FALSE;
849 openh264enc->max_bitrate_changed = FALSE;
851 GST_OBJECT_UNLOCK (openh264enc);
853 if (ret != cmResultSuccess) {
854 GST_ERROR_OBJECT (openh264enc, "failed to initialize encoder");
858 openh264enc->encoder->SetOption (ENCODER_OPTION_DATAFORMAT, &video_format);
860 output_state = gst_video_encoder_set_output_state (encoder, outcaps, state);
861 gst_video_codec_state_unref (output_state);
863 return gst_video_encoder_negotiate (encoder);
867 gst_openh264enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
869 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
872 GST_VIDEO_ENCODER_CLASS
873 (gst_openh264enc_parent_class)->propose_allocation (encoder, query);
877 gst_openh264enc_handle_frame (GstVideoEncoder * encoder,
878 GstVideoCodecFrame * frame)
880 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
881 SSourcePicture *src_pic = NULL;
882 GstVideoFrame video_frame;
883 gboolean force_keyframe;
885 SFrameBSInfo frame_info;
888 gsize buf_length = 0;
890 GST_OBJECT_LOCK (openh264enc);
892 if (openh264enc->bitrate_changed || openh264enc->max_bitrate_changed) {
893 SEncParamExt enc_params;
894 if (openh264enc->encoder->GetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
895 &enc_params) == cmResultSuccess) {
896 if (openh264enc->bitrate_changed) {
897 enc_params.iTargetBitrate = openh264enc->bitrate;
898 enc_params.sSpatialLayers[0].iSpatialBitrate =
899 enc_params.iTargetBitrate;
901 if (openh264enc->max_bitrate_changed) {
902 enc_params.iMaxBitrate = openh264enc->max_bitrate;
903 enc_params.sSpatialLayers[0].iMaxSpatialBitrate =
904 enc_params.iMaxBitrate;
906 if (openh264enc->encoder->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
907 &enc_params) != cmResultSuccess) {
908 GST_WARNING_OBJECT (openh264enc,
909 "Error changing bitrate/max bitrate, unable to set new enc_params");
912 GST_WARNING_OBJECT (openh264enc,
913 "Error changing bitrate/max bitrate, unable to get enc_params");
915 openh264enc->bitrate_changed = FALSE;
916 openh264enc->max_bitrate_changed = FALSE;
919 GST_OBJECT_UNLOCK (openh264enc);
922 src_pic = new SSourcePicture;
924 if (src_pic == NULL) {
926 gst_video_codec_frame_unref (frame);
927 return GST_FLOW_ERROR;
929 //fill default src_pic
930 src_pic->iColorFormat = videoFormatI420;
931 src_pic->uiTimeStamp = frame->pts / GST_MSECOND;
934 openh264enc->frame_count++;
936 if (G_UNLIKELY (openh264enc->frame_count == 1)) {
937 openh264enc->time_per_frame = (GST_SECOND / openh264enc->framerate);
938 openh264enc->previous_timestamp = frame->pts;
940 openh264enc->time_per_frame = (guint64)
941 (openh264enc->time_per_frame * 0.8 + (frame->pts -
942 openh264enc->previous_timestamp) * 0.2);
943 openh264enc->previous_timestamp = frame->pts;
944 if (openh264enc->frame_count % 10 == 0) {
945 fps = GST_SECOND / (gdouble) openh264enc->time_per_frame;
946 openh264enc->encoder->SetOption (ENCODER_OPTION_FRAME_RATE, &fps);
952 gst_video_frame_map (&video_frame, &openh264enc->input_state->info,
953 frame->input_buffer, GST_MAP_READ);
954 src_pic->iPicWidth = GST_VIDEO_FRAME_WIDTH (&video_frame);
955 src_pic->iPicHeight = GST_VIDEO_FRAME_HEIGHT (&video_frame);
956 src_pic->iStride[0] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 0);
957 src_pic->iStride[1] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 1);
958 src_pic->iStride[2] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 2);
959 src_pic->pData[0] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 0);
960 src_pic->pData[1] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 1);
961 src_pic->pData[2] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 2);
963 force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
964 if (force_keyframe) {
965 openh264enc->encoder->ForceIntraFrame (true);
966 GST_DEBUG_OBJECT (openh264enc,
967 "Got force key unit event, next frame coded as intra picture");
971 memset (&frame_info, 0, sizeof (SFrameBSInfo));
972 ret = openh264enc->encoder->EncodeFrame (src_pic, &frame_info);
973 if (ret != cmResultSuccess) {
975 gst_video_frame_unmap (&video_frame);
976 gst_video_codec_frame_unref (frame);
978 GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE,
979 ("Could not encode frame"), ("Openh264 returned %d", ret));
980 return GST_FLOW_ERROR;
986 if (videoFrameTypeSkip == frame_info.eFrameType) {
988 gst_video_frame_unmap (&video_frame);
989 gst_video_encoder_finish_frame (encoder, frame);
997 gst_video_frame_unmap (&video_frame);
998 gst_video_codec_frame_unref (frame);
1004 /* FIXME: openh264 has no way for us to get a connection
1005 * between the input and output frames, we just have to
1006 * guess based on the input */
1007 frame = gst_video_encoder_get_oldest_frame (encoder);
1009 GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE,
1010 ("Could not encode frame"), ("openh264enc returned %d", ret));
1011 gst_video_codec_frame_unref (frame);
1012 return GST_FLOW_ERROR;
1015 if (videoFrameTypeIDR == frame_info.eFrameType) {
1016 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1018 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
1021 for (i = 0; i < frame_info.iLayerNum; i++) {
1022 for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) {
1023 buf_length += frame_info.sLayerInfo[i].pNalLengthInByte[j];
1027 frame->output_buffer =
1028 gst_video_encoder_allocate_output_buffer (encoder, buf_length);
1032 for (i = 0; i < frame_info.iLayerNum; i++) {
1033 gsize layer_size = 0;
1034 for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) {
1035 layer_size += frame_info.sLayerInfo[i].pNalLengthInByte[j];
1037 gst_buffer_fill (frame->output_buffer, buf_length, frame_info.sLayerInfo[i].pBsBuf, layer_size);
1038 buf_length += layer_size;
1041 GST_LOG_OBJECT (openh264enc, "openh264 picture %scoded OK!",
1042 (ret != cmResultSuccess) ? "NOT " : "");
1044 return gst_video_encoder_finish_frame (encoder, frame);
1047 static GstFlowReturn
1048 gst_openh264enc_finish (GstVideoEncoder * encoder)
1050 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
1052 if (openh264enc->frame_count == 0)
1056 while ((gst_openh264enc_handle_frame (encoder, NULL)) == GST_FLOW_OK);
1061 openh264enc_element_init (GstPlugin * plugin)
1063 if (openh264_element_init (plugin))
1064 return gst_element_register (plugin, "openh264enc", GST_RANK_MARGINAL,
1065 GST_TYPE_OPENH264ENC);
1067 GST_ERROR ("Incorrect library version loaded, expecting %s", g_strCodecVer);