Merge branch 'move_subdir_rtsp-server' into tizen_gst_1.19.2_mono
[platform/upstream/gstreamer.git] / subprojects / gst-omx / 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 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
59   PROP_NUM_REF_FRAME,
60   PROP_NUM_B_FRAME,
61 #endif
62   PROP_PERIODICITYOFIDRFRAMES,
63   PROP_PERIODICITYOFIDRFRAMES_COMPAT,
64   PROP_INTERVALOFCODINGINTRAFRAMES,
65   PROP_B_FRAMES,
66   PROP_ENTROPY_MODE,
67   PROP_CONSTRAINED_INTRA_PREDICTION,
68   PROP_LOOP_FILTER_MODE,
69   PROP_REF_FRAMES
70 };
71
72 #ifdef USE_OMX_TARGET_RPI
73 #define GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT      TRUE
74 #endif
75 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
76 #define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT (0x00000001)
77 #define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX (0x00000002)
78 #define GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT (0x00000001)
79 #define GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX (0x00000002)
80 #endif
81 #define GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT    (0xffffffff)
82 #define GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
83 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
84 #define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0)
85 #define ALIGNMENT "{ au, nal }"
86 #else
87 #define GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
88 #define ALIGNMENT "au"
89 #endif
90 #define GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT (0xffffffff)
91 #define GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT (FALSE)
92 #define GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT (0xffffffff)
93 #define GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT 0
94 #define GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MIN 0
95 #define GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MAX 16
96
97 /* class initialization */
98
99 #define DEBUG_INIT \
100   GST_DEBUG_CATEGORY_INIT (gst_omx_h264_enc_debug_category, "omxh264enc", 0, \
101       "debug category for gst-omx video encoder base class");
102
103 #define parent_class gst_omx_h264_enc_parent_class
104 G_DEFINE_TYPE_WITH_CODE (GstOMXH264Enc, gst_omx_h264_enc,
105     GST_TYPE_OMX_VIDEO_ENC, DEBUG_INIT);
106
107 #define GST_TYPE_OMX_H264_ENC_ENTROPY_MODE (gst_omx_h264_enc_entropy_mode_get_type ())
108 static GType
109 gst_omx_h264_enc_entropy_mode_get_type (void)
110 {
111   static GType qtype = 0;
112
113   if (qtype == 0) {
114     static const GEnumValue values[] = {
115       {FALSE, "CAVLC entropy mode", "CAVLC"},
116       {TRUE, "CABAC entropy mode", "CABAC"},
117       {0xffffffff, "Component Default", "default"},
118       {0, NULL, NULL}
119     };
120
121     qtype = g_enum_register_static ("GstOMXH264EncEntropyMode", values);
122   }
123   return qtype;
124 }
125
126 #define GST_TYPE_OMX_H264_ENC_LOOP_FILTER_MODE (gst_omx_h264_enc_loop_filter_mode_get_type ())
127 static GType
128 gst_omx_h264_enc_loop_filter_mode_get_type (void)
129 {
130   static GType qtype = 0;
131
132   if (qtype == 0) {
133     static const GEnumValue values[] = {
134       {OMX_VIDEO_AVCLoopFilterEnable, "Enable deblocking filter", "enable"},
135       {OMX_VIDEO_AVCLoopFilterDisable, "Disable deblocking filter", "disable"},
136       {OMX_VIDEO_AVCLoopFilterDisableSliceBoundary,
137             "Disables deblocking filter on slice boundary",
138           "disable-slice-boundary"},
139       {0xffffffff, "Component Default", "default"},
140       {0, NULL, NULL}
141     };
142
143     qtype = g_enum_register_static ("GstOMXH264EncLoopFilter", values);
144   }
145   return qtype;
146 }
147
148 static void
149 gst_omx_h264_enc_class_init (GstOMXH264EncClass * klass)
150 {
151   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
152   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
153   GstVideoEncoderClass *basevideoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
154   GstOMXVideoEncClass *videoenc_class = GST_OMX_VIDEO_ENC_CLASS (klass);
155
156   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_h264_enc_set_format);
157   videoenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_h264_enc_get_caps);
158
159   gobject_class->set_property = gst_omx_h264_enc_set_property;
160   gobject_class->get_property = gst_omx_h264_enc_get_property;
161
162 #ifdef USE_OMX_TARGET_RPI
163   g_object_class_install_property (gobject_class, PROP_INLINESPSPPSHEADERS,
164       g_param_spec_boolean ("inline-header",
165           "Inline SPS/PPS headers before IDR",
166           "Inline SPS/PPS header before IDR",
167           GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT,
168           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
169           GST_PARAM_MUTABLE_READY));
170 #endif
171 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
172   g_object_class_install_property (gobject_class, PROP_NUM_REF_FRAME,
173       g_param_spec_uint ("reference-frame", "set number of reference frame",
174           "The number of reference frame (0x00000001=component default)",
175           GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT, GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX,
176           GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT,
177           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
178           GST_PARAM_MUTABLE_READY));
179
180   g_object_class_install_property (gobject_class, PROP_NUM_B_FRAME,
181       g_param_spec_uint ("b-frame", "set number of b frame",
182           "The number of reference frame (0x00000001=component default)",
183           GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT, GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX,
184           GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT,
185           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
186           GST_PARAM_MUTABLE_READY));
187 #endif
188   g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES,
189       g_param_spec_uint ("periodicity-idr", "IDR periodicity",
190           "Periodicity of IDR frames (0xffffffff=component default)",
191           0, G_MAXUINT,
192           GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
193           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
194           GST_PARAM_MUTABLE_READY));
195
196   g_object_class_install_property (gobject_class,
197       PROP_PERIODICITYOFIDRFRAMES_COMPAT, g_param_spec_uint ("periodicty-idr",
198           "IDR periodicity",
199           "Periodicity of IDR frames (0xffffffff=component default) DEPRECATED - only for backwards compat",
200           0, G_MAXUINT,
201           GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
202           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
203           GST_PARAM_MUTABLE_READY));
204
205   g_object_class_install_property (gobject_class,
206       PROP_INTERVALOFCODINGINTRAFRAMES,
207       g_param_spec_uint ("interval-intraframes",
208           "Interval of coding Intra frames",
209           "Interval of coding Intra frames (0xffffffff=component default)", 0,
210           G_MAXUINT,
211           GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT,
212           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
213           GST_PARAM_MUTABLE_READY));
214
215   g_object_class_install_property (gobject_class, PROP_B_FRAMES,
216       g_param_spec_uint ("b-frames", "Number of B-frames",
217           "Number of B-frames between two consecutive I-frames (0xffffffff=component default)",
218           0, G_MAXUINT, GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT,
219           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
220           GST_PARAM_MUTABLE_READY));
221
222   g_object_class_install_property (gobject_class, PROP_ENTROPY_MODE,
223       g_param_spec_enum ("entropy-mode", "Entropy Mode",
224           "Entropy mode for encoding process",
225           GST_TYPE_OMX_H264_ENC_ENTROPY_MODE,
226           GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT,
227           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
228           GST_PARAM_MUTABLE_READY));
229
230   g_object_class_install_property (gobject_class,
231       PROP_CONSTRAINED_INTRA_PREDICTION,
232       g_param_spec_boolean ("constrained-intra-prediction",
233           "Constrained Intra Prediction",
234           "If enabled, prediction only uses residual data and decoded samples "
235           "from neighbouring coding blocks coded using intra prediction modes",
236           GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT,
237           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
238           GST_PARAM_MUTABLE_READY));
239
240   g_object_class_install_property (gobject_class, PROP_LOOP_FILTER_MODE,
241       g_param_spec_enum ("loop-filter-mode", "Loop Filter mode",
242           "Enable or disable the deblocking filter (0xffffffff=component default)",
243           GST_TYPE_OMX_H264_ENC_LOOP_FILTER_MODE,
244           GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT,
245           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
246           GST_PARAM_MUTABLE_READY));
247
248   g_object_class_install_property (gobject_class, PROP_REF_FRAMES,
249       g_param_spec_uchar ("ref-frames", "Reference frames",
250           "Number of reference frames used for inter-motion search (0=component default)",
251           GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MIN,
252           GST_OMX_H264_VIDEO_ENC_REF_FRAMES_MAX,
253           GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT,
254           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
255           GST_PARAM_MUTABLE_READY));
256
257   basevideoenc_class->flush = gst_omx_h264_enc_flush;
258   basevideoenc_class->stop = gst_omx_h264_enc_stop;
259
260   videoenc_class->cdata.default_src_template_caps = "video/x-h264, "
261       "width = (int) [ 16, 4096 ], height = (int) [ 16, 4096 ], "
262       "framerate = (fraction) [0, MAX], stream-format=(string) byte-stream, "
263       "alignment = (string) " ALIGNMENT;
264   videoenc_class->handle_output_frame =
265       GST_DEBUG_FUNCPTR (gst_omx_h264_enc_handle_output_frame);
266
267   gst_element_class_set_static_metadata (element_class,
268       "OpenMAX H.264 Video Encoder",
269       "Codec/Encoder/Video/Hardware",
270       "Encode H.264 video streams",
271       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
272
273   gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.avc");
274 }
275
276 static void
277 gst_omx_h264_enc_set_property (GObject * object, guint prop_id,
278     const GValue * value, GParamSpec * pspec)
279 {
280   GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
281
282   switch (prop_id) {
283 #ifdef USE_OMX_TARGET_RPI
284     case PROP_INLINESPSPPSHEADERS:
285       self->inline_sps_pps_headers = g_value_get_boolean (value);
286       break;
287 #endif
288 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
289     case PROP_NUM_REF_FRAME:
290       self->reference_frame = g_value_get_int (value);
291       break;
292     case PROP_NUM_B_FRAME:
293       self->b_frame = g_value_get_int (value);
294       break;
295 #endif
296     case PROP_PERIODICITYOFIDRFRAMES:
297     case PROP_PERIODICITYOFIDRFRAMES_COMPAT:
298       self->periodicty_idr = g_value_get_uint (value);
299       break;
300     case PROP_INTERVALOFCODINGINTRAFRAMES:
301       self->interval_intraframes = g_value_get_uint (value);
302       break;
303     case PROP_B_FRAMES:
304       self->b_frames = g_value_get_uint (value);
305       break;
306     case PROP_ENTROPY_MODE:
307       self->entropy_mode = g_value_get_enum (value);
308       break;
309     case PROP_CONSTRAINED_INTRA_PREDICTION:
310       self->constrained_intra_prediction = g_value_get_boolean (value);
311       break;
312     case PROP_LOOP_FILTER_MODE:
313       self->loop_filter_mode = g_value_get_enum (value);
314       break;
315     case PROP_REF_FRAMES:
316       self->ref_frames = g_value_get_uchar (value);
317       break;
318     default:
319       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320       break;
321   }
322 }
323
324 static void
325 gst_omx_h264_enc_get_property (GObject * object, guint prop_id, GValue * value,
326     GParamSpec * pspec)
327 {
328   GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
329
330   switch (prop_id) {
331 #ifdef USE_OMX_TARGET_RPI
332     case PROP_INLINESPSPPSHEADERS:
333       g_value_set_boolean (value, self->inline_sps_pps_headers);
334       break;
335 #endif
336 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
337     case PROP_NUM_REF_FRAME:
338       g_value_set_uint (value, self->reference_frame);
339       break;
340     case PROP_NUM_B_FRAME:
341       g_value_set_uint (value, self->b_frame);
342       break;
343 #endif
344     case PROP_PERIODICITYOFIDRFRAMES:
345     case PROP_PERIODICITYOFIDRFRAMES_COMPAT:
346       g_value_set_uint (value, self->periodicty_idr);
347       break;
348     case PROP_INTERVALOFCODINGINTRAFRAMES:
349       g_value_set_uint (value, self->interval_intraframes);
350       break;
351     case PROP_B_FRAMES:
352       g_value_set_uint (value, self->b_frames);
353       break;
354     case PROP_ENTROPY_MODE:
355       g_value_set_enum (value, self->entropy_mode);
356       break;
357     case PROP_CONSTRAINED_INTRA_PREDICTION:
358       g_value_set_boolean (value, self->constrained_intra_prediction);
359       break;
360     case PROP_LOOP_FILTER_MODE:
361       g_value_set_enum (value, self->loop_filter_mode);
362       break;
363     case PROP_REF_FRAMES:
364       g_value_set_uchar (value, self->ref_frames);
365       break;
366     default:
367       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368       break;
369   }
370 }
371
372 static void
373 gst_omx_h264_enc_init (GstOMXH264Enc * self)
374 {
375 #ifdef USE_OMX_TARGET_RPI
376   self->inline_sps_pps_headers =
377       GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT;
378 #endif
379 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
380   self->reference_frame = GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT;
381 #endif
382   self->periodicty_idr =
383       GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT;
384   self->interval_intraframes =
385       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT;
386   self->b_frames = GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT;
387   self->entropy_mode = GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT;
388   self->constrained_intra_prediction =
389       GST_OMX_H264_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT;
390   self->loop_filter_mode = GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT;
391   self->ref_frames = GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT;
392 }
393
394 static gboolean
395 gst_omx_h264_enc_flush (GstVideoEncoder * enc)
396 {
397   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
398
399   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
400   self->headers = NULL;
401
402   return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (enc);
403 }
404
405 static gboolean
406 gst_omx_h264_enc_stop (GstVideoEncoder * enc)
407 {
408   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
409
410   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
411   self->headers = NULL;
412
413   return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc);
414 }
415
416 /* Update OMX_VIDEO_PARAM_PROFILELEVELTYPE.{eProfile,eLevel}
417  *
418  * Returns TRUE if succeeded or if not supported, FALSE if failed */
419 static gboolean
420 update_param_profile_level (GstOMXH264Enc * self,
421     OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level)
422 {
423   OMX_VIDEO_PARAM_PROFILELEVELTYPE 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   err =
430       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
431       OMX_IndexParamVideoProfileLevelCurrent, &param);
432   if (err != OMX_ErrorNone) {
433     GST_WARNING_OBJECT (self,
434         "Getting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
435     return TRUE;
436   }
437
438   if (profile != OMX_VIDEO_AVCProfileMax)
439     param.eProfile = profile;
440   if (level != OMX_VIDEO_AVCLevelMax)
441     param.eLevel = level;
442
443   err =
444       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
445       OMX_IndexParamVideoProfileLevelCurrent, &param);
446   if (err == OMX_ErrorUnsupportedIndex) {
447     GST_WARNING_OBJECT (self,
448         "Setting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
449     return TRUE;
450   } else if (err != OMX_ErrorNone) {
451     GST_ERROR_OBJECT (self,
452         "Error setting profile %u and level %u: %s (0x%08x)",
453         (guint) param.eProfile, (guint) param.eLevel,
454         gst_omx_error_to_string (err), err);
455     return FALSE;
456   }
457
458   return TRUE;
459 }
460
461 /* Update OMX_VIDEO_PARAM_AVCTYPE
462  *
463  * Returns TRUE if succeeded or if not supported, FALSE if failed */
464 static gboolean
465 update_param_avc (GstOMXH264Enc * self,
466     OMX_VIDEO_AVCPROFILETYPE profile, OMX_VIDEO_AVCLEVELTYPE level)
467 {
468   OMX_VIDEO_PARAM_AVCTYPE param;
469   OMX_ERRORTYPE err;
470
471   GST_OMX_INIT_STRUCT (&param);
472   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
473
474   /* On Android the param struct is initialized manually with default
475    * settings rather than using GetParameter() to retrieve them.
476    * We should probably do the same when we'll add Android as target.
477    * See bgo#783862 for details. */
478
479   err =
480       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
481       OMX_IndexParamVideoAvc, &param);
482   if (err != OMX_ErrorNone) {
483     GST_WARNING_OBJECT (self,
484         "Getting OMX_IndexParamVideoAvc not supported by component");
485     return TRUE;
486   }
487
488   if (profile != OMX_VIDEO_AVCProfileMax)
489     param.eProfile = profile;
490   if (level != OMX_VIDEO_AVCLevelMax)
491     param.eLevel = level;
492
493   /* GOP pattern */
494   if (self->interval_intraframes !=
495       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
496     param.nPFrames = self->interval_intraframes;
497
498     /* If user specified a specific number of B-frames, reduce the number of
499      * P-frames by this amount. If not ensure there is no B-frame to have the
500      * requested GOP length. */
501     if (self->b_frames != GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT) {
502       if (self->b_frames > self->interval_intraframes) {
503         GST_ERROR_OBJECT (self,
504             "The interval_intraframes perdiod (%u) needs to be higher than the number of B-frames (%u)",
505             self->interval_intraframes, self->b_frames);
506         return FALSE;
507       }
508       param.nPFrames -= self->b_frames;
509     } else {
510       param.nBFrames = 0;
511     }
512   }
513
514   if (self->b_frames != GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT) {
515     if (profile == OMX_VIDEO_AVCProfileBaseline && self->b_frames > 0) {
516       GST_ERROR_OBJECT (self,
517           "Baseline profile doesn't support B-frames (%u requested)",
518           self->b_frames);
519       return FALSE;
520     }
521     param.nBFrames = self->b_frames;
522   }
523
524   if (self->ref_frames != GST_OMX_H264_VIDEO_ENC_REF_FRAMES_DEFAULT)
525     param.nRefFrames = self->ref_frames;
526
527   if (self->entropy_mode != GST_OMX_H264_VIDEO_ENC_ENTROPY_MODE_DEFAULT) {
528     param.bEntropyCodingCABAC = self->entropy_mode;
529   }
530
531   param.bconstIpred = self->constrained_intra_prediction;
532
533   if (self->loop_filter_mode != GST_OMX_H264_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT) {
534     param.eLoopFilterMode = self->loop_filter_mode;
535   }
536
537   err =
538       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
539       OMX_IndexParamVideoAvc, &param);
540   if (err == OMX_ErrorUnsupportedIndex) {
541     GST_WARNING_OBJECT (self,
542         "Setting OMX_IndexParamVideoAvc not supported by component");
543     return TRUE;
544   } else if (err != OMX_ErrorNone) {
545     GST_ERROR_OBJECT (self,
546         "Error setting AVC settings (profile %u and level %u): %s (0x%08x)",
547         (guint) param.eProfile, (guint) param.eLevel,
548         gst_omx_error_to_string (err), err);
549     return FALSE;
550   }
551
552   return TRUE;
553 }
554
555 static gboolean
556 set_avc_intra_period (GstOMXH264Enc * self)
557 {
558   OMX_VIDEO_CONFIG_AVCINTRAPERIOD config_avcintraperiod;
559   OMX_ERRORTYPE err;
560
561   GST_OMX_INIT_STRUCT (&config_avcintraperiod);
562   config_avcintraperiod.nPortIndex =
563       GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
564   err =
565       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
566       OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod);
567   if (err == OMX_ErrorUnsupportedIndex) {
568     GST_WARNING_OBJECT (self,
569         "OMX_IndexConfigVideoAVCIntraPeriod  not supported by component");
570     return TRUE;
571   } else if (err != OMX_ErrorNone) {
572     GST_ERROR_OBJECT (self,
573         "can't get OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
574         gst_omx_error_to_string (err), err);
575     return FALSE;
576   }
577
578   GST_DEBUG_OBJECT (self, "default nPFrames:%u, nIDRPeriod:%u",
579       (guint) config_avcintraperiod.nPFrames,
580       (guint) config_avcintraperiod.nIDRPeriod);
581
582   if (self->periodicty_idr !=
583       GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT) {
584     config_avcintraperiod.nIDRPeriod = self->periodicty_idr;
585   }
586
587   if (self->interval_intraframes !=
588       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
589     /* This OMX API doesn't allow us to specify the number of B-frames.
590      * So if user requested one we have to rely on update_param_avc()
591      * to configure the intraframes interval so it can take the
592      * B-frames into account. */
593     if (self->b_frames == GST_OMX_H264_VIDEO_ENC_B_FRAMES_DEFAULT)
594       config_avcintraperiod.nPFrames = self->interval_intraframes;
595   }
596
597   err =
598       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
599       OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod);
600   if (err != OMX_ErrorNone) {
601     GST_ERROR_OBJECT (self,
602         "can't set OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
603         gst_omx_error_to_string (err), err);
604     return FALSE;
605   }
606
607   return TRUE;
608 }
609
610 #ifdef USE_OMX_TARGET_RPI
611 static gboolean
612 set_brcm_video_intra_period (GstOMXH264Enc * self)
613 {
614   OMX_PARAM_U32TYPE intra_period;
615   OMX_ERRORTYPE err;
616
617   GST_OMX_INIT_STRUCT (&intra_period);
618
619   intra_period.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
620   err =
621       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
622       OMX_IndexConfigBrcmVideoIntraPeriod, &intra_period);
623   if (err != OMX_ErrorNone) {
624     GST_ERROR_OBJECT (self,
625         "can't get OMX_IndexConfigBrcmVideoIntraPeriod %s (0x%08x)",
626         gst_omx_error_to_string (err), err);
627     return FALSE;
628   }
629
630   GST_DEBUG_OBJECT (self, "default OMX_IndexConfigBrcmVideoIntraPeriod: %u",
631       (guint) intra_period.nU32);
632
633   if (self->interval_intraframes ==
634       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT)
635     return TRUE;
636
637   intra_period.nU32 = self->interval_intraframes;
638
639   err =
640       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
641       OMX_IndexConfigBrcmVideoIntraPeriod, &intra_period);
642   if (err != OMX_ErrorNone) {
643     GST_ERROR_OBJECT (self,
644         "can't set OMX_IndexConfigBrcmVideoIntraPeriod %s (0x%08x)",
645         gst_omx_error_to_string (err), err);
646     return FALSE;
647   }
648
649   GST_DEBUG_OBJECT (self, "OMX_IndexConfigBrcmVideoIntraPeriod set to %u",
650       (guint) intra_period.nU32);
651
652   return TRUE;
653 }
654 #endif
655
656 static gboolean
657 gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
658     GstVideoCodecState * state)
659 {
660   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
661   GstCaps *peercaps;
662   OMX_PARAM_PORTDEFINITIONTYPE port_def;
663 #ifdef USE_OMX_TARGET_RPI
664   OMX_CONFIG_PORTBOOLEANTYPE config_inline_header;
665 #endif
666 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
667   OMX_VIDEO_PARAM_AVCTYPE avc_param;
668 #endif
669   OMX_ERRORTYPE err;
670   const gchar *profile_string, *level_string;
671   OMX_VIDEO_AVCPROFILETYPE profile = OMX_VIDEO_AVCProfileMax;
672   OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevelMax;
673   gboolean enable_subframe = FALSE;
674
675 #ifdef USE_OMX_TARGET_RPI
676   GST_OMX_INIT_STRUCT (&config_inline_header);
677   config_inline_header.nPortIndex =
678       GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
679   err =
680       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
681       OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header);
682   if (err != OMX_ErrorNone) {
683     GST_ERROR_OBJECT (self,
684         "can't get OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)",
685         gst_omx_error_to_string (err), err);
686     return FALSE;
687   }
688
689   if (self->inline_sps_pps_headers) {
690     config_inline_header.bEnabled = OMX_TRUE;
691   } else {
692     config_inline_header.bEnabled = OMX_FALSE;
693   }
694
695   err =
696       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
697       OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header);
698   if (err != OMX_ErrorNone) {
699     GST_ERROR_OBJECT (self,
700         "can't set OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)",
701         gst_omx_error_to_string (err), err);
702     return FALSE;
703   }
704 #endif
705 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
706   GST_OMX_INIT_STRUCT (&avc_param);
707
708   err =
709       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
710       OMX_IndexParamVideoAvc, &avc_param);
711   if (err != OMX_ErrorNone) {
712     GST_ERROR_OBJECT (self,
713         "can't get OMX_IndexParamVideoAvc %s (0x%08x)",
714         gst_omx_error_to_string (err), err);
715     return FALSE;
716   }
717
718   GST_DEBUG_OBJECT (self, "default nRefFrames:%u, nBFrames:%u",
719       (guint) avc_param.nRefFrames,
720       (guint) avc_param.nBFrames);
721
722   avc_param.nRefFrames = self->reference_frame;
723   avc_param.nBFrames = self->b_frame;
724   err =
725       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
726       OMX_IndexParamVideoAvc, &avc_param);
727   if (err != OMX_ErrorNone) {
728     GST_ERROR_OBJECT (self,
729         "can't set OMX_IndexParamVideoAvc %s (0x%08x)",
730         gst_omx_error_to_string (err), err);
731     return FALSE;
732   }
733
734 #endif
735
736   /* Configure GOP pattern */
737   if (self->periodicty_idr !=
738       GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT
739       || self->interval_intraframes !=
740       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
741     set_avc_intra_period (self);
742   }
743 #ifdef USE_OMX_TARGET_RPI
744   /* The Pi uses a specific OMX setting to configure the intra period */
745
746   if (self->interval_intraframes)
747     set_brcm_video_intra_period (self);
748 #endif
749
750   gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
751       &port_def);
752   port_def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
753   err =
754       gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
755       (self)->enc_out_port, &port_def);
756   if (err != OMX_ErrorNone)
757     return FALSE;
758
759   /* Set profile and level */
760   peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc),
761       gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc)));
762   if (peercaps) {
763     GstStructure *s;
764     const gchar *alignment_string;
765
766     if (gst_caps_is_empty (peercaps)) {
767       gst_caps_unref (peercaps);
768       GST_ERROR_OBJECT (self, "Empty caps");
769       return FALSE;
770     }
771
772     s = gst_caps_get_structure (peercaps, 0);
773     profile_string = gst_structure_get_string (s, "profile");
774     if (profile_string) {
775       profile = gst_omx_h264_utils_get_profile_from_str (profile_string);
776       if (profile == OMX_VIDEO_AVCProfileMax)
777         goto unsupported_profile;
778     }
779     level_string = gst_structure_get_string (s, "level");
780     if (level_string) {
781       level = gst_omx_h264_utils_get_level_from_str (level_string);
782       if (level == OMX_VIDEO_AVCLevelMax)
783         goto unsupported_level;
784     }
785
786     alignment_string = gst_structure_get_string (s, "alignment");
787     if (alignment_string && g_str_equal (alignment_string, "nal"))
788       enable_subframe = TRUE;
789
790     gst_caps_unref (peercaps);
791   }
792
793   if (profile != OMX_VIDEO_AVCProfileMax || level != OMX_VIDEO_AVCLevelMax) {
794     /* OMX provides 2 API to set the profile and level. We try using the
795      * generic one here and the H264 specific when calling
796      * update_param_avc() */
797     if (!update_param_profile_level (self, profile, level))
798       return FALSE;
799   }
800
801   gst_omx_port_set_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port,
802       enable_subframe);
803
804   if (!update_param_avc (self, profile, level))
805     return FALSE;
806
807   return TRUE;
808
809 unsupported_profile:
810   GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
811   gst_caps_unref (peercaps);
812   return FALSE;
813
814 unsupported_level:
815   GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
816   gst_caps_unref (peercaps);
817   return FALSE;
818 }
819
820 static GstCaps *
821 gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
822     GstVideoCodecState * state)
823 {
824   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
825   GstCaps *caps;
826   OMX_ERRORTYPE err;
827   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
828   const gchar *profile, *level, *alignment;
829
830   GST_OMX_INIT_STRUCT (&param);
831   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
832
833   err =
834       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
835       OMX_IndexParamVideoProfileLevelCurrent, &param);
836   if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
837     return NULL;
838
839   if (gst_omx_port_get_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port))
840     alignment = "nal";
841   else
842     alignment = "au";
843
844   caps = gst_caps_new_simple ("video/x-h264",
845       "stream-format", G_TYPE_STRING, "byte-stream",
846       "alignment", G_TYPE_STRING, alignment, NULL);
847
848   if (err == OMX_ErrorNone) {
849     profile = gst_omx_h264_utils_get_profile_from_enum (param.eProfile);
850     if (!profile) {
851       g_assert_not_reached ();
852       gst_caps_unref (caps);
853       return NULL;
854     }
855
856     switch (param.eLevel) {
857       case OMX_VIDEO_AVCLevel1:
858         level = "1";
859         break;
860       case OMX_VIDEO_AVCLevel1b:
861         level = "1b";
862         break;
863       case OMX_VIDEO_AVCLevel11:
864         level = "1.1";
865         break;
866       case OMX_VIDEO_AVCLevel12:
867         level = "1.2";
868         break;
869       case OMX_VIDEO_AVCLevel13:
870         level = "1.3";
871         break;
872       case OMX_VIDEO_AVCLevel2:
873         level = "2";
874         break;
875       case OMX_VIDEO_AVCLevel21:
876         level = "2.1";
877         break;
878       case OMX_VIDEO_AVCLevel22:
879         level = "2.2";
880         break;
881       case OMX_VIDEO_AVCLevel3:
882         level = "3";
883         break;
884       case OMX_VIDEO_AVCLevel31:
885         level = "3.1";
886         break;
887       case OMX_VIDEO_AVCLevel32:
888         level = "3.2";
889         break;
890       case OMX_VIDEO_AVCLevel4:
891         level = "4";
892         break;
893       case OMX_VIDEO_AVCLevel41:
894         level = "4.1";
895         break;
896       case OMX_VIDEO_AVCLevel42:
897         level = "4.2";
898         break;
899       case OMX_VIDEO_AVCLevel5:
900         level = "5";
901         break;
902       case OMX_VIDEO_AVCLevel51:
903         level = "5.1";
904         break;
905 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
906       case OMX_ALG_VIDEO_AVCLevel52:
907         level = "5.2";
908         break;
909       case OMX_ALG_VIDEO_AVCLevel60:
910         level = "6.0";
911         break;
912       case OMX_ALG_VIDEO_AVCLevel61:
913         level = "6.1";
914         break;
915       case OMX_ALG_VIDEO_AVCLevel62:
916         level = "6.2";
917         break;
918 #endif
919       default:
920         g_assert_not_reached ();
921         gst_caps_unref (caps);
922         return NULL;
923     }
924     gst_caps_set_simple (caps,
925         "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level, NULL);
926   }
927
928   return caps;
929 }
930
931 static GstFlowReturn
932 gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * enc, GstOMXPort * port,
933     GstOMXBuffer * buf, GstVideoCodecFrame * frame)
934 {
935   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
936
937   if (buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
938     /* The codec data is SPS/PPS but our output is stream-format=byte-stream.
939      * For bytestream stream format the SPS/PPS is only in-stream and not
940      * in the caps!
941      */
942     GstBuffer *hdrs;
943     GstMapInfo map = GST_MAP_INFO_INIT;
944     GstFlowReturn flow_ret;
945
946     GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
947
948     hdrs = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
949     GST_BUFFER_FLAG_SET (hdrs, GST_BUFFER_FLAG_HEADER);
950
951     gst_buffer_map (hdrs, &map, GST_MAP_WRITE);
952     memcpy (map.data,
953         buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
954         buf->omx_buf->nFilledLen);
955     gst_buffer_unmap (hdrs, &map);
956     self->headers = g_list_append (self->headers, gst_buffer_ref (hdrs));
957     frame->output_buffer = hdrs;
958     flow_ret =
959         gst_video_encoder_finish_subframe (GST_VIDEO_ENCODER (self), frame);
960     gst_video_codec_frame_unref (frame);
961
962     return flow_ret;
963   } else if (self->headers) {
964     gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), self->headers);
965     self->headers = NULL;
966   }
967
968   return
969       GST_OMX_VIDEO_ENC_CLASS
970       (gst_omx_h264_enc_parent_class)->handle_output_frame (enc, port, buf,
971       frame);
972 }