omxvideodec: support interlace-mode=interleaved input
[platform/upstream/gstreamer.git] / omx / gstomxh264enc.c
1 /*
2  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gst.h>
26
27 #include "gstomxh264enc.h"
28 #include "gstomxh264utils.h"
29
30 #ifdef USE_OMX_TARGET_RPI
31 #include <OMX_Broadcom.h>
32 #include <OMX_Index.h>
33 #endif
34
35 GST_DEBUG_CATEGORY_STATIC (gst_omx_h264_enc_debug_category);
36 #define GST_CAT_DEFAULT gst_omx_h264_enc_debug_category
37
38 /* prototypes */
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);
51
52 enum
53 {
54   PROP_0,
55 #ifdef USE_OMX_TARGET_RPI
56   PROP_INLINESPSPPSHEADERS,
57 #endif
58   PROP_PERIODICITYOFIDRFRAMES,
59   PROP_PERIODICITYOFIDRFRAMES_COMPAT,
60   PROP_INTERVALOFCODINGINTRAFRAMES,
61   PROP_B_FRAMES,
62   PROP_ENTROPY_MODE,
63   PROP_CONSTRAINED_INTRA_PREDICTION,
64   PROP_LOOP_FILTER_MODE,
65   PROP_REF_FRAMES
66 };
67
68 #ifdef USE_OMX_TARGET_RPI
69 #define GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT      TRUE
70 #endif
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 }"
76 #else
77 #define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
78 #define ALIGNMENT "au"
79 #endif
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
86
87 /* class initialization */
88
89 #define DEBUG_INIT \
90   GST_DEBUG_CATEGORY_INIT (gst_omx_h264_enc_debug_category, "omxh264enc", 0, \
91       "debug category for gst-omx video encoder base class");
92
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);
96
97 #define GST_TYPE_OMX_H264_ENC_ENTROPY_MODE (gst_omx_h264_enc_entropy_mode_get_type ())
98 static GType
99 gst_omx_h264_enc_entropy_mode_get_type (void)
100 {
101   static GType qtype = 0;
102
103   if (qtype == 0) {
104     static const GEnumValue values[] = {
105       {FALSE, "CAVLC entropy mode", "CAVLC"},
106       {TRUE, "CABAC entropy mode", "CABAC"},
107       {0xffffffff, "Component Default", "default"},
108       {0, NULL, NULL}
109     };
110
111     qtype = g_enum_register_static ("GstOMXH264EncEntropyMode", values);
112   }
113   return qtype;
114 }
115
116 #define GST_TYPE_OMX_H264_ENC_LOOP_FILTER_MODE (gst_omx_h264_enc_loop_filter_mode_get_type ())
117 static GType
118 gst_omx_h264_enc_loop_filter_mode_get_type (void)
119 {
120   static GType qtype = 0;
121
122   if (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"},
130       {0, NULL, NULL}
131     };
132
133     qtype = g_enum_register_static ("GstOMXH264EncLoopFilter", values);
134   }
135   return qtype;
136 }
137
138 static void
139 gst_omx_h264_enc_class_init (GstOMXH264EncClass * klass)
140 {
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);
145
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);
148
149   gobject_class->set_property = gst_omx_h264_enc_set_property;
150   gobject_class->get_property = gst_omx_h264_enc_get_property;
151
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));
160 #endif
161
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)",
165           0, G_MAXUINT,
166           GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
167           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
168           GST_PARAM_MUTABLE_READY));
169
170   g_object_class_install_property (gobject_class,
171       PROP_PERIODICITYOFIDRFRAMES_COMPAT, g_param_spec_uint ("periodicty-idr",
172           "IDR periodicity",
173           "Periodicity of IDR frames (0xffffffff=component default) DEPRECATED - only for backwards compat",
174           0, G_MAXUINT,
175           GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
176           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
177           GST_PARAM_MUTABLE_READY));
178
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,
184           G_MAXUINT,
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));
188
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));
195
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));
203
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));
213
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));
221
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));
230
231   basevideoenc_class->flush = gst_omx_h264_enc_flush;
232   basevideoenc_class->stop = gst_omx_h264_enc_stop;
233
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);
240
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>");
246
247   gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.avc");
248 }
249
250 static void
251 gst_omx_h264_enc_set_property (GObject * object, guint prop_id,
252     const GValue * value, GParamSpec * pspec)
253 {
254   GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
255
256   switch (prop_id) {
257 #ifdef USE_OMX_TARGET_RPI
258     case PROP_INLINESPSPPSHEADERS:
259       self->inline_sps_pps_headers = g_value_get_boolean (value);
260       break;
261 #endif
262     case PROP_PERIODICITYOFIDRFRAMES:
263     case PROP_PERIODICITYOFIDRFRAMES_COMPAT:
264       self->periodicty_idr = g_value_get_uint (value);
265       break;
266     case PROP_INTERVALOFCODINGINTRAFRAMES:
267       self->interval_intraframes = g_value_get_uint (value);
268       break;
269     case PROP_B_FRAMES:
270       self->b_frames = g_value_get_uint (value);
271       break;
272     case PROP_ENTROPY_MODE:
273       self->entropy_mode = g_value_get_enum (value);
274       break;
275     case PROP_CONSTRAINED_INTRA_PREDICTION:
276       self->constrained_intra_prediction = g_value_get_boolean (value);
277       break;
278     case PROP_LOOP_FILTER_MODE:
279       self->loop_filter_mode = g_value_get_enum (value);
280       break;
281     case PROP_REF_FRAMES:
282       self->ref_frames = g_value_get_uchar (value);
283       break;
284     default:
285       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286       break;
287   }
288 }
289
290 static void
291 gst_omx_h264_enc_get_property (GObject * object, guint prop_id, GValue * value,
292     GParamSpec * pspec)
293 {
294   GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
295
296   switch (prop_id) {
297 #ifdef USE_OMX_TARGET_RPI
298     case PROP_INLINESPSPPSHEADERS:
299       g_value_set_boolean (value, self->inline_sps_pps_headers);
300       break;
301 #endif
302     case PROP_PERIODICITYOFIDRFRAMES:
303     case PROP_PERIODICITYOFIDRFRAMES_COMPAT:
304       g_value_set_uint (value, self->periodicty_idr);
305       break;
306     case PROP_INTERVALOFCODINGINTRAFRAMES:
307       g_value_set_uint (value, self->interval_intraframes);
308       break;
309     case PROP_B_FRAMES:
310       g_value_set_uint (value, self->b_frames);
311       break;
312     case PROP_ENTROPY_MODE:
313       g_value_set_enum (value, self->entropy_mode);
314       break;
315     case PROP_CONSTRAINED_INTRA_PREDICTION:
316       g_value_set_boolean (value, self->constrained_intra_prediction);
317       break;
318     case PROP_LOOP_FILTER_MODE:
319       g_value_set_enum (value, self->loop_filter_mode);
320       break;
321     case PROP_REF_FRAMES:
322       g_value_set_uchar (value, self->ref_frames);
323       break;
324     default:
325       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326       break;
327   }
328 }
329
330 static void
331 gst_omx_h264_enc_init (GstOMXH264Enc * self)
332 {
333 #ifdef USE_OMX_TARGET_RPI
334   self->inline_sps_pps_headers =
335       GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT;
336 #endif
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;
347 }
348
349 static gboolean
350 gst_omx_h264_enc_flush (GstVideoEncoder * enc)
351 {
352   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
353
354   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
355   self->headers = NULL;
356
357   return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (enc);
358 }
359
360 static gboolean
361 gst_omx_h264_enc_stop (GstVideoEncoder * enc)
362 {
363   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
364
365   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
366   self->headers = NULL;
367
368   return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc);
369 }
370
371 /* Update OMX_VIDEO_PARAM_PROFILELEVELTYPE.{eProfile,eLevel}
372  *
373  * Returns TRUE if succeeded or if not supported, FALSE if failed */
374 static gboolean
375 update_param_profile_level (GstOMXH264Enc * self,
376     OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level)
377 {
378   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
379   OMX_ERRORTYPE err;
380
381   GST_OMX_INIT_STRUCT (&param);
382   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
383
384   err =
385       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
386       OMX_IndexParamVideoProfileLevelCurrent, &param);
387   if (err != OMX_ErrorNone) {
388     GST_WARNING_OBJECT (self,
389         "Getting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
390     return TRUE;
391   }
392
393   if (profile != OMX_VIDEO_AVCProfileMax)
394     param.eProfile = profile;
395   if (level != OMX_VIDEO_AVCLevelMax)
396     param.eLevel = level;
397
398   err =
399       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
400       OMX_IndexParamVideoProfileLevelCurrent, &param);
401   if (err == OMX_ErrorUnsupportedIndex) {
402     GST_WARNING_OBJECT (self,
403         "Setting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
404     return TRUE;
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);
410     return FALSE;
411   }
412
413   return TRUE;
414 }
415
416 /* Update OMX_VIDEO_PARAM_AVCTYPE
417  *
418  * Returns TRUE if succeeded or if not supported, FALSE if failed */
419 static gboolean
420 update_param_avc (GstOMXH264Enc * self,
421     OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level)
422 {
423   OMX_VIDEO_PARAM_AVCTYPE param;
424   OMX_ERRORTYPE err;
425
426   GST_OMX_INIT_STRUCT (&param);
427   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
428
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. */
433
434   err =
435       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
436       OMX_IndexParamVideoAvc, &param);
437   if (err != OMX_ErrorNone) {
438     GST_WARNING_OBJECT (self,
439         "Getting OMX_IndexParamVideoAvc not supported by component");
440     return TRUE;
441   }
442
443   if (profile != OMX_VIDEO_AVCProfileMax)
444     param.eProfile = profile;
445   if (level != OMX_VIDEO_AVCLevelMax)
446     param.eLevel = level;
447
448   /* GOP pattern */
449   if (self->interval_intraframes !=
450       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
451     param.nPFrames = self->interval_intraframes;
452
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);
461         return FALSE;
462       }
463       param.nPFrames -= self->b_frames;
464     } else {
465       param.nBFrames = 0;
466     }
467   }
468
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)",
473           self->b_frames);
474       return FALSE;
475     }
476     param.nBFrames = self->b_frames;
477   }
478
479   if (self->ref_frames != GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT)
480     param.nRefFrames = self->ref_frames;
481
482   if (self->entropy_mode != GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT) {
483     param.bEntropyCodingCABAC = self->entropy_mode;
484   }
485
486   param.bconstIpred = self->constrained_intra_prediction;
487
488   if (self->loop_filter_mode != GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT) {
489     param.eLoopFilterMode = self->loop_filter_mode;
490   }
491
492   err =
493       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
494       OMX_IndexParamVideoAvc, &param);
495   if (err == OMX_ErrorUnsupportedIndex) {
496     GST_WARNING_OBJECT (self,
497         "Setting OMX_IndexParamVideoAvc not supported by component");
498     return TRUE;
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);
504     return FALSE;
505   }
506
507   return TRUE;
508 }
509
510 static gboolean
511 set_avc_intra_period (GstOMXH264Enc * self)
512 {
513   OMX_VIDEO_CONFIG_AVCINTRAPERIOD config_avcintraperiod;
514   OMX_ERRORTYPE err;
515
516   GST_OMX_INIT_STRUCT (&config_avcintraperiod);
517   config_avcintraperiod.nPortIndex =
518       GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
519   err =
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");
525     return TRUE;
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);
530     return FALSE;
531   }
532
533   GST_DEBUG_OBJECT (self, "default nPFrames:%u, nIDRPeriod:%u",
534       (guint) config_avcintraperiod.nPFrames,
535       (guint) config_avcintraperiod.nIDRPeriod);
536
537   if (self->periodicty_idr !=
538       GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT) {
539     config_avcintraperiod.nIDRPeriod = self->periodicty_idr;
540   }
541
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;
550   }
551
552   err =
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);
559     return FALSE;
560   }
561
562   return TRUE;
563 }
564
565 #ifdef USE_OMX_TARGET_RPI
566 static gboolean
567 set_brcm_video_intra_period (GstOMXH264Enc * self)
568 {
569   OMX_PARAM_U32TYPE intra_period;
570   OMX_ERRORTYPE err;
571
572   GST_OMX_INIT_STRUCT (&intra_period);
573
574   intra_period.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
575   err =
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);
582     return FALSE;
583   }
584
585   GST_DEBUG_OBJECT (self, "default OMX_IndexConfigBrcmVideoIntraPeriod: %u",
586       (guint) intra_period.nU32);
587
588   if (self->interval_intraframes ==
589       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT)
590     return TRUE;
591
592   intra_period.nU32 = self->interval_intraframes;
593
594   err =
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);
601     return FALSE;
602   }
603
604   GST_DEBUG_OBJECT (self, "OMX_IndexConfigBrcmVideoIntraPeriod set to %u",
605       (guint) intra_period.nU32);
606
607   return TRUE;
608 }
609 #endif
610
611 static gboolean
612 gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
613     GstVideoCodecState * state)
614 {
615   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
616   GstCaps *peercaps;
617   OMX_PARAM_PORTDEFINITIONTYPE port_def;
618 #ifdef USE_OMX_TARGET_RPI
619   OMX_CONFIG_PORTBOOLEANTYPE config_inline_header;
620 #endif
621   OMX_ERRORTYPE err;
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;
626
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;
631   err =
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);
638     return FALSE;
639   }
640
641   if (self->inline_sps_pps_headers) {
642     config_inline_header.bEnabled = OMX_TRUE;
643   } else {
644     config_inline_header.bEnabled = OMX_FALSE;
645   }
646
647   err =
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);
654     return FALSE;
655   }
656 #endif
657
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);
664   }
665 #ifdef USE_OMX_TARGET_RPI
666   /* The Pi uses a specific OMX setting to configure the intra period */
667
668   if (self->interval_intraframes)
669     set_brcm_video_intra_period (self);
670 #endif
671
672   gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
673       &port_def);
674   port_def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
675   err =
676       gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
677       (self)->enc_out_port, &port_def);
678   if (err != OMX_ErrorNone)
679     return FALSE;
680
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)));
684   if (peercaps) {
685     GstStructure *s;
686     const gchar *alignment_string;
687
688     if (gst_caps_is_empty (peercaps)) {
689       gst_caps_unref (peercaps);
690       GST_ERROR_OBJECT (self, "Empty caps");
691       return FALSE;
692     }
693
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;
700     }
701     level_string = gst_structure_get_string (s, "level");
702     if (level_string) {
703       level = gst_omx_h264_utils_get_level_from_str (level_string);
704       if (level == OMX_VIDEO_AVCLevelMax)
705         goto unsupported_level;
706     }
707
708     alignment_string = gst_structure_get_string (s, "alignment");
709     if (alignment_string && g_str_equal (alignment_string, "nal"))
710       enable_subframe = TRUE;
711
712     gst_caps_unref (peercaps);
713   }
714
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))
720       return FALSE;
721   }
722
723   gst_omx_port_set_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port,
724       enable_subframe);
725
726   if (!update_param_avc (self, profile, level))
727     return FALSE;
728
729   return TRUE;
730
731 unsupported_profile:
732   GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
733   gst_caps_unref (peercaps);
734   return FALSE;
735
736 unsupported_level:
737   GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
738   gst_caps_unref (peercaps);
739   return FALSE;
740 }
741
742 static GstCaps *
743 gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
744     GstVideoCodecState * state)
745 {
746   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
747   GstCaps *caps;
748   OMX_ERRORTYPE err;
749   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
750   const gchar *profile, *level, *alignment;
751
752   GST_OMX_INIT_STRUCT (&param);
753   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
754
755   err =
756       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
757       OMX_IndexParamVideoProfileLevelCurrent, &param);
758   if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
759     return NULL;
760
761   if (gst_omx_port_get_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port))
762     alignment = "nal";
763   else
764     alignment = "au";
765
766   caps = gst_caps_new_simple ("video/x-h264",
767       "stream-format", G_TYPE_STRING, "byte-stream",
768       "alignment", G_TYPE_STRING, alignment, NULL);
769
770   if (err == OMX_ErrorNone) {
771     profile = gst_omx_h264_utils_get_profile_from_enum (param.eProfile);
772     if (!profile) {
773       g_assert_not_reached ();
774       gst_caps_unref (caps);
775       return NULL;
776     }
777
778     switch (param.eLevel) {
779       case OMX_VIDEO_AVCLevel1:
780         level = "1";
781         break;
782       case OMX_VIDEO_AVCLevel1b:
783         level = "1b";
784         break;
785       case OMX_VIDEO_AVCLevel11:
786         level = "1.1";
787         break;
788       case OMX_VIDEO_AVCLevel12:
789         level = "1.2";
790         break;
791       case OMX_VIDEO_AVCLevel13:
792         level = "1.3";
793         break;
794       case OMX_VIDEO_AVCLevel2:
795         level = "2";
796         break;
797       case OMX_VIDEO_AVCLevel21:
798         level = "2.1";
799         break;
800       case OMX_VIDEO_AVCLevel22:
801         level = "2.2";
802         break;
803       case OMX_VIDEO_AVCLevel3:
804         level = "3";
805         break;
806       case OMX_VIDEO_AVCLevel31:
807         level = "3.1";
808         break;
809       case OMX_VIDEO_AVCLevel32:
810         level = "3.2";
811         break;
812       case OMX_VIDEO_AVCLevel4:
813         level = "4";
814         break;
815       case OMX_VIDEO_AVCLevel41:
816         level = "4.1";
817         break;
818       case OMX_VIDEO_AVCLevel42:
819         level = "4.2";
820         break;
821       case OMX_VIDEO_AVCLevel5:
822         level = "5";
823         break;
824       case OMX_VIDEO_AVCLevel51:
825         level = "5.1";
826         break;
827 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
828       case OMX_ALG_VIDEO_AVCLevel52:
829         level = "5.2";
830         break;
831       case OMX_ALG_VIDEO_AVCLevel60:
832         level = "6.0";
833         break;
834       case OMX_ALG_VIDEO_AVCLevel61:
835         level = "6.1";
836         break;
837       case OMX_ALG_VIDEO_AVCLevel62:
838         level = "6.2";
839         break;
840 #endif
841       default:
842         g_assert_not_reached ();
843         gst_caps_unref (caps);
844         return NULL;
845     }
846     gst_caps_set_simple (caps,
847         "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level, NULL);
848   }
849
850   return caps;
851 }
852
853 static GstFlowReturn
854 gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * enc, GstOMXPort * port,
855     GstOMXBuffer * buf, GstVideoCodecFrame * frame)
856 {
857   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
858
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
862      * in the caps!
863      */
864     GstBuffer *hdrs;
865     GstMapInfo map = GST_MAP_INFO_INIT;
866     GstFlowReturn flow_ret;
867
868     GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
869
870     hdrs = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
871     GST_BUFFER_FLAG_SET (hdrs, GST_BUFFER_FLAG_HEADER);
872
873     gst_buffer_map (hdrs, &map, GST_MAP_WRITE);
874     memcpy (map.data,
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;
880     flow_ret =
881         gst_video_encoder_finish_subframe (GST_VIDEO_ENCODER (self), frame);
882     gst_video_codec_frame_unref (frame);
883
884     return flow_ret;
885   } else if (self->headers) {
886     gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), self->headers);
887     self->headers = NULL;
888   }
889
890   return
891       GST_OMX_VIDEO_ENC_CLASS
892       (gst_omx_h264_enc_parent_class)->handle_output_frame (enc, port, buf,
893       frame);
894 }