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