1 /*
2 * Copyright (c) 2014, Ericsson AB. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
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.
13 *
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
23 * OF SUCH DAMAGE.
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "gstopenh264enc.h"
31
32 #include <gst/gst.h>
33 #include <gst/base/base.h>
34 #include <gst/video/video.h>
35 #include <gst/video/gstvideoencoder.h>
36 #include <string.h>
37
38 GST_DEBUG_CATEGORY_STATIC (gst_openh264enc_debug_category);
39 #define GST_CAT_DEFAULT gst_openh264enc_debug_category
40
41 /* FIXME: we should not really directly use the enums from the openh264 API
42 * here, since it might change or be removed */
43 #define GST_TYPE_USAGE_TYPE (gst_openh264enc_usage_type_get_type ())
44 static GType
gst_openh264enc_usage_type_get_type(void)45 gst_openh264enc_usage_type_get_type (void)
46 {
47 static GType usage_type = 0;
48
49 if (!usage_type) {
50 static const GEnumValue usage_types[] = {
51 {CAMERA_VIDEO_REAL_TIME, "video from camera", "camera"},
52 {SCREEN_CONTENT_REAL_TIME, "screen content", "screen"},
53 {0, NULL, NULL},
54 };
55
56 usage_type = g_enum_register_static ("EUsageType", usage_types);
57 }
58
59 return usage_type;
60 }
61
62 #define GST_TYPE_RC_MODES (gst_openh264enc_rc_modes_get_type ())
63 static GType
gst_openh264enc_rc_modes_get_type(void)64 gst_openh264enc_rc_modes_get_type (void)
65 {
66 static GType rc_modes_type = 0;
67
68 if (!rc_modes_type) {
69 static const GEnumValue rc_modes_types[] = {
70 {RC_QUALITY_MODE, "Quality mode", "quality"},
71 {RC_BITRATE_MODE, "Bitrate mode", "bitrate"},
72 {RC_BUFFERBASED_MODE, "No bitrate control, just using buffer status",
73 "buffer"},
74 {RC_OFF_MODE, "Rate control off mode", "off"},
75 {0, NULL, NULL},
76 };
77
78 rc_modes_type = g_enum_register_static ("RC_MODES", rc_modes_types);
79 }
80
81 return rc_modes_type;
82 }
83
84 #define GST_TYPE_OPENH264ENC_DEBLOCKING_MODE (gst_openh264enc_deblocking_mode_get_type ())
85 static GType
gst_openh264enc_deblocking_mode_get_type(void)86 gst_openh264enc_deblocking_mode_get_type (void)
87 {
88 static const GEnumValue types[] = {
89 {GST_OPENH264_DEBLOCKING_ON, "Deblocking on", "on"},
90 {GST_OPENH264_DEBLOCKING_OFF, "Deblocking off", "off"},
91 {GST_OPENH264_DEBLOCKING_NOT_SLICE_BOUNDARIES,
92 "Deblocking on, except for slice boundaries", "not-slice-boundaries"},
93 {0, NULL, NULL},
94 };
95 static gsize id = 0;
96
97 if (g_once_init_enter (&id)) {
98 GType _id = g_enum_register_static ("GstOpenh264encDeblockingModes", types);
99 g_once_init_leave (&id, _id);
100 }
101
102 return (GType) id;
103 }
104
105 #define GST_TYPE_OPENH264ENC_SLICE_MODE (gst_openh264enc_slice_mode_get_type ())
106 static GType
gst_openh264enc_slice_mode_get_type(void)107 gst_openh264enc_slice_mode_get_type (void)
108 {
109 static const GEnumValue types[] = {
110 {GST_OPENH264_SLICE_MODE_N_SLICES, "Fixed number of slices", "n-slices"},
111 {GST_OPENH264_SLICE_MODE_AUTO,
112 "Number of slices equal to number of threads", "auto"},
113 {0, NULL, NULL},
114 };
115 static gsize id = 0;
116
117 if (g_once_init_enter (&id)) {
118 GType _id = g_enum_register_static ("GstOpenh264EncSliceModes", types);
119 g_once_init_leave (&id, _id);
120 }
121
122 return (GType) id;
123 }
124
125 #define GST_TYPE_OPENH264ENC_COMPLEXITY (gst_openh264enc_complexity_get_type ())
126 static GType
gst_openh264enc_complexity_get_type(void)127 gst_openh264enc_complexity_get_type (void)
128 {
129 static const GEnumValue types[] = {
130 {LOW_COMPLEXITY, "Low complexity / high speed encoding", "low"},
131 {MEDIUM_COMPLEXITY, "Medium complexity / medium speed encoding", "medium"},
132 {HIGH_COMPLEXITY, "High complexity / low speed encoding", "high"},
133 {0, NULL, NULL},
134 };
135 static gsize id = 0;
136
137 if (g_once_init_enter (&id)) {
138 GType _id = g_enum_register_static ("GstOpenh264encComplexity", types);
139 g_once_init_leave (&id, _id);
140 }
141
142 return (GType) id;
143 }
144
145 /* prototypes */
146
147 static void gst_openh264enc_set_property (GObject * object,
148 guint property_id, const GValue * value, GParamSpec * pspec);
149 static void gst_openh264enc_get_property (GObject * object,
150 guint property_id, GValue * value, GParamSpec * pspec);
151 static void gst_openh264enc_finalize (GObject * object);
152 static gboolean gst_openh264enc_start (GstVideoEncoder * encoder);
153 static gboolean gst_openh264enc_stop (GstVideoEncoder * encoder);
154 static gboolean gst_openh264enc_set_format (GstVideoEncoder * encoder,
155 GstVideoCodecState * state);
156 static GstFlowReturn gst_openh264enc_handle_frame (GstVideoEncoder * encoder,
157 GstVideoCodecFrame * frame);
158 static GstFlowReturn gst_openh264enc_finish (GstVideoEncoder * encoder);
159 static gboolean gst_openh264enc_propose_allocation (GstVideoEncoder * encoder,
160 GstQuery * query);
161 static void gst_openh264enc_set_usage_type (GstOpenh264Enc * openh264enc,
162 gint usage_type);
163 static void gst_openh264enc_set_rate_control (GstOpenh264Enc * openh264enc,
164 gint rc_mode);
165
166
167 #define DEFAULT_BITRATE (128000)
168 #define DEFAULT_MAX_BITRATE (UNSPECIFIED_BIT_RATE)
169 #define DEFAULT_GOP_SIZE (90)
170 #define DEFAULT_MAX_SLICE_SIZE (1500000)
171 #define START_FRAMERATE 30
172 #define DEFAULT_USAGE_TYPE CAMERA_VIDEO_REAL_TIME
173 #define DEFAULT_RATE_CONTROL RC_QUALITY_MODE
174 #define DEFAULT_MULTI_THREAD 0
175 #define DEFAULT_ENABLE_DENOISE FALSE
176 #define DEFAULT_ENABLE_FRAME_SKIP FALSE
177 #define DEFAULT_DEBLOCKING_MODE GST_OPENH264_DEBLOCKING_ON
178 #define DEFAULT_BACKGROUND_DETECTION TRUE
179 #define DEFAULT_ADAPTIVE_QUANTIZATION TRUE
180 #define DEFAULT_SCENE_CHANGE_DETECTION TRUE
181 #define DEFAULT_SLICE_MODE GST_OPENH264_SLICE_MODE_N_SLICES
182 #define DEFAULT_NUM_SLICES 1
183 #define DEFAULT_COMPLEXITY MEDIUM_COMPLEXITY
184 #define DEFAULT_QP_MIN 0
185 #define DEFAULT_QP_MAX 51
186
187 enum
188 {
189 PROP_0,
190 PROP_USAGE_TYPE,
191 PROP_BITRATE,
192 PROP_MAX_BITRATE,
193 PROP_GOP_SIZE,
194 PROP_MAX_SLICE_SIZE,
195 PROP_RATE_CONTROL,
196 PROP_MULTI_THREAD,
197 PROP_ENABLE_DENOISE,
198 PROP_ENABLE_FRAME_SKIP,
199 PROP_DEBLOCKING_MODE,
200 PROP_BACKGROUND_DETECTION,
201 PROP_ADAPTIVE_QUANTIZATION,
202 PROP_SCENE_CHANGE_DETECTION,
203 PROP_SLICE_MODE,
204 PROP_NUM_SLICES,
205 PROP_COMPLEXITY,
206 PROP_QP_MIN,
207 PROP_QP_MAX,
208 N_PROPERTIES
209 };
210
211 /* pad templates */
212
213 static GstStaticPadTemplate gst_openh264enc_sink_template =
214 GST_STATIC_PAD_TEMPLATE ("sink",
215 GST_PAD_SINK,
216 GST_PAD_ALWAYS,
217 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
218 );
219
220 static GstStaticPadTemplate gst_openh264enc_src_template =
221 GST_STATIC_PAD_TEMPLATE ("src",
222 GST_PAD_SRC,
223 GST_PAD_ALWAYS,
224 GST_STATIC_CAPS
225 ("video/x-h264, stream-format=(string)\"byte-stream\", alignment=(string)\"au\", profile=(string)\"baseline\"")
226 );
227
228 /* class initialization */
229
230 G_DEFINE_TYPE_WITH_CODE (GstOpenh264Enc, gst_openh264enc,
231 GST_TYPE_VIDEO_ENCODER,
232 G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL);
233 GST_DEBUG_CATEGORY_INIT (gst_openh264enc_debug_category, "openh264enc", 0,
234 "debug category for openh264enc element"));
235
236 static void
gst_openh264enc_class_init(GstOpenh264EncClass * klass)237 gst_openh264enc_class_init (GstOpenh264EncClass * klass)
238 {
239 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
240 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
241
242 /* Setting up pads and setting metadata should be moved to
243 base_class_init if you intend to subclass this class. */
244 gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
245 &gst_openh264enc_src_template);
246 gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
247 &gst_openh264enc_sink_template);
248
249 gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
250 "OpenH264 video encoder", "Encoder/Video", "OpenH264 video encoder",
251 "Ericsson AB, http://www.ericsson.com");
252
253 gobject_class->set_property = gst_openh264enc_set_property;
254 gobject_class->get_property = gst_openh264enc_get_property;
255 gobject_class->finalize = gst_openh264enc_finalize;
256 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_openh264enc_start);
257 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_openh264enc_stop);
258 video_encoder_class->set_format =
259 GST_DEBUG_FUNCPTR (gst_openh264enc_set_format);
260 video_encoder_class->handle_frame =
261 GST_DEBUG_FUNCPTR (gst_openh264enc_handle_frame);
262 video_encoder_class->propose_allocation =
263 GST_DEBUG_FUNCPTR (gst_openh264enc_propose_allocation);
264 video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_openh264enc_finish);
265
266 /* define properties */
267 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_USAGE_TYPE,
268 g_param_spec_enum ("usage-type", "Usage type",
269 "Type of video content",
270 GST_TYPE_USAGE_TYPE, CAMERA_VIDEO_REAL_TIME,
271 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
272
273 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RATE_CONTROL,
274 g_param_spec_enum ("rate-control", "Rate control",
275 "Rate control mode",
276 GST_TYPE_RC_MODES, RC_QUALITY_MODE,
277 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
278
279 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MULTI_THREAD,
280 g_param_spec_uint ("multi-thread", "Number of threads",
281 "The number of threads.",
282 0, G_MAXUINT, DEFAULT_MULTI_THREAD,
283 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
284
285 g_object_class_install_property (gobject_class, PROP_ENABLE_DENOISE,
286 g_param_spec_boolean ("enable-denoise", "Denoise Control",
287 "Denoise control",
288 FALSE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
289
290 g_object_class_install_property (gobject_class, PROP_ENABLE_FRAME_SKIP,
291 g_param_spec_boolean ("enable-frame-skip", "Skip Frames",
292 "Skip frames to reach target bitrate",
293 FALSE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
294
295 g_object_class_install_property (gobject_class, PROP_BITRATE,
296 g_param_spec_uint ("bitrate", "Bitrate",
297 "Bitrate (in bits per second)",
298 0, G_MAXUINT, DEFAULT_BITRATE,
299 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
300 GST_PARAM_MUTABLE_PLAYING)));
301
302 g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
303 g_param_spec_uint ("max-bitrate", "Max Bitrate",
304 "Maximum Bitrate (in bits per second)",
305 0, G_MAXUINT, DEFAULT_MAX_BITRATE,
306 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
307 GST_PARAM_MUTABLE_PLAYING)));
308
309 g_object_class_install_property (gobject_class, PROP_QP_MIN,
310 g_param_spec_uint ("qp-min", "Minimum Quantizer",
311 "Minimum quantizer", 0, 51, DEFAULT_QP_MIN,
312 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
313
314 g_object_class_install_property (gobject_class, PROP_QP_MAX,
315 g_param_spec_uint ("qp-max", "Maximum Quantizer",
316 "Maximum quantizer", 0, 51, DEFAULT_QP_MAX,
317 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
318
319 g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
320 g_param_spec_uint ("gop-size", "GOP size",
321 "Number of frames between intra frames",
322 0, G_MAXUINT, DEFAULT_GOP_SIZE,
323 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
324
325 g_object_class_install_property (gobject_class, PROP_MAX_SLICE_SIZE,
326 g_param_spec_uint ("max-slice-size", "Max slice size",
327 "The maximum size of one slice (in bytes).",
328 0, G_MAXUINT, DEFAULT_MAX_SLICE_SIZE,
329 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
330
331 g_object_class_install_property (G_OBJECT_CLASS (klass),
332 PROP_DEBLOCKING_MODE, g_param_spec_enum ("deblocking",
333 "Deblocking mode", "Deblocking mode",
334 GST_TYPE_OPENH264ENC_DEBLOCKING_MODE, DEFAULT_DEBLOCKING_MODE,
335 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
336
337 g_object_class_install_property (gobject_class, PROP_BACKGROUND_DETECTION,
338 g_param_spec_boolean ("background-detection", "Background detection",
339 "Background detection", DEFAULT_BACKGROUND_DETECTION,
340 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
341
342 g_object_class_install_property (gobject_class, PROP_ADAPTIVE_QUANTIZATION,
343 g_param_spec_boolean ("adaptive-quantization", "Adaptive quantization",
344 "Adaptive quantization", DEFAULT_ADAPTIVE_QUANTIZATION,
345 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
346
347 g_object_class_install_property (gobject_class, PROP_SCENE_CHANGE_DETECTION,
348 g_param_spec_boolean ("scene-change-detection",
349 "Scene change detection", "Scene change detection",
350 DEFAULT_SCENE_CHANGE_DETECTION,
351 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
352
353 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLICE_MODE,
354 g_param_spec_enum ("slice-mode", "Slice mode", "Slice mode",
355 GST_TYPE_OPENH264ENC_SLICE_MODE, DEFAULT_SLICE_MODE,
356 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
357
358 g_object_class_install_property (gobject_class, PROP_NUM_SLICES,
359 g_param_spec_uint ("num-slices", "Number of slices",
360 "The number of slices (needs slice-mode=n-slices)",
361 0, G_MAXUINT, DEFAULT_NUM_SLICES,
362 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
363
364 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
365 g_param_spec_enum ("complexity", "Complexity / quality / speed tradeoff",
366 "Complexity", GST_TYPE_OPENH264ENC_COMPLEXITY, DEFAULT_COMPLEXITY,
367 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
368 }
369
370 static void
gst_openh264enc_init(GstOpenh264Enc * openh264enc)371 gst_openh264enc_init (GstOpenh264Enc * openh264enc)
372 {
373 openh264enc->gop_size = DEFAULT_GOP_SIZE;
374 openh264enc->usage_type = DEFAULT_USAGE_TYPE;
375 openh264enc->rate_control = DEFAULT_RATE_CONTROL;
376 openh264enc->multi_thread = DEFAULT_MULTI_THREAD;
377 openh264enc->max_slice_size = DEFAULT_MAX_SLICE_SIZE;
378 openh264enc->bitrate = DEFAULT_BITRATE;
379 openh264enc->max_bitrate = DEFAULT_MAX_BITRATE;
380 openh264enc->qp_min = DEFAULT_QP_MIN;
381 openh264enc->qp_max = DEFAULT_QP_MAX;
382 openh264enc->framerate = START_FRAMERATE;
383 openh264enc->input_state = NULL;
384 openh264enc->time_per_frame = GST_SECOND / openh264enc->framerate;
385 openh264enc->frame_count = 0;
386 openh264enc->previous_timestamp = 0;
387 openh264enc->enable_denoise = DEFAULT_ENABLE_DENOISE;
388 openh264enc->enable_frame_skip = DEFAULT_ENABLE_FRAME_SKIP;
389 openh264enc->deblocking_mode = DEFAULT_DEBLOCKING_MODE;
390 openh264enc->background_detection = DEFAULT_BACKGROUND_DETECTION;
391 openh264enc->adaptive_quantization = DEFAULT_ADAPTIVE_QUANTIZATION;
392 openh264enc->scene_change_detection = DEFAULT_SCENE_CHANGE_DETECTION;
393 openh264enc->slice_mode = DEFAULT_SLICE_MODE;
394 openh264enc->num_slices = DEFAULT_NUM_SLICES;
395 openh264enc->encoder = NULL;
396 openh264enc->complexity = DEFAULT_COMPLEXITY;
397 openh264enc->bitrate_changed = FALSE;
398 openh264enc->max_bitrate_changed = FALSE;
399 gst_openh264enc_set_usage_type (openh264enc, CAMERA_VIDEO_REAL_TIME);
400 gst_openh264enc_set_rate_control (openh264enc, RC_QUALITY_MODE);
401 }
402
403 static void
gst_openh264enc_set_usage_type(GstOpenh264Enc * openh264enc,gint usage_type)404 gst_openh264enc_set_usage_type (GstOpenh264Enc * openh264enc, gint usage_type)
405 {
406 switch (usage_type) {
407 case CAMERA_VIDEO_REAL_TIME:
408 openh264enc->usage_type = CAMERA_VIDEO_REAL_TIME;
409 break;
410 case SCREEN_CONTENT_REAL_TIME:
411 openh264enc->usage_type = SCREEN_CONTENT_REAL_TIME;
412 break;
413 default:
414 g_assert_not_reached ();
415 }
416 }
417
418 static void
gst_openh264enc_set_rate_control(GstOpenh264Enc * openh264enc,gint rc_mode)419 gst_openh264enc_set_rate_control (GstOpenh264Enc * openh264enc, gint rc_mode)
420 {
421 switch (rc_mode) {
422 case RC_QUALITY_MODE:
423 openh264enc->rate_control = RC_QUALITY_MODE;
424 break;
425 case RC_BITRATE_MODE:
426 openh264enc->rate_control = RC_BITRATE_MODE;
427 break;
428 case RC_BUFFERBASED_MODE:
429 openh264enc->rate_control = RC_BUFFERBASED_MODE;
430 break;
431 case RC_OFF_MODE:
432 openh264enc->rate_control = RC_OFF_MODE;
433 break;
434 default:
435 g_assert_not_reached ();
436 }
437 }
438
439 void
gst_openh264enc_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)440 gst_openh264enc_set_property (GObject * object, guint property_id,
441 const GValue * value, GParamSpec * pspec)
442 {
443 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
444
445 GST_DEBUG_OBJECT (openh264enc, "set_property");
446
447 switch (property_id) {
448 case PROP_BITRATE:
449 GST_OBJECT_LOCK (openh264enc);
450 if (openh264enc->bitrate != g_value_get_uint (value)) {
451 openh264enc->bitrate = g_value_get_uint (value);
452 openh264enc->bitrate_changed = TRUE;
453 }
454 GST_OBJECT_UNLOCK (openh264enc);
455 break;
456
457 case PROP_MAX_BITRATE:
458 GST_OBJECT_LOCK (openh264enc);
459 if (openh264enc->max_bitrate != g_value_get_uint (value)) {
460 openh264enc->max_bitrate = g_value_get_uint (value);
461 openh264enc->max_bitrate_changed = TRUE;
462 }
463 GST_OBJECT_UNLOCK (openh264enc);
464 break;
465
466 case PROP_QP_MIN:
467 openh264enc->qp_min = g_value_get_uint (value);
468 break;
469
470 case PROP_QP_MAX:
471 openh264enc->qp_max = g_value_get_uint (value);
472 break;
473
474 case PROP_MULTI_THREAD:
475 openh264enc->multi_thread = g_value_get_uint (value);
476 break;
477
478 case PROP_USAGE_TYPE:
479 gst_openh264enc_set_usage_type (openh264enc, g_value_get_enum (value));
480 break;
481
482 case PROP_ENABLE_DENOISE:
483 openh264enc->enable_denoise = g_value_get_boolean (value);
484 break;
485
486 case PROP_ENABLE_FRAME_SKIP:
487 openh264enc->enable_frame_skip = g_value_get_boolean (value);
488 break;
489
490 case PROP_RATE_CONTROL:
491 gst_openh264enc_set_rate_control (openh264enc, g_value_get_enum (value));
492 break;
493
494 case PROP_GOP_SIZE:
495 openh264enc->gop_size = g_value_get_uint (value);
496 break;
497
498 case PROP_MAX_SLICE_SIZE:
499 openh264enc->max_slice_size = g_value_get_uint (value);
500 break;
501
502 case PROP_DEBLOCKING_MODE:
503 openh264enc->deblocking_mode =
504 (GstOpenh264encDeblockingMode) g_value_get_enum (value);
505 break;
506
507 case PROP_BACKGROUND_DETECTION:
508 openh264enc->background_detection = g_value_get_boolean (value);
509 break;
510
511 case PROP_ADAPTIVE_QUANTIZATION:
512 openh264enc->adaptive_quantization = g_value_get_boolean (value);
513 break;
514
515 case PROP_SCENE_CHANGE_DETECTION:
516 openh264enc->scene_change_detection = g_value_get_boolean (value);
517 break;
518
519 case PROP_SLICE_MODE:
520 openh264enc->slice_mode =
521 (GstOpenh264EncSliceMode) g_value_get_enum (value);
522 break;
523
524 case PROP_NUM_SLICES:
525 openh264enc->num_slices = g_value_get_uint (value);
526 break;
527
528 case PROP_COMPLEXITY:
529 openh264enc->complexity = (ECOMPLEXITY_MODE) g_value_get_enum (value);
530 break;
531
532 default:
533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
534 break;
535 }
536 }
537
538 void
gst_openh264enc_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)539 gst_openh264enc_get_property (GObject * object, guint property_id,
540 GValue * value, GParamSpec * pspec)
541 {
542 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
543
544 GST_DEBUG_OBJECT (openh264enc, "get_property");
545
546 switch (property_id) {
547 case PROP_USAGE_TYPE:
548 g_value_set_enum (value, openh264enc->usage_type);
549 break;
550
551 case PROP_RATE_CONTROL:
552 g_value_set_enum (value, openh264enc->rate_control);
553 break;
554
555 case PROP_BITRATE:
556 g_value_set_uint (value, openh264enc->bitrate);
557 break;
558
559 case PROP_MAX_BITRATE:
560 g_value_set_uint (value, openh264enc->max_bitrate);
561 break;
562
563 case PROP_QP_MIN:
564 g_value_set_uint (value, openh264enc->qp_min);
565 break;
566
567 case PROP_QP_MAX:
568 g_value_set_uint (value, openh264enc->qp_max);
569 break;
570
571 case PROP_ENABLE_DENOISE:
572 g_value_set_boolean (value, openh264enc->enable_denoise);
573 break;
574
575 case PROP_ENABLE_FRAME_SKIP:
576 g_value_set_boolean (value, openh264enc->enable_frame_skip);
577 break;
578
579 case PROP_MULTI_THREAD:
580 g_value_set_uint (value, openh264enc->multi_thread);
581 break;
582
583 case PROP_GOP_SIZE:
584 g_value_set_uint (value, openh264enc->gop_size);
585 break;
586
587 case PROP_MAX_SLICE_SIZE:
588 g_value_set_uint (value, openh264enc->max_slice_size);
589 break;
590
591 case PROP_DEBLOCKING_MODE:
592 g_value_set_enum (value, openh264enc->deblocking_mode);
593 break;
594
595 case PROP_BACKGROUND_DETECTION:
596 g_value_set_boolean (value, openh264enc->background_detection);
597 break;
598
599 case PROP_ADAPTIVE_QUANTIZATION:
600 g_value_set_boolean (value, openh264enc->adaptive_quantization);
601 break;
602
603 case PROP_SCENE_CHANGE_DETECTION:
604 g_value_set_boolean (value, openh264enc->scene_change_detection);
605 break;
606
607 case PROP_SLICE_MODE:
608 g_value_set_enum (value, openh264enc->slice_mode);
609 break;
610
611 case PROP_NUM_SLICES:
612 g_value_set_uint (value, openh264enc->num_slices);
613 break;
614
615 case PROP_COMPLEXITY:
616 g_value_set_enum (value, openh264enc->complexity);
617 break;
618
619 default:
620 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
621 break;
622 }
623 }
624
625 void
gst_openh264enc_finalize(GObject * object)626 gst_openh264enc_finalize (GObject * object)
627 {
628 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
629
630 GST_DEBUG_OBJECT (openh264enc, "finalize");
631
632 /* clean up object here */
633
634 if (openh264enc->input_state) {
635 gst_video_codec_state_unref (openh264enc->input_state);
636 }
637 openh264enc->input_state = NULL;
638
639 G_OBJECT_CLASS (gst_openh264enc_parent_class)->finalize (object);
640 }
641
642 static gboolean
gst_openh264enc_start(GstVideoEncoder * encoder)643 gst_openh264enc_start (GstVideoEncoder * encoder)
644 {
645 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
646 GST_DEBUG_OBJECT (openh264enc, "start");
647
648 return TRUE;
649 }
650
651 static gboolean
gst_openh264enc_stop(GstVideoEncoder * encoder)652 gst_openh264enc_stop (GstVideoEncoder * encoder)
653 {
654 GstOpenh264Enc *openh264enc;
655
656 openh264enc = GST_OPENH264ENC (encoder);
657
658 if (openh264enc->encoder != NULL) {
659 openh264enc->encoder->Uninitialize ();
660 WelsDestroySVCEncoder (openh264enc->encoder);
661 openh264enc->encoder = NULL;
662 }
663 openh264enc->encoder = NULL;
664
665 if (openh264enc->input_state) {
666 gst_video_codec_state_unref (openh264enc->input_state);
667 }
668 openh264enc->input_state = NULL;
669
670 GST_DEBUG_OBJECT (openh264enc, "openh264_enc_stop called");
671
672 return TRUE;
673 }
674
675
676 static gboolean
gst_openh264enc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)677 gst_openh264enc_set_format (GstVideoEncoder * encoder,
678 GstVideoCodecState * state)
679 {
680 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
681 gchar *debug_caps;
682 guint width, height, fps_n, fps_d;
683 SEncParamExt enc_params;
684 SliceModeEnum slice_mode = SM_SINGLE_SLICE;
685 guint n_slices = 1;
686 gint ret;
687 GstCaps *outcaps;
688 GstVideoCodecState *output_state;
689 openh264enc->frame_count = 0;
690 int video_format = videoFormatI420;
691
692 debug_caps = gst_caps_to_string (state->caps);
693 GST_DEBUG_OBJECT (openh264enc, "gst_e26d4_enc_set_format called, caps: %s",
694 debug_caps);
695 g_free (debug_caps);
696
697 gst_openh264enc_stop (encoder);
698
699 if (openh264enc->input_state) {
700 gst_video_codec_state_unref (openh264enc->input_state);
701 }
702 openh264enc->input_state = gst_video_codec_state_ref (state);
703
704 width = GST_VIDEO_INFO_WIDTH (&state->info);
705 height = GST_VIDEO_INFO_HEIGHT (&state->info);
706 fps_n = GST_VIDEO_INFO_FPS_N (&state->info);
707 fps_d = GST_VIDEO_INFO_FPS_D (&state->info);
708
709 if (openh264enc->encoder != NULL) {
710 openh264enc->encoder->Uninitialize ();
711 WelsDestroySVCEncoder (openh264enc->encoder);
712 openh264enc->encoder = NULL;
713 }
714 WelsCreateSVCEncoder (&openh264enc->encoder);
715 unsigned int uiTraceLevel = WELS_LOG_ERROR;
716 openh264enc->encoder->SetOption (ENCODER_OPTION_TRACE_LEVEL, &uiTraceLevel);
717
718 GST_OBJECT_LOCK (openh264enc);
719
720 openh264enc->encoder->GetDefaultParams (&enc_params);
721
722 enc_params.iUsageType = openh264enc->usage_type;
723 enc_params.iPicWidth = width;
724 enc_params.iPicHeight = height;
725 enc_params.iTargetBitrate = openh264enc->bitrate;
726 enc_params.iMaxBitrate = openh264enc->max_bitrate;
727 enc_params.iMaxQp = openh264enc->qp_max;
728 enc_params.iMinQp = openh264enc->qp_min;
729 enc_params.iRCMode = openh264enc->rate_control;
730 enc_params.iTemporalLayerNum = 1;
731 enc_params.iSpatialLayerNum = 1;
732 enc_params.iLtrMarkPeriod = 30;
733 enc_params.iMultipleThreadIdc = openh264enc->multi_thread;
734 enc_params.bEnableDenoise = openh264enc->enable_denoise;
735 enc_params.iComplexityMode = openh264enc->complexity;
736 enc_params.uiIntraPeriod = openh264enc->gop_size;
737 enc_params.bEnableBackgroundDetection = openh264enc->background_detection;
738 enc_params.bEnableAdaptiveQuant = openh264enc->adaptive_quantization;
739 enc_params.bEnableSceneChangeDetect = openh264enc->scene_change_detection;
740 enc_params.bEnableFrameSkip = openh264enc->enable_frame_skip;
741 enc_params.bEnableLongTermReference = 0;
742 #if (OPENH264_MAJOR > 1 || (OPENH264_MAJOR == 1 && OPENH264_MINOR >= 4))
743 enc_params.eSpsPpsIdStrategy = CONSTANT_ID;
744 #else
745 enc_params.bEnableSpsPpsIdAddition = 0;
746 #endif
747 enc_params.bPrefixNalAddingCtrl = 0;
748 enc_params.fMaxFrameRate = fps_n * 1.0 / fps_d;
749 enc_params.iLoopFilterDisableIdc = openh264enc->deblocking_mode;
750 enc_params.sSpatialLayers[0].uiProfileIdc = PRO_BASELINE;
751 enc_params.sSpatialLayers[0].iVideoWidth = enc_params.iPicWidth;
752 enc_params.sSpatialLayers[0].iVideoHeight = enc_params.iPicHeight;
753 enc_params.sSpatialLayers[0].fFrameRate = fps_n * 1.0 / fps_d;
754 enc_params.sSpatialLayers[0].iSpatialBitrate = enc_params.iTargetBitrate;
755 enc_params.sSpatialLayers[0].iMaxSpatialBitrate = enc_params.iMaxBitrate;
756
757 if (openh264enc->slice_mode == GST_OPENH264_SLICE_MODE_N_SLICES) {
758 if (openh264enc->num_slices == 1)
759 slice_mode = SM_SINGLE_SLICE;
760 else
761 slice_mode = SM_FIXEDSLCNUM_SLICE;
762 n_slices = openh264enc->num_slices;
763 } else if (openh264enc->slice_mode == GST_OPENH264_SLICE_MODE_AUTO) {
764 #if OPENH264_MAJOR == 1 && OPENH264_MINOR < 6
765 slice_mode = SM_AUTO_SLICE;
766 #else
767 slice_mode = SM_FIXEDSLCNUM_SLICE;
768 n_slices = 0;
769 #endif
770 } else {
771 GST_ERROR_OBJECT (openh264enc, "unexpected slice mode %d",
772 openh264enc->slice_mode);
773 slice_mode = SM_SINGLE_SLICE;
774 }
775
776 #if OPENH264_MAJOR == 1 && OPENH264_MINOR < 6
777 enc_params.sSpatialLayers[0].sSliceCfg.uiSliceMode = slice_mode;
778 enc_params.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = n_slices;
779 #else
780 enc_params.sSpatialLayers[0].sSliceArgument.uiSliceMode = slice_mode;
781 enc_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = n_slices;
782 #endif
783
784 openh264enc->framerate = (1 + fps_n / fps_d);
785
786 ret = openh264enc->encoder->InitializeExt (&enc_params);
787
788 openh264enc->bitrate_changed = FALSE;
789 openh264enc->max_bitrate_changed = FALSE;
790
791 GST_OBJECT_UNLOCK (openh264enc);
792
793 if (ret != cmResultSuccess) {
794 GST_ERROR_OBJECT (openh264enc, "failed to initialize encoder");
795 return FALSE;
796 }
797
798 openh264enc->encoder->SetOption (ENCODER_OPTION_DATAFORMAT, &video_format);
799
800 outcaps =
801 gst_caps_copy (gst_static_pad_template_get_caps
802 (&gst_openh264enc_src_template));
803
804 output_state = gst_video_encoder_set_output_state (encoder, outcaps, state);
805 gst_video_codec_state_unref (output_state);
806
807 return gst_video_encoder_negotiate (encoder);
808 }
809
810 static gboolean
gst_openh264enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)811 gst_openh264enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
812 {
813 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
814
815 return
816 GST_VIDEO_ENCODER_CLASS
817 (gst_openh264enc_parent_class)->propose_allocation (encoder, query);
818 }
819
820 static GstFlowReturn
gst_openh264enc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)821 gst_openh264enc_handle_frame (GstVideoEncoder * encoder,
822 GstVideoCodecFrame * frame)
823 {
824 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
825 SSourcePicture *src_pic = NULL;
826 GstVideoFrame video_frame;
827 gboolean force_keyframe;
828 gint ret;
829 SFrameBSInfo frame_info;
830 gfloat fps;
831 GstMapInfo map;
832 gint i, j;
833 gsize buf_length = 0;
834
835 GST_OBJECT_LOCK (openh264enc);
836
837 if (openh264enc->bitrate_changed || openh264enc->max_bitrate_changed) {
838 SEncParamExt enc_params;
839 if (openh264enc->encoder->GetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
840 &enc_params) == cmResultSuccess) {
841 if (openh264enc->bitrate_changed) {
842 enc_params.iTargetBitrate = openh264enc->bitrate;
843 enc_params.sSpatialLayers[0].iSpatialBitrate =
844 enc_params.iTargetBitrate;
845 }
846 if (openh264enc->max_bitrate_changed) {
847 enc_params.iMaxBitrate = openh264enc->max_bitrate;
848 enc_params.sSpatialLayers[0].iMaxSpatialBitrate =
849 enc_params.iMaxBitrate;
850 }
851 if (openh264enc->encoder->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
852 &enc_params) != cmResultSuccess) {
853 GST_WARNING_OBJECT (openh264enc,
854 "Error changing bitrate/max bitrate, unable to set new enc_params");
855 }
856 } else {
857 GST_WARNING_OBJECT (openh264enc,
858 "Error changing bitrate/max bitrate, unable to get enc_params");
859 }
860 openh264enc->bitrate_changed = FALSE;
861 openh264enc->max_bitrate_changed = FALSE;
862 }
863
864 GST_OBJECT_UNLOCK (openh264enc);
865
866 if (frame) {
867 src_pic = new SSourcePicture;
868
869 if (src_pic == NULL) {
870 if (frame)
871 gst_video_codec_frame_unref (frame);
872 return GST_FLOW_ERROR;
873 }
874 //fill default src_pic
875 src_pic->iColorFormat = videoFormatI420;
876 src_pic->uiTimeStamp = frame->pts / GST_MSECOND;
877 }
878
879 openh264enc->frame_count++;
880 if (frame) {
881 if (G_UNLIKELY (openh264enc->frame_count == 1)) {
882 openh264enc->time_per_frame = (GST_SECOND / openh264enc->framerate);
883 openh264enc->previous_timestamp = frame->pts;
884 } else {
885 openh264enc->time_per_frame = (guint64)
886 (openh264enc->time_per_frame * 0.8 + (frame->pts -
887 openh264enc->previous_timestamp) * 0.2);
888 openh264enc->previous_timestamp = frame->pts;
889 if (openh264enc->frame_count % 10 == 0) {
890 fps = GST_SECOND / (gdouble) openh264enc->time_per_frame;
891 openh264enc->encoder->SetOption (ENCODER_OPTION_FRAME_RATE, &fps);
892 }
893 }
894 }
895
896 if (frame) {
897 gst_video_frame_map (&video_frame, &openh264enc->input_state->info,
898 frame->input_buffer, GST_MAP_READ);
899 src_pic->iPicWidth = GST_VIDEO_FRAME_WIDTH (&video_frame);
900 src_pic->iPicHeight = GST_VIDEO_FRAME_HEIGHT (&video_frame);
901 src_pic->iStride[0] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 0);
902 src_pic->iStride[1] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 1);
903 src_pic->iStride[2] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 2);
904 src_pic->pData[0] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 0);
905 src_pic->pData[1] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 1);
906 src_pic->pData[2] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 2);
907
908 force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
909 if (force_keyframe) {
910 openh264enc->encoder->ForceIntraFrame (true);
911 GST_DEBUG_OBJECT (openh264enc,
912 "Got force key unit event, next frame coded as intra picture");
913 }
914 }
915
916 memset (&frame_info, 0, sizeof (SFrameBSInfo));
917 ret = openh264enc->encoder->EncodeFrame (src_pic, &frame_info);
918 if (ret != cmResultSuccess) {
919 if (frame) {
920 gst_video_frame_unmap (&video_frame);
921 gst_video_codec_frame_unref (frame);
922 delete src_pic;
923 GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE,
924 ("Could not encode frame"), ("Openh264 returned %d", ret));
925 return GST_FLOW_ERROR;
926 } else {
927 return GST_FLOW_EOS;
928 }
929 }
930
931 if (videoFrameTypeSkip == frame_info.eFrameType) {
932 if (frame) {
933 gst_video_frame_unmap (&video_frame);
934 gst_video_encoder_finish_frame (encoder, frame);
935 delete src_pic;
936 }
937
938 return GST_FLOW_OK;
939 }
940
941 if (frame) {
942 gst_video_frame_unmap (&video_frame);
943 gst_video_codec_frame_unref (frame);
944 delete src_pic;
945 src_pic = NULL;
946 frame = NULL;
947 }
948
949 /* FIXME: openh264 has no way for us to get a connection
950 * between the input and output frames, we just have to
951 * guess based on the input */
952 frame = gst_video_encoder_get_oldest_frame (encoder);
953 if (!frame) {
954 GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE,
955 ("Could not encode frame"), ("openh264enc returned %d", ret));
956 gst_video_codec_frame_unref (frame);
957 return GST_FLOW_ERROR;
958 }
959
960 if (videoFrameTypeIDR == frame_info.eFrameType) {
961 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
962 } else {
963 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
964 }
965
966 for (i = 0; i < frame_info.iLayerNum; i++) {
967 for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) {
968 buf_length += frame_info.sLayerInfo[i].pNalLengthInByte[j];
969 }
970 }
971
972 frame->output_buffer =
973 gst_video_encoder_allocate_output_buffer (encoder, buf_length);
974 gst_buffer_map (frame->output_buffer, &map, GST_MAP_WRITE);
975
976 buf_length = 0;
977 for (i = 0; i < frame_info.iLayerNum; i++) {
978 gsize layer_size = 0;
979 for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) {
980 layer_size += frame_info.sLayerInfo[i].pNalLengthInByte[j];
981 }
982 memcpy (map.data + buf_length, frame_info.sLayerInfo[i].pBsBuf, layer_size);
983 buf_length += layer_size;
984 }
985
986 gst_buffer_unmap (frame->output_buffer, &map);
987
988 GST_LOG_OBJECT (openh264enc, "openh264 picture %scoded OK!",
989 (ret != cmResultSuccess) ? "NOT " : "");
990
991 return gst_video_encoder_finish_frame (encoder, frame);
992 }
993
994 static GstFlowReturn
gst_openh264enc_finish(GstVideoEncoder * encoder)995 gst_openh264enc_finish (GstVideoEncoder * encoder)
996 {
997 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
998
999 if (openh264enc->frame_count == 0)
1000 return GST_FLOW_OK;
1001
1002 /* Drain encoder */
1003 while ((gst_openh264enc_handle_frame (encoder, NULL)) == GST_FLOW_OK);
1004
1005 return GST_FLOW_OK;
1006 }
1007