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 "gstopenh264elements.h"
31 #include "gstopenh264enc.h"
32
33 #include <gst/pbutils/pbutils.h>
34 #include <gst/gst.h>
35 #include <gst/base/base.h>
36 #include <gst/video/video.h>
37 #include <gst/video/gstvideoencoder.h>
38 #include <string.h>
39
40 GST_DEBUG_CATEGORY_STATIC (gst_openh264enc_debug_category);
41 #define GST_CAT_DEFAULT gst_openh264enc_debug_category
42
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 ())
46 static GType
gst_openh264enc_usage_type_get_type(void)47 gst_openh264enc_usage_type_get_type (void)
48 {
49 static GType usage_type = 0;
50
51 if (!usage_type) {
52 static const GEnumValue usage_types[] = {
53 {CAMERA_VIDEO_REAL_TIME, "video from camera", "camera"},
54 {SCREEN_CONTENT_REAL_TIME, "screen content", "screen"},
55 {0, NULL, NULL},
56 };
57
58 usage_type = g_enum_register_static ("EUsageType", usage_types);
59 }
60
61 return usage_type;
62 }
63
64 #define GST_TYPE_RC_MODES (gst_openh264enc_rc_modes_get_type ())
65 static GType
gst_openh264enc_rc_modes_get_type(void)66 gst_openh264enc_rc_modes_get_type (void)
67 {
68 static GType rc_modes_type = 0;
69
70 if (!rc_modes_type) {
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",
75 "buffer"},
76 {RC_OFF_MODE, "Rate control off mode", "off"},
77 {0, NULL, NULL},
78 };
79
80 rc_modes_type = g_enum_register_static ("RC_MODES", rc_modes_types);
81 }
82
83 return rc_modes_type;
84 }
85
86 #define GST_TYPE_OPENH264ENC_DEBLOCKING_MODE (gst_openh264enc_deblocking_mode_get_type ())
87 static GType
gst_openh264enc_deblocking_mode_get_type(void)88 gst_openh264enc_deblocking_mode_get_type (void)
89 {
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"},
95 {0, NULL, NULL},
96 };
97 static gsize id = 0;
98
99 if (g_once_init_enter (&id)) {
100 GType _id = g_enum_register_static ("GstOpenh264encDeblockingModes", types);
101 g_once_init_leave (&id, _id);
102 }
103
104 return (GType) id;
105 }
106
107 #define GST_TYPE_OPENH264ENC_SLICE_MODE (gst_openh264enc_slice_mode_get_type ())
108 static GType
gst_openh264enc_slice_mode_get_type(void)109 gst_openh264enc_slice_mode_get_type (void)
110 {
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"},
115 {0, NULL, NULL},
116 };
117 static gsize id = 0;
118
119 if (g_once_init_enter (&id)) {
120 GType _id = g_enum_register_static ("GstOpenh264EncSliceModes", types);
121 g_once_init_leave (&id, _id);
122 }
123
124 return (GType) id;
125 }
126
127 #define GST_TYPE_OPENH264ENC_COMPLEXITY (gst_openh264enc_complexity_get_type ())
128 static GType
gst_openh264enc_complexity_get_type(void)129 gst_openh264enc_complexity_get_type (void)
130 {
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"},
135 {0, NULL, NULL},
136 };
137 static gsize id = 0;
138
139 if (g_once_init_enter (&id)) {
140 GType _id = g_enum_register_static ("GstOpenh264encComplexity", types);
141 g_once_init_leave (&id, _id);
142 }
143
144 return (GType) id;
145 }
146
147 /* prototypes */
148
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,
162 GstQuery * query);
163 static void gst_openh264enc_set_usage_type (GstOpenh264Enc * openh264enc,
164 gint usage_type);
165 static void gst_openh264enc_set_rate_control (GstOpenh264Enc * openh264enc,
166 gint rc_mode);
167 static gboolean openh264enc_element_init (GstPlugin * plugin);
168
169
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
189
190 enum
191 {
192 PROP_0,
193 PROP_USAGE_TYPE,
194 PROP_BITRATE,
195 PROP_MAX_BITRATE,
196 PROP_GOP_SIZE,
197 PROP_MAX_SLICE_SIZE,
198 PROP_RATE_CONTROL,
199 PROP_MULTI_THREAD,
200 PROP_ENABLE_DENOISE,
201 PROP_ENABLE_FRAME_SKIP,
202 PROP_DEBLOCKING_MODE,
203 PROP_BACKGROUND_DETECTION,
204 PROP_ADAPTIVE_QUANTIZATION,
205 PROP_SCENE_CHANGE_DETECTION,
206 PROP_SLICE_MODE,
207 PROP_NUM_SLICES,
208 PROP_COMPLEXITY,
209 PROP_QP_MIN,
210 PROP_QP_MAX,
211 N_PROPERTIES
212 };
213
214 /* pad templates */
215
216 static GstStaticPadTemplate gst_openh264enc_sink_template =
217 GST_STATIC_PAD_TEMPLATE ("sink",
218 GST_PAD_SINK,
219 GST_PAD_ALWAYS,
220 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
221 );
222
223 static GstStaticPadTemplate gst_openh264enc_src_template =
224 GST_STATIC_PAD_TEMPLATE ("src",
225 GST_PAD_SRC,
226 GST_PAD_ALWAYS,
227 GST_STATIC_CAPS
228 ("video/x-h264, "
229 "stream-format=(string)\"byte-stream\", alignment=(string)\"au\","
230 "profile = (string) { constrained-baseline, baseline, main, constrained-high, high }"
231 )
232 );
233
234 /* class initialization */
235
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);
242
243 static void
gst_openh264enc_class_init(GstOpenh264EncClass * klass)244 gst_openh264enc_class_init (GstOpenh264EncClass * klass)
245 {
246 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
247 GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
248
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);
255
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");
259
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);
272
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)));
279
280 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RATE_CONTROL,
281 g_param_spec_enum ("rate-control", "Rate control",
282 "Rate control mode",
283 GST_TYPE_RC_MODES, RC_QUALITY_MODE,
284 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
285
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)));
291
292 g_object_class_install_property (gobject_class, PROP_ENABLE_DENOISE,
293 g_param_spec_boolean ("enable-denoise", "Denoise Control",
294 "Denoise control",
295 FALSE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
296
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)));
301
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)));
308
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)));
315
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)));
320
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)));
325
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)));
331
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)));
337
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)));
343
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)));
348
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)));
353
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)));
359
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)));
364
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)));
370
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)));
375
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);
381 }
382
383 static void
gst_openh264enc_init(GstOpenh264Enc * openh264enc)384 gst_openh264enc_init (GstOpenh264Enc * openh264enc)
385 {
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);
414 }
415
416 static void
gst_openh264enc_set_usage_type(GstOpenh264Enc * openh264enc,gint usage_type)417 gst_openh264enc_set_usage_type (GstOpenh264Enc * openh264enc, gint usage_type)
418 {
419 switch (usage_type) {
420 case CAMERA_VIDEO_REAL_TIME:
421 openh264enc->usage_type = CAMERA_VIDEO_REAL_TIME;
422 break;
423 case SCREEN_CONTENT_REAL_TIME:
424 openh264enc->usage_type = SCREEN_CONTENT_REAL_TIME;
425 break;
426 default:
427 g_assert_not_reached ();
428 }
429 }
430
431 static void
gst_openh264enc_set_rate_control(GstOpenh264Enc * openh264enc,gint rc_mode)432 gst_openh264enc_set_rate_control (GstOpenh264Enc * openh264enc, gint rc_mode)
433 {
434 switch (rc_mode) {
435 case RC_QUALITY_MODE:
436 openh264enc->rate_control = RC_QUALITY_MODE;
437 break;
438 case RC_BITRATE_MODE:
439 openh264enc->rate_control = RC_BITRATE_MODE;
440 break;
441 case RC_BUFFERBASED_MODE:
442 openh264enc->rate_control = RC_BUFFERBASED_MODE;
443 break;
444 case RC_OFF_MODE:
445 openh264enc->rate_control = RC_OFF_MODE;
446 break;
447 default:
448 g_assert_not_reached ();
449 }
450 }
451
452 void
gst_openh264enc_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)453 gst_openh264enc_set_property (GObject * object, guint property_id,
454 const GValue * value, GParamSpec * pspec)
455 {
456 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
457
458 GST_DEBUG_OBJECT (openh264enc, "set_property");
459
460 switch (property_id) {
461 case PROP_BITRATE:
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;
466 }
467 GST_OBJECT_UNLOCK (openh264enc);
468 break;
469
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;
475 }
476 GST_OBJECT_UNLOCK (openh264enc);
477 break;
478
479 case PROP_QP_MIN:
480 openh264enc->qp_min = g_value_get_uint (value);
481 break;
482
483 case PROP_QP_MAX:
484 openh264enc->qp_max = g_value_get_uint (value);
485 break;
486
487 case PROP_MULTI_THREAD:
488 openh264enc->multi_thread = g_value_get_uint (value);
489 break;
490
491 case PROP_USAGE_TYPE:
492 gst_openh264enc_set_usage_type (openh264enc, g_value_get_enum (value));
493 break;
494
495 case PROP_ENABLE_DENOISE:
496 openh264enc->enable_denoise = g_value_get_boolean (value);
497 break;
498
499 case PROP_ENABLE_FRAME_SKIP:
500 openh264enc->enable_frame_skip = g_value_get_boolean (value);
501 break;
502
503 case PROP_RATE_CONTROL:
504 gst_openh264enc_set_rate_control (openh264enc, g_value_get_enum (value));
505 break;
506
507 case PROP_GOP_SIZE:
508 openh264enc->gop_size = g_value_get_uint (value);
509 break;
510
511 case PROP_MAX_SLICE_SIZE:
512 openh264enc->max_slice_size = g_value_get_uint (value);
513 break;
514
515 case PROP_DEBLOCKING_MODE:
516 openh264enc->deblocking_mode =
517 (GstOpenh264encDeblockingMode) g_value_get_enum (value);
518 break;
519
520 case PROP_BACKGROUND_DETECTION:
521 openh264enc->background_detection = g_value_get_boolean (value);
522 break;
523
524 case PROP_ADAPTIVE_QUANTIZATION:
525 openh264enc->adaptive_quantization = g_value_get_boolean (value);
526 break;
527
528 case PROP_SCENE_CHANGE_DETECTION:
529 openh264enc->scene_change_detection = g_value_get_boolean (value);
530 break;
531
532 case PROP_SLICE_MODE:
533 openh264enc->slice_mode =
534 (GstOpenh264EncSliceMode) g_value_get_enum (value);
535 break;
536
537 case PROP_NUM_SLICES:
538 openh264enc->num_slices = g_value_get_uint (value);
539 break;
540
541 case PROP_COMPLEXITY:
542 openh264enc->complexity = (ECOMPLEXITY_MODE) g_value_get_enum (value);
543 break;
544
545 default:
546 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
547 break;
548 }
549 }
550
551 void
gst_openh264enc_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)552 gst_openh264enc_get_property (GObject * object, guint property_id,
553 GValue * value, GParamSpec * pspec)
554 {
555 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
556
557 GST_DEBUG_OBJECT (openh264enc, "get_property");
558
559 switch (property_id) {
560 case PROP_USAGE_TYPE:
561 g_value_set_enum (value, openh264enc->usage_type);
562 break;
563
564 case PROP_RATE_CONTROL:
565 g_value_set_enum (value, openh264enc->rate_control);
566 break;
567
568 case PROP_BITRATE:
569 g_value_set_uint (value, openh264enc->bitrate);
570 break;
571
572 case PROP_MAX_BITRATE:
573 g_value_set_uint (value, openh264enc->max_bitrate);
574 break;
575
576 case PROP_QP_MIN:
577 g_value_set_uint (value, openh264enc->qp_min);
578 break;
579
580 case PROP_QP_MAX:
581 g_value_set_uint (value, openh264enc->qp_max);
582 break;
583
584 case PROP_ENABLE_DENOISE:
585 g_value_set_boolean (value, openh264enc->enable_denoise);
586 break;
587
588 case PROP_ENABLE_FRAME_SKIP:
589 g_value_set_boolean (value, openh264enc->enable_frame_skip);
590 break;
591
592 case PROP_MULTI_THREAD:
593 g_value_set_uint (value, openh264enc->multi_thread);
594 break;
595
596 case PROP_GOP_SIZE:
597 g_value_set_uint (value, openh264enc->gop_size);
598 break;
599
600 case PROP_MAX_SLICE_SIZE:
601 g_value_set_uint (value, openh264enc->max_slice_size);
602 break;
603
604 case PROP_DEBLOCKING_MODE:
605 g_value_set_enum (value, openh264enc->deblocking_mode);
606 break;
607
608 case PROP_BACKGROUND_DETECTION:
609 g_value_set_boolean (value, openh264enc->background_detection);
610 break;
611
612 case PROP_ADAPTIVE_QUANTIZATION:
613 g_value_set_boolean (value, openh264enc->adaptive_quantization);
614 break;
615
616 case PROP_SCENE_CHANGE_DETECTION:
617 g_value_set_boolean (value, openh264enc->scene_change_detection);
618 break;
619
620 case PROP_SLICE_MODE:
621 g_value_set_enum (value, openh264enc->slice_mode);
622 break;
623
624 case PROP_NUM_SLICES:
625 g_value_set_uint (value, openh264enc->num_slices);
626 break;
627
628 case PROP_COMPLEXITY:
629 g_value_set_enum (value, openh264enc->complexity);
630 break;
631
632 default:
633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
634 break;
635 }
636 }
637
638 void
gst_openh264enc_finalize(GObject * object)639 gst_openh264enc_finalize (GObject * object)
640 {
641 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (object);
642
643 GST_DEBUG_OBJECT (openh264enc, "finalize");
644
645 /* clean up object here */
646
647 if (openh264enc->input_state) {
648 gst_video_codec_state_unref (openh264enc->input_state);
649 }
650 openh264enc->input_state = NULL;
651
652 G_OBJECT_CLASS (gst_openh264enc_parent_class)->finalize (object);
653 }
654
655 static gboolean
gst_openh264enc_start(GstVideoEncoder * encoder)656 gst_openh264enc_start (GstVideoEncoder * encoder)
657 {
658 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
659 GST_DEBUG_OBJECT (openh264enc, "start");
660
661 return TRUE;
662 }
663
664 static gboolean
gst_openh264enc_stop(GstVideoEncoder * encoder)665 gst_openh264enc_stop (GstVideoEncoder * encoder)
666 {
667 GstOpenh264Enc *openh264enc;
668
669 openh264enc = GST_OPENH264ENC (encoder);
670
671 if (openh264enc->encoder != NULL) {
672 openh264enc->encoder->Uninitialize ();
673 WelsDestroySVCEncoder (openh264enc->encoder);
674 openh264enc->encoder = NULL;
675 }
676 openh264enc->encoder = NULL;
677
678 if (openh264enc->input_state) {
679 gst_video_codec_state_unref (openh264enc->input_state);
680 }
681 openh264enc->input_state = NULL;
682
683 GST_DEBUG_OBJECT (openh264enc, "openh264_enc_stop called");
684
685 return TRUE;
686 }
687
688 static guint8
gst_openh264enc_get_level_from_caps(GstCaps * outcaps,GstCaps * allowed_caps)689 gst_openh264enc_get_level_from_caps (GstCaps *outcaps, GstCaps *allowed_caps)
690 {
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");
693
694 if (!level)
695 return LEVEL_UNKNOWN;
696
697 gst_structure_set (s, "level", G_TYPE_STRING, level, NULL);
698 return gst_codec_utils_h264_get_level_idc (level);
699 }
700
701 static EProfileIdc
gst_openh264enc_get_profile_from_caps(GstCaps * outcaps,GstCaps * allowed_caps)702 gst_openh264enc_get_profile_from_caps (GstCaps *outcaps, GstCaps *allowed_caps)
703 {
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");
708
709 if (!profile)
710 return oh264_profile;
711
712 gst_structure_set (s, "profile", G_TYPE_STRING, profile, NULL);
713 if (!g_strcmp0 (profile, "constrained-baseline") ||
714 !g_strcmp0 (profile, "baseline"))
715 return PRO_BASELINE;
716 else if (!g_strcmp0 (profile, "main"))
717 return PRO_MAIN;
718 else if (!g_strcmp0 (profile, "high"))
719 return PRO_HIGH;
720
721 g_assert_not_reached ();
722 return PRO_BASELINE;
723 }
724
725 static gboolean
gst_openh264enc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)726 gst_openh264enc_set_format (GstVideoEncoder * encoder,
727 GstVideoCodecState * state)
728 {
729 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
730 gchar *debug_caps;
731 guint width, height, fps_n, fps_d;
732 SEncParamExt enc_params;
733 SliceModeEnum slice_mode = SM_SINGLE_SLICE;
734 guint n_slices = 1;
735 gint ret;
736 GstCaps *outcaps;
737 GstVideoCodecState *output_state;
738 openh264enc->frame_count = 0;
739 int video_format = videoFormatI420;
740 GstCaps *allowed_caps = NULL;
741
742 debug_caps = gst_caps_to_string (state->caps);
743 GST_DEBUG_OBJECT (openh264enc, "gst_e26d4_enc_set_format called, caps: %s",
744 debug_caps);
745 g_free (debug_caps);
746
747 gst_openh264enc_stop (encoder);
748
749 if (openh264enc->input_state) {
750 gst_video_codec_state_unref (openh264enc->input_state);
751 }
752 openh264enc->input_state = gst_video_codec_state_ref (state);
753
754 width = GST_VIDEO_INFO_WIDTH (&state->info);
755 height = GST_VIDEO_INFO_HEIGHT (&state->info);
756 fps_n = GST_VIDEO_INFO_FPS_N (&state->info);
757 fps_d = GST_VIDEO_INFO_FPS_D (&state->info);
758
759 if (openh264enc->encoder != NULL) {
760 openh264enc->encoder->Uninitialize ();
761 WelsDestroySVCEncoder (openh264enc->encoder);
762 openh264enc->encoder = NULL;
763 }
764 WelsCreateSVCEncoder (&openh264enc->encoder);
765 unsigned int uiTraceLevel = WELS_LOG_ERROR;
766 openh264enc->encoder->SetOption (ENCODER_OPTION_TRACE_LEVEL, &uiTraceLevel);
767
768 outcaps = gst_static_pad_template_get_caps (&gst_openh264enc_src_template);
769 outcaps = gst_caps_make_writable (outcaps);
770 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
771 allowed_caps = gst_caps_make_writable (allowed_caps);
772 allowed_caps = gst_caps_fixate (allowed_caps);
773
774 GST_OBJECT_LOCK (openh264enc);
775
776 openh264enc->encoder->GetDefaultParams (&enc_params);
777
778 enc_params.iUsageType = openh264enc->usage_type;
779 enc_params.iPicWidth = width;
780 enc_params.iPicHeight = height;
781 enc_params.iTargetBitrate = openh264enc->bitrate;
782 enc_params.iMaxBitrate = openh264enc->max_bitrate;
783 enc_params.iMaxQp = openh264enc->qp_max;
784 enc_params.iMinQp = openh264enc->qp_min;
785 enc_params.iRCMode = openh264enc->rate_control;
786 enc_params.iTemporalLayerNum = 1;
787 enc_params.iSpatialLayerNum = 1;
788 enc_params.iLtrMarkPeriod = 30;
789 enc_params.iMultipleThreadIdc = openh264enc->multi_thread;
790 enc_params.bEnableDenoise = openh264enc->enable_denoise;
791 enc_params.iComplexityMode = openh264enc->complexity;
792 enc_params.uiIntraPeriod = openh264enc->gop_size;
793 enc_params.bEnableBackgroundDetection = openh264enc->background_detection;
794 enc_params.bEnableAdaptiveQuant = openh264enc->adaptive_quantization;
795 enc_params.bEnableSceneChangeDetect = openh264enc->scene_change_detection;
796 enc_params.bEnableFrameSkip = openh264enc->enable_frame_skip;
797 enc_params.bEnableLongTermReference = 0;
798 #if (OPENH264_MAJOR > 1 || (OPENH264_MAJOR == 1 && OPENH264_MINOR >= 4))
799 enc_params.eSpsPpsIdStrategy = CONSTANT_ID;
800 #else
801 enc_params.bEnableSpsPpsIdAddition = 0;
802 #endif
803 enc_params.bPrefixNalAddingCtrl = 0;
804 enc_params.fMaxFrameRate = fps_n * 1.0 / fps_d;
805 enc_params.iLoopFilterDisableIdc = openh264enc->deblocking_mode;
806 enc_params.sSpatialLayers[0].uiProfileIdc = gst_openh264enc_get_profile_from_caps (outcaps, allowed_caps);
807 enc_params.sSpatialLayers[0].uiLevelIdc = (ELevelIdc) gst_openh264enc_get_level_from_caps (outcaps, allowed_caps);
808 enc_params.sSpatialLayers[0].iVideoWidth = enc_params.iPicWidth;
809 enc_params.sSpatialLayers[0].iVideoHeight = enc_params.iPicHeight;
810 enc_params.sSpatialLayers[0].fFrameRate = fps_n * 1.0 / fps_d;
811 enc_params.sSpatialLayers[0].iSpatialBitrate = enc_params.iTargetBitrate;
812 enc_params.sSpatialLayers[0].iMaxSpatialBitrate = enc_params.iMaxBitrate;
813
814 gst_clear_caps (&allowed_caps);
815
816 if (openh264enc->slice_mode == GST_OPENH264_SLICE_MODE_N_SLICES) {
817 if (openh264enc->num_slices == 1)
818 slice_mode = SM_SINGLE_SLICE;
819 else
820 slice_mode = SM_FIXEDSLCNUM_SLICE;
821 n_slices = openh264enc->num_slices;
822 } else if (openh264enc->slice_mode == GST_OPENH264_SLICE_MODE_AUTO) {
823 #if OPENH264_MAJOR == 1 && OPENH264_MINOR < 6
824 slice_mode = SM_AUTO_SLICE;
825 #else
826 slice_mode = SM_FIXEDSLCNUM_SLICE;
827 n_slices = 0;
828 #endif
829 } else {
830 GST_ERROR_OBJECT (openh264enc, "unexpected slice mode %d",
831 openh264enc->slice_mode);
832 slice_mode = SM_SINGLE_SLICE;
833 }
834
835 #if OPENH264_MAJOR == 1 && OPENH264_MINOR < 6
836 enc_params.sSpatialLayers[0].sSliceCfg.uiSliceMode = slice_mode;
837 enc_params.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = n_slices;
838 #else
839 enc_params.sSpatialLayers[0].sSliceArgument.uiSliceMode = slice_mode;
840 enc_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = n_slices;
841 #endif
842
843 openh264enc->framerate = (1 + fps_n / fps_d);
844
845 ret = openh264enc->encoder->InitializeExt (&enc_params);
846
847 openh264enc->bitrate_changed = FALSE;
848 openh264enc->max_bitrate_changed = FALSE;
849
850 GST_OBJECT_UNLOCK (openh264enc);
851
852 if (ret != cmResultSuccess) {
853 GST_ERROR_OBJECT (openh264enc, "failed to initialize encoder");
854 return FALSE;
855 }
856
857 openh264enc->encoder->SetOption (ENCODER_OPTION_DATAFORMAT, &video_format);
858
859 output_state = gst_video_encoder_set_output_state (encoder, outcaps, state);
860 gst_video_codec_state_unref (output_state);
861
862 return gst_video_encoder_negotiate (encoder);
863 }
864
865 static gboolean
gst_openh264enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)866 gst_openh264enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
867 {
868 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
869
870 return
871 GST_VIDEO_ENCODER_CLASS
872 (gst_openh264enc_parent_class)->propose_allocation (encoder, query);
873 }
874
875 static GstFlowReturn
gst_openh264enc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)876 gst_openh264enc_handle_frame (GstVideoEncoder * encoder,
877 GstVideoCodecFrame * frame)
878 {
879 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
880 SSourcePicture *src_pic = NULL;
881 GstVideoFrame video_frame;
882 gboolean force_keyframe;
883 gint ret;
884 SFrameBSInfo frame_info;
885 gfloat fps;
886 gint i, j;
887 gsize buf_length = 0;
888
889 GST_OBJECT_LOCK (openh264enc);
890
891 if (openh264enc->bitrate_changed || openh264enc->max_bitrate_changed) {
892 SEncParamExt enc_params;
893 if (openh264enc->encoder->GetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
894 &enc_params) == cmResultSuccess) {
895 if (openh264enc->bitrate_changed) {
896 enc_params.iTargetBitrate = openh264enc->bitrate;
897 enc_params.sSpatialLayers[0].iSpatialBitrate =
898 enc_params.iTargetBitrate;
899 }
900 if (openh264enc->max_bitrate_changed) {
901 enc_params.iMaxBitrate = openh264enc->max_bitrate;
902 enc_params.sSpatialLayers[0].iMaxSpatialBitrate =
903 enc_params.iMaxBitrate;
904 }
905 if (openh264enc->encoder->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
906 &enc_params) != cmResultSuccess) {
907 GST_WARNING_OBJECT (openh264enc,
908 "Error changing bitrate/max bitrate, unable to set new enc_params");
909 }
910 } else {
911 GST_WARNING_OBJECT (openh264enc,
912 "Error changing bitrate/max bitrate, unable to get enc_params");
913 }
914 openh264enc->bitrate_changed = FALSE;
915 openh264enc->max_bitrate_changed = FALSE;
916 }
917
918 GST_OBJECT_UNLOCK (openh264enc);
919
920 if (frame) {
921 src_pic = new SSourcePicture;
922
923 if (src_pic == NULL) {
924 if (frame)
925 gst_video_codec_frame_unref (frame);
926 return GST_FLOW_ERROR;
927 }
928 //fill default src_pic
929 src_pic->iColorFormat = videoFormatI420;
930 src_pic->uiTimeStamp = frame->pts / GST_MSECOND;
931 }
932
933 openh264enc->frame_count++;
934 if (frame) {
935 if (G_UNLIKELY (openh264enc->frame_count == 1)) {
936 openh264enc->time_per_frame = (GST_SECOND / openh264enc->framerate);
937 openh264enc->previous_timestamp = frame->pts;
938 } else {
939 openh264enc->time_per_frame = (guint64)
940 (openh264enc->time_per_frame * 0.8 + (frame->pts -
941 openh264enc->previous_timestamp) * 0.2);
942 openh264enc->previous_timestamp = frame->pts;
943 if (openh264enc->frame_count % 10 == 0) {
944 fps = GST_SECOND / (gdouble) openh264enc->time_per_frame;
945 openh264enc->encoder->SetOption (ENCODER_OPTION_FRAME_RATE, &fps);
946 }
947 }
948 }
949
950 if (frame) {
951 gst_video_frame_map (&video_frame, &openh264enc->input_state->info,
952 frame->input_buffer, GST_MAP_READ);
953 src_pic->iPicWidth = GST_VIDEO_FRAME_WIDTH (&video_frame);
954 src_pic->iPicHeight = GST_VIDEO_FRAME_HEIGHT (&video_frame);
955 src_pic->iStride[0] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 0);
956 src_pic->iStride[1] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 1);
957 src_pic->iStride[2] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 2);
958 src_pic->pData[0] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 0);
959 src_pic->pData[1] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 1);
960 src_pic->pData[2] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 2);
961
962 force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
963 if (force_keyframe) {
964 openh264enc->encoder->ForceIntraFrame (true);
965 GST_DEBUG_OBJECT (openh264enc,
966 "Got force key unit event, next frame coded as intra picture");
967 }
968 }
969
970 memset (&frame_info, 0, sizeof (SFrameBSInfo));
971 ret = openh264enc->encoder->EncodeFrame (src_pic, &frame_info);
972 if (ret != cmResultSuccess) {
973 if (frame) {
974 gst_video_frame_unmap (&video_frame);
975 gst_video_codec_frame_unref (frame);
976 delete src_pic;
977 GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE,
978 ("Could not encode frame"), ("Openh264 returned %d", ret));
979 return GST_FLOW_ERROR;
980 } else {
981 return GST_FLOW_EOS;
982 }
983 }
984
985 if (videoFrameTypeSkip == frame_info.eFrameType) {
986 if (frame) {
987 gst_video_frame_unmap (&video_frame);
988 gst_video_encoder_finish_frame (encoder, frame);
989 delete src_pic;
990 }
991
992 return GST_FLOW_OK;
993 }
994
995 if (frame) {
996 gst_video_frame_unmap (&video_frame);
997 gst_video_codec_frame_unref (frame);
998 delete src_pic;
999 src_pic = NULL;
1000 frame = NULL;
1001 }
1002
1003 /* FIXME: openh264 has no way for us to get a connection
1004 * between the input and output frames, we just have to
1005 * guess based on the input */
1006 frame = gst_video_encoder_get_oldest_frame (encoder);
1007 if (!frame) {
1008 GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE,
1009 ("Could not encode frame"), ("openh264enc returned %d", ret));
1010 gst_video_codec_frame_unref (frame);
1011 return GST_FLOW_ERROR;
1012 }
1013
1014 if (videoFrameTypeIDR == frame_info.eFrameType) {
1015 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1016 } else {
1017 GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
1018 }
1019
1020 for (i = 0; i < frame_info.iLayerNum; i++) {
1021 for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) {
1022 buf_length += frame_info.sLayerInfo[i].pNalLengthInByte[j];
1023 }
1024 }
1025
1026 frame->output_buffer =
1027 gst_video_encoder_allocate_output_buffer (encoder, buf_length);
1028
1029
1030 buf_length = 0;
1031 for (i = 0; i < frame_info.iLayerNum; i++) {
1032 gsize layer_size = 0;
1033 for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) {
1034 layer_size += frame_info.sLayerInfo[i].pNalLengthInByte[j];
1035 }
1036 gst_buffer_fill (frame->output_buffer, buf_length, frame_info.sLayerInfo[i].pBsBuf, layer_size);
1037 buf_length += layer_size;
1038 }
1039
1040 GST_LOG_OBJECT (openh264enc, "openh264 picture %scoded OK!",
1041 (ret != cmResultSuccess) ? "NOT " : "");
1042
1043 return gst_video_encoder_finish_frame (encoder, frame);
1044 }
1045
1046 static GstFlowReturn
gst_openh264enc_finish(GstVideoEncoder * encoder)1047 gst_openh264enc_finish (GstVideoEncoder * encoder)
1048 {
1049 GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder);
1050
1051 if (openh264enc->frame_count == 0)
1052 return GST_FLOW_OK;
1053
1054 /* Drain encoder */
1055 while ((gst_openh264enc_handle_frame (encoder, NULL)) == GST_FLOW_OK);
1056
1057 return GST_FLOW_OK;
1058 }
1059 static gboolean
openh264enc_element_init(GstPlugin * plugin)1060 openh264enc_element_init (GstPlugin * plugin)
1061 {
1062 if (openh264_element_init (plugin))
1063 return gst_element_register (plugin, "openh264enc", GST_RANK_MARGINAL,
1064 GST_TYPE_OPENH264ENC);
1065
1066 GST_ERROR ("Incorrect library version loaded, expecting %s", g_strCodecVer);
1067 return FALSE;
1068 }
1069