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