2 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation
8 * version 2.1 of the License.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "gstomxh264enc.h"
28 #include "gstomxh264utils.h"
30 #ifdef USE_OMX_TARGET_RPI
31 #include <OMX_Broadcom.h>
32 #include <OMX_Index.h>
35 GST_DEBUG_CATEGORY_STATIC (gst_omx_h264_enc_debug_category);
36 #define GST_CAT_DEFAULT gst_omx_h264_enc_debug_category
39 static gboolean gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc,
40 GstOMXPort * port, GstVideoCodecState * state);
41 static GstCaps *gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc,
42 GstOMXPort * port, GstVideoCodecState * state);
43 static GstFlowReturn gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc *
44 self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
45 static gboolean gst_omx_h264_enc_flush (GstVideoEncoder * enc);
46 static gboolean gst_omx_h264_enc_stop (GstVideoEncoder * enc);
47 static void gst_omx_h264_enc_set_property (GObject * object, guint prop_id,
48 const GValue * value, GParamSpec * pspec);
49 static void gst_omx_h264_enc_get_property (GObject * object, guint prop_id,
50 GValue * value, GParamSpec * pspec);
55 #ifdef USE_OMX_TARGET_RPI
56 PROP_INLINESPSPPSHEADERS,
58 PROP_PERIODICITYOFIDRFRAMES,
59 PROP_PERIODICITYOFIDRFRAMES_COMPAT,
60 PROP_INTERVALOFCODINGINTRAFRAMES,
63 PROP_CONSTRAINED_INTRA_PREDICTION,
64 PROP_LOOP_FILTER_MODE,
68 #ifdef USE_OMX_TARGET_RPI
69 #define GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT TRUE
71 #define GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT (0xffffffff)
72 #define GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
73 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
74 #define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0)
75 #define ALIGNMENT "{ au, nal }"
77 #define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
78 #define ALIGNMENT "au"
80 #define GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT (0xffffffff)
81 #define GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT (FALSE)
82 #define GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT (0xffffffff)
83 #define GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT 0
84 #define GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MIN 0
85 #define GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MAX 16
87 /* class initialization */
90 GST_DEBUG_CATEGORY_INIT (gst_omx_h264_enc_debug_category, "omxh264enc", 0, \
91 "debug category for gst-omx video encoder base class");
93 #define parent_class gst_omx_h264_enc_parent_class
94 G_DEFINE_TYPE_WITH_CODE (GstOMXH264Enc, gst_omx_h264_enc,
95 GST_TYPE_OMX_VIDEO_ENC, DEBUG_INIT);
97 #define GST_TYPE_OMX_H264_ENC_ENTROPY_MODE (gst_omx_h264_enc_entropy_mode_get_type ())
99 gst_omx_h264_enc_entropy_mode_get_type (void)
101 static GType qtype = 0;
104 static const GEnumValue values[] = {
105 {FALSE, "CAVLC entropy mode", "CAVLC"},
106 {TRUE, "CABAC entropy mode", "CABAC"},
107 {0xffffffff, "Component Default", "default"},
111 qtype = g_enum_register_static ("GstOMXH264EncEntropyMode", values);
116 #define GST_TYPE_OMX_H264_ENC_LOOP_FILTER_MODE (gst_omx_h264_enc_loop_filter_mode_get_type ())
118 gst_omx_h264_enc_loop_filter_mode_get_type (void)
120 static GType qtype = 0;
123 static const GEnumValue values[] = {
124 {OMX_VIDEO_AVCLoopFilterEnable, "Enable deblocking filter", "enable"},
125 {OMX_VIDEO_AVCLoopFilterDisable, "Disable deblocking filter", "disable"},
126 {OMX_VIDEO_AVCLoopFilterDisableSliceBoundary,
127 "Disables deblocking filter on slice boundary",
128 "disable-slice-boundary"},
129 {0xffffffff, "Component Default", "default"},
133 qtype = g_enum_register_static ("GstOMXH264EncLoopFilter", values);
139 gst_omx_h264_enc_class_init (GstOMXH264EncClass * klass)
141 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
142 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
143 GstVideoEncoderClass *basevideoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
144 GstOMXVideoEncClass *videoenc_class = GST_OMX_VIDEO_ENC_CLASS (klass);
146 videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_h264_enc_set_format);
147 videoenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_h264_enc_get_caps);
149 gobject_class->set_property = gst_omx_h264_enc_set_property;
150 gobject_class->get_property = gst_omx_h264_enc_get_property;
152 #ifdef USE_OMX_TARGET_RPI
153 g_object_class_install_property (gobject_class, PROP_INLINESPSPPSHEADERS,
154 g_param_spec_boolean ("inline-header",
155 "Inline SPS/PPS headers before IDR",
156 "Inline SPS/PPS header before IDR",
157 GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT,
158 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
159 GST_PARAM_MUTABLE_READY));
162 g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES,
163 g_param_spec_uint ("periodicity-idr", "IDR periodicity",
164 "Periodicity of IDR frames (0xffffffff=component default)",
166 GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
167 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
168 GST_PARAM_MUTABLE_READY));
170 g_object_class_install_property (gobject_class,
171 PROP_PERIODICITYOFIDRFRAMES_COMPAT, g_param_spec_uint ("periodicty-idr",
173 "Periodicity of IDR frames (0xffffffff=component default) DEPRECATED - only for backwards compat",
175 GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
176 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
177 GST_PARAM_MUTABLE_READY));
179 g_object_class_install_property (gobject_class,
180 PROP_INTERVALOFCODINGINTRAFRAMES,
181 g_param_spec_uint ("interval-intraframes",
182 "Interval of coding Intra frames",
183 "Interval of coding Intra frames (0xffffffff=component default)", 0,
185 GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT,
186 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
187 GST_PARAM_MUTABLE_READY));
189 g_object_class_install_property (gobject_class, PROP_B_FRAMES,
190 g_param_spec_uint ("b-frames", "Number of B-frames",
191 "Number of B-frames between two consecutive I-frames (0xffffffff=component default)",
192 0, G_MAXUINT, GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT,
193 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
194 GST_PARAM_MUTABLE_READY));
196 g_object_class_install_property (gobject_class, PROP_ENTROPY_MODE,
197 g_param_spec_enum ("entropy-mode", "Entropy Mode",
198 "Entropy mode for encoding process",
199 GST_TYPE_OMX_H264_ENC_ENTROPY_MODE,
200 GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT,
201 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
202 GST_PARAM_MUTABLE_READY));
204 g_object_class_install_property (gobject_class,
205 PROP_CONSTRAINED_INTRA_PREDICTION,
206 g_param_spec_boolean ("constrained-intra-prediction",
207 "Constrained Intra Prediction",
208 "If enabled, prediction only uses residual data and decoded samples "
209 "from neighbouring coding blocks coded using intra prediction modes",
210 GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT,
211 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
212 GST_PARAM_MUTABLE_READY));
214 g_object_class_install_property (gobject_class, PROP_LOOP_FILTER_MODE,
215 g_param_spec_enum ("loop-filter-mode", "Loop Filter mode",
216 "Enable or disable the deblocking filter (0xffffffff=component default)",
217 GST_TYPE_OMX_H264_ENC_LOOP_FILTER_MODE,
218 GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT,
219 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
220 GST_PARAM_MUTABLE_READY));
222 g_object_class_install_property (gobject_class, PROP_REF_FRAMES,
223 g_param_spec_uchar ("ref-frames", "Reference frames",
224 "Number of reference frames used for inter-motion search (0=component default)",
225 GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MIN,
226 GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MAX,
227 GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT,
228 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
229 GST_PARAM_MUTABLE_READY));
231 basevideoenc_class->flush = gst_omx_h264_enc_flush;
232 basevideoenc_class->stop = gst_omx_h264_enc_stop;
234 videoenc_class->cdata.default_src_template_caps = "video/x-h264, "
235 "width = (int) [ 16, 4096 ], height = (int) [ 16, 4096 ], "
236 "framerate = (fraction) [0, MAX], stream-format=(string) byte-stream, "
237 "alignment = (string) " ALIGNMENT;
238 videoenc_class->handle_output_frame =
239 GST_DEBUG_FUNCPTR (gst_omx_h264_enc_handle_output_frame);
241 gst_element_class_set_static_metadata (element_class,
242 "OpenMAX H.264 Video Encoder",
243 "Codec/Encoder/Video/Hardware",
244 "Encode H.264 video streams",
245 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
247 gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.avc");
251 gst_omx_h264_enc_set_property (GObject * object, guint prop_id,
252 const GValue * value, GParamSpec * pspec)
254 GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
257 #ifdef USE_OMX_TARGET_RPI
258 case PROP_INLINESPSPPSHEADERS:
259 self->inline_sps_pps_headers = g_value_get_boolean (value);
262 case PROP_PERIODICITYOFIDRFRAMES:
263 case PROP_PERIODICITYOFIDRFRAMES_COMPAT:
264 self->periodicty_idr = g_value_get_uint (value);
266 case PROP_INTERVALOFCODINGINTRAFRAMES:
267 self->interval_intraframes = g_value_get_uint (value);
270 self->b_frames = g_value_get_uint (value);
272 case PROP_ENTROPY_MODE:
273 self->entropy_mode = g_value_get_enum (value);
275 case PROP_CONSTRAINED_INTRA_PREDICTION:
276 self->constrained_intra_prediction = g_value_get_boolean (value);
278 case PROP_LOOP_FILTER_MODE:
279 self->loop_filter_mode = g_value_get_enum (value);
281 case PROP_REF_FRAMES:
282 self->ref_frames = g_value_get_uchar (value);
285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291 gst_omx_h264_enc_get_property (GObject * object, guint prop_id, GValue * value,
294 GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
297 #ifdef USE_OMX_TARGET_RPI
298 case PROP_INLINESPSPPSHEADERS:
299 g_value_set_boolean (value, self->inline_sps_pps_headers);
302 case PROP_PERIODICITYOFIDRFRAMES:
303 case PROP_PERIODICITYOFIDRFRAMES_COMPAT:
304 g_value_set_uint (value, self->periodicty_idr);
306 case PROP_INTERVALOFCODINGINTRAFRAMES:
307 g_value_set_uint (value, self->interval_intraframes);
310 g_value_set_uint (value, self->b_frames);
312 case PROP_ENTROPY_MODE:
313 g_value_set_enum (value, self->entropy_mode);
315 case PROP_CONSTRAINED_INTRA_PREDICTION:
316 g_value_set_boolean (value, self->constrained_intra_prediction);
318 case PROP_LOOP_FILTER_MODE:
319 g_value_set_enum (value, self->loop_filter_mode);
321 case PROP_REF_FRAMES:
322 g_value_set_uchar (value, self->ref_frames);
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
331 gst_omx_h264_enc_init (GstOMXH264Enc * self)
333 #ifdef USE_OMX_TARGET_RPI
334 self->inline_sps_pps_headers =
335 GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT;
337 self->periodicty_idr =
338 GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT;
339 self->interval_intraframes =
340 GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT;
341 self->b_frames = GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT;
342 self->entropy_mode = GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT;
343 self->constrained_intra_prediction =
344 GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT;
345 self->loop_filter_mode = GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT;
346 self->ref_frames = GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT;
350 gst_omx_h264_enc_flush (GstVideoEncoder * enc)
352 GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
354 g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
355 self->headers = NULL;
357 return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (enc);
361 gst_omx_h264_enc_stop (GstVideoEncoder * enc)
363 GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
365 g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
366 self->headers = NULL;
368 return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc);
371 /* Update OMX_VIDEO_PARAM_PROFILELEVELTYPE.{eProfile,eLevel}
373 * Returns TRUE if succeeded or if not supported, FALSE if failed */
375 update_param_profile_level (GstOMXH264Enc * self,
376 OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level)
378 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
381 GST_OMX_INIT_STRUCT (¶m);
382 param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
385 gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
386 OMX_IndexParamVideoProfileLevelCurrent, ¶m);
387 if (err != OMX_ErrorNone) {
388 GST_WARNING_OBJECT (self,
389 "Getting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
393 if (profile != OMX_VIDEO_AVCProfileMax)
394 param.eProfile = profile;
395 if (level != OMX_VIDEO_AVCLevelMax)
396 param.eLevel = level;
399 gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
400 OMX_IndexParamVideoProfileLevelCurrent, ¶m);
401 if (err == OMX_ErrorUnsupportedIndex) {
402 GST_WARNING_OBJECT (self,
403 "Setting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
405 } else if (err != OMX_ErrorNone) {
406 GST_ERROR_OBJECT (self,
407 "Error setting profile %u and level %u: %s (0x%08x)",
408 (guint) param.eProfile, (guint) param.eLevel,
409 gst_omx_error_to_string (err), err);
416 /* Update OMX_VIDEO_PARAM_AVCTYPE
418 * Returns TRUE if succeeded or if not supported, FALSE if failed */
420 update_param_avc (GstOMXH264Enc * self,
421 OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level)
423 OMX_VIDEO_PARAM_AVCTYPE param;
426 GST_OMX_INIT_STRUCT (¶m);
427 param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
429 /* On Android the param struct is initialized manually with default
430 * settings rather than using GetParameter() to retrieve them.
431 * We should probably do the same when we'll add Android as target.
432 * See bgo#783862 for details. */
435 gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
436 OMX_IndexParamVideoAvc, ¶m);
437 if (err != OMX_ErrorNone) {
438 GST_WARNING_OBJECT (self,
439 "Getting OMX_IndexParamVideoAvc not supported by component");
443 if (profile != OMX_VIDEO_AVCProfileMax)
444 param.eProfile = profile;
445 if (level != OMX_VIDEO_AVCLevelMax)
446 param.eLevel = level;
449 if (self->interval_intraframes !=
450 GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
451 param.nPFrames = self->interval_intraframes;
453 /* If user specified a specific number of B-frames, reduce the number of
454 * P-frames by this amount. If not ensure there is no B-frame to have the
455 * requested GOP length. */
456 if (self->b_frames != GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT) {
457 if (self->b_frames > self->interval_intraframes) {
458 GST_ERROR_OBJECT (self,
459 "The interval_intraframes perdiod (%u) needs to be higher than the number of B-frames (%u)",
460 self->interval_intraframes, self->b_frames);
463 param.nPFrames -= self->b_frames;
469 if (self->b_frames != GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT) {
470 if (profile == OMX_VIDEO_AVCProfileBaseline && self->b_frames > 0) {
471 GST_ERROR_OBJECT (self,
472 "Baseline profile doesn't support B-frames (%u requested)",
476 param.nBFrames = self->b_frames;
479 if (self->ref_frames != GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT)
480 param.nRefFrames = self->ref_frames;
482 if (self->entropy_mode != GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT) {
483 param.bEntropyCodingCABAC = self->entropy_mode;
486 param.bconstIpred = self->constrained_intra_prediction;
488 if (self->loop_filter_mode != GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT) {
489 param.eLoopFilterMode = self->loop_filter_mode;
493 gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
494 OMX_IndexParamVideoAvc, ¶m);
495 if (err == OMX_ErrorUnsupportedIndex) {
496 GST_WARNING_OBJECT (self,
497 "Setting OMX_IndexParamVideoAvc not supported by component");
499 } else if (err != OMX_ErrorNone) {
500 GST_ERROR_OBJECT (self,
501 "Error setting AVC settings (profile %u and level %u): %s (0x%08x)",
502 (guint) param.eProfile, (guint) param.eLevel,
503 gst_omx_error_to_string (err), err);
511 set_avc_intra_period (GstOMXH264Enc * self)
513 OMX_VIDEO_CONFIG_AVCINTRAPERIOD config_avcintraperiod;
516 GST_OMX_INIT_STRUCT (&config_avcintraperiod);
517 config_avcintraperiod.nPortIndex =
518 GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
520 gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
521 OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod);
522 if (err == OMX_ErrorUnsupportedIndex) {
523 GST_WARNING_OBJECT (self,
524 "OMX_IndexConfigVideoAVCIntraPeriod not supported by component");
526 } else if (err != OMX_ErrorNone) {
527 GST_ERROR_OBJECT (self,
528 "can't get OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
529 gst_omx_error_to_string (err), err);
533 GST_DEBUG_OBJECT (self, "default nPFrames:%u, nIDRPeriod:%u",
534 (guint) config_avcintraperiod.nPFrames,
535 (guint) config_avcintraperiod.nIDRPeriod);
537 if (self->periodicty_idr !=
538 GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT) {
539 config_avcintraperiod.nIDRPeriod = self->periodicty_idr;
542 if (self->interval_intraframes !=
543 GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
544 /* This OMX API doesn't allow us to specify the number of B-frames.
545 * So if user requested one we have to rely on update_param_avc()
546 * to configure the intraframes interval so it can take the
547 * B-frames into account. */
548 if (self->b_frames == GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT)
549 config_avcintraperiod.nPFrames = self->interval_intraframes;
553 gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
554 OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod);
555 if (err != OMX_ErrorNone) {
556 GST_ERROR_OBJECT (self,
557 "can't set OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
558 gst_omx_error_to_string (err), err);
565 #ifdef USE_OMX_TARGET_RPI
567 set_brcm_video_intra_period (GstOMXH264Enc * self)
569 OMX_PARAM_U32TYPE intra_period;
572 GST_OMX_INIT_STRUCT (&intra_period);
574 intra_period.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
576 gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
577 OMX_IndexConfigBrcmVideoIntraPeriod, &intra_period);
578 if (err != OMX_ErrorNone) {
579 GST_ERROR_OBJECT (self,
580 "can't get OMX_IndexConfigBrcmVideoIntraPeriod %s (0x%08x)",
581 gst_omx_error_to_string (err), err);
585 GST_DEBUG_OBJECT (self, "default OMX_IndexConfigBrcmVideoIntraPeriod: %u",
586 (guint) intra_period.nU32);
588 if (self->interval_intraframes ==
589 GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT)
592 intra_period.nU32 = self->interval_intraframes;
595 gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
596 OMX_IndexConfigBrcmVideoIntraPeriod, &intra_period);
597 if (err != OMX_ErrorNone) {
598 GST_ERROR_OBJECT (self,
599 "can't set OMX_IndexConfigBrcmVideoIntraPeriod %s (0x%08x)",
600 gst_omx_error_to_string (err), err);
604 GST_DEBUG_OBJECT (self, "OMX_IndexConfigBrcmVideoIntraPeriod set to %u",
605 (guint) intra_period.nU32);
612 gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
613 GstVideoCodecState * state)
615 GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
617 OMX_PARAM_PORTDEFINITIONTYPE port_def;
618 #ifdef USE_OMX_TARGET_RPI
619 OMX_CONFIG_PORTBOOLEANTYPE config_inline_header;
622 const gchar *profile_string, *level_string;
623 OMX_VIDEO_AVCPROFILETYPE profile = OMX_VIDEO_AVCProfileMax;
624 OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevelMax;
625 gboolean enable_subframe = FALSE;
627 #ifdef USE_OMX_TARGET_RPI
628 GST_OMX_INIT_STRUCT (&config_inline_header);
629 config_inline_header.nPortIndex =
630 GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
632 gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
633 OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header);
634 if (err != OMX_ErrorNone) {
635 GST_ERROR_OBJECT (self,
636 "can't get OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)",
637 gst_omx_error_to_string (err), err);
641 if (self->inline_sps_pps_headers) {
642 config_inline_header.bEnabled = OMX_TRUE;
644 config_inline_header.bEnabled = OMX_FALSE;
648 gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
649 OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header);
650 if (err != OMX_ErrorNone) {
651 GST_ERROR_OBJECT (self,
652 "can't set OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)",
653 gst_omx_error_to_string (err), err);
658 /* Configure GOP pattern */
659 if (self->periodicty_idr !=
660 GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT
661 || self->interval_intraframes !=
662 GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
663 set_avc_intra_period (self);
665 #ifdef USE_OMX_TARGET_RPI
666 /* The Pi uses a specific OMX setting to configure the intra period */
668 if (self->interval_intraframes)
669 set_brcm_video_intra_period (self);
672 gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
674 port_def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
676 gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
677 (self)->enc_out_port, &port_def);
678 if (err != OMX_ErrorNone)
681 /* Set profile and level */
682 peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc),
683 gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc)));
686 const gchar *alignment_string;
688 if (gst_caps_is_empty (peercaps)) {
689 gst_caps_unref (peercaps);
690 GST_ERROR_OBJECT (self, "Empty caps");
694 s = gst_caps_get_structure (peercaps, 0);
695 profile_string = gst_structure_get_string (s, "profile");
696 if (profile_string) {
697 profile = gst_omx_h264_utils_get_profile_from_str (profile_string);
698 if (profile == OMX_VIDEO_AVCProfileMax)
699 goto unsupported_profile;
701 level_string = gst_structure_get_string (s, "level");
703 level = gst_omx_h264_utils_get_level_from_str (level_string);
704 if (level == OMX_VIDEO_AVCLevelMax)
705 goto unsupported_level;
708 alignment_string = gst_structure_get_string (s, "alignment");
709 if (alignment_string && g_str_equal (alignment_string, "nal"))
710 enable_subframe = TRUE;
712 gst_caps_unref (peercaps);
715 if (profile != OMX_VIDEO_AVCProfileMax || level != OMX_VIDEO_AVCLevelMax) {
716 /* OMX provides 2 API to set the profile and level. We try using the
717 * generic one here and the H264 specific when calling
718 * update_param_avc() */
719 if (!update_param_profile_level (self, profile, level))
723 gst_omx_port_set_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port,
726 if (!update_param_avc (self, profile, level))
732 GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
733 gst_caps_unref (peercaps);
737 GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
738 gst_caps_unref (peercaps);
743 gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
744 GstVideoCodecState * state)
746 GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
749 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
750 const gchar *profile, *level, *alignment;
752 GST_OMX_INIT_STRUCT (¶m);
753 param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
756 gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
757 OMX_IndexParamVideoProfileLevelCurrent, ¶m);
758 if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
761 if (gst_omx_port_get_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port))
766 caps = gst_caps_new_simple ("video/x-h264",
767 "stream-format", G_TYPE_STRING, "byte-stream",
768 "alignment", G_TYPE_STRING, alignment, NULL);
770 if (err == OMX_ErrorNone) {
771 profile = gst_omx_h264_utils_get_profile_from_enum (param.eProfile);
773 g_assert_not_reached ();
774 gst_caps_unref (caps);
778 switch (param.eLevel) {
779 case OMX_VIDEO_AVCLevel1:
782 case OMX_VIDEO_AVCLevel1b:
785 case OMX_VIDEO_AVCLevel11:
788 case OMX_VIDEO_AVCLevel12:
791 case OMX_VIDEO_AVCLevel13:
794 case OMX_VIDEO_AVCLevel2:
797 case OMX_VIDEO_AVCLevel21:
800 case OMX_VIDEO_AVCLevel22:
803 case OMX_VIDEO_AVCLevel3:
806 case OMX_VIDEO_AVCLevel31:
809 case OMX_VIDEO_AVCLevel32:
812 case OMX_VIDEO_AVCLevel4:
815 case OMX_VIDEO_AVCLevel41:
818 case OMX_VIDEO_AVCLevel42:
821 case OMX_VIDEO_AVCLevel5:
824 case OMX_VIDEO_AVCLevel51:
827 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
828 case OMX_ALG_VIDEO_AVCLevel52:
831 case OMX_ALG_VIDEO_AVCLevel60:
834 case OMX_ALG_VIDEO_AVCLevel61:
837 case OMX_ALG_VIDEO_AVCLevel62:
842 g_assert_not_reached ();
843 gst_caps_unref (caps);
846 gst_caps_set_simple (caps,
847 "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level, NULL);
854 gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * enc, GstOMXPort * port,
855 GstOMXBuffer * buf, GstVideoCodecFrame * frame)
857 GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
859 if (buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
860 /* The codec data is SPS/PPS but our output is stream-format=byte-stream.
861 * For bytestream stream format the SPS/PPS is only in-stream and not
865 GstMapInfo map = GST_MAP_INFO_INIT;
866 GstFlowReturn flow_ret;
868 GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
870 hdrs = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
871 GST_BUFFER_FLAG_SET (hdrs, GST_BUFFER_FLAG_HEADER);
873 gst_buffer_map (hdrs, &map, GST_MAP_WRITE);
875 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
876 buf->omx_buf->nFilledLen);
877 gst_buffer_unmap (hdrs, &map);
878 self->headers = g_list_append (self->headers, gst_buffer_ref (hdrs));
879 frame->output_buffer = hdrs;
881 gst_video_encoder_finish_subframe (GST_VIDEO_ENCODER (self), frame);
882 gst_video_codec_frame_unref (frame);
885 } else if (self->headers) {
886 gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), self->headers);
887 self->headers = NULL;
891 GST_OMX_VIDEO_ENC_CLASS
892 (gst_omx_h264_enc_parent_class)->handle_output_frame (enc, port, buf,