Added exception handling for null buffer
[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
29 #ifdef USE_OMX_TARGET_RPI
30 #include <OMX_Broadcom.h>
31 #include <OMX_Index.h>
32 #endif
33
34 GST_DEBUG_CATEGORY_STATIC (gst_omx_h264_enc_debug_category);
35 #define GST_CAT_DEFAULT gst_omx_h264_enc_debug_category
36
37 /* prototypes */
38 static gboolean gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc,
39     GstOMXPort * port, GstVideoCodecState * state);
40 static GstCaps *gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc,
41     GstOMXPort * port, GstVideoCodecState * state);
42 static GstFlowReturn gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc *
43     self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
44 static gboolean gst_omx_h264_enc_flush (GstVideoEncoder * enc);
45 static gboolean gst_omx_h264_enc_stop (GstVideoEncoder * enc);
46 static void gst_omx_h264_enc_set_property (GObject * object, guint prop_id,
47     const GValue * value, GParamSpec * pspec);
48 static void gst_omx_h264_enc_get_property (GObject * object, guint prop_id,
49     GValue * value, GParamSpec * pspec);
50
51 enum
52 {
53   PROP_0,
54 #ifdef USE_OMX_TARGET_RPI
55   PROP_INLINESPSPPSHEADERS,
56 #endif
57 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
58   PROP_NUM_REF_FRAME,
59   PROP_NUM_B_FRAME,
60 #endif
61   PROP_PERIODICITYOFIDRFRAMES,
62   PROP_INTERVALOFCODINGINTRAFRAMES
63 };
64
65 #ifdef USE_OMX_TARGET_RPI
66 #define GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT      TRUE
67 #endif
68 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
69 #define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT (0x00000001)
70 #define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX (0x00000002)
71 #define GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT (0x00000001)
72 #define GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX (0x00000002)
73 #endif
74 #define GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT    (0xffffffff)
75 #define GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
76
77
78 /* class initialization */
79
80 #define DEBUG_INIT \
81   GST_DEBUG_CATEGORY_INIT (gst_omx_h264_enc_debug_category, "omxh264enc", 0, \
82       "debug category for gst-omx video encoder base class");
83
84 #define parent_class gst_omx_h264_enc_parent_class
85 G_DEFINE_TYPE_WITH_CODE (GstOMXH264Enc, gst_omx_h264_enc,
86     GST_TYPE_OMX_VIDEO_ENC, DEBUG_INIT);
87
88 static void
89 gst_omx_h264_enc_class_init (GstOMXH264EncClass * klass)
90 {
91   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
92   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
93   GstVideoEncoderClass *basevideoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
94   GstOMXVideoEncClass *videoenc_class = GST_OMX_VIDEO_ENC_CLASS (klass);
95
96   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_h264_enc_set_format);
97   videoenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_h264_enc_get_caps);
98
99   gobject_class->set_property = gst_omx_h264_enc_set_property;
100   gobject_class->get_property = gst_omx_h264_enc_get_property;
101
102 #ifdef USE_OMX_TARGET_RPI
103   g_object_class_install_property (gobject_class, PROP_INLINESPSPPSHEADERS,
104       g_param_spec_boolean ("inline-header",
105           "Inline SPS/PPS headers before IDR",
106           "Inline SPS/PPS header before IDR",
107           GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT,
108           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
109           GST_PARAM_MUTABLE_READY));
110 #endif
111 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
112   g_object_class_install_property (gobject_class, PROP_NUM_REF_FRAME,
113       g_param_spec_uint ("reference-frame", "set number of reference frame",
114           "The number of reference frame (0x00000001=component default)",
115           GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT, GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX,
116           GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT,
117           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
118           GST_PARAM_MUTABLE_READY));
119
120   g_object_class_install_property (gobject_class, PROP_NUM_B_FRAME,
121       g_param_spec_uint ("b-frame", "set number of b frame",
122           "The number of reference frame (0x00000001=component default)",
123           GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT, GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX,
124           GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT,
125           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
126           GST_PARAM_MUTABLE_READY));
127 #endif
128   g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES,
129       g_param_spec_uint ("periodicty-idr", "Target Bitrate",
130           "Periodicity of IDR frames (0xffffffff=component default)",
131           0, G_MAXUINT,
132           GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
133           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
134           GST_PARAM_MUTABLE_READY));
135
136   g_object_class_install_property (gobject_class,
137       PROP_INTERVALOFCODINGINTRAFRAMES,
138       g_param_spec_uint ("interval-intraframes",
139           "Interval of coding Intra frames",
140           "Interval of coding Intra frames (0xffffffff=component default)", 0,
141           G_MAXUINT,
142           GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT,
143           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
144           GST_PARAM_MUTABLE_READY));
145
146   basevideoenc_class->flush = gst_omx_h264_enc_flush;
147   basevideoenc_class->stop = gst_omx_h264_enc_stop;
148
149   videoenc_class->cdata.default_src_template_caps = "video/x-h264, "
150       "width=(int) [ 16, 4096 ], " "height=(int) [ 16, 4096 ]";
151   videoenc_class->handle_output_frame =
152       GST_DEBUG_FUNCPTR (gst_omx_h264_enc_handle_output_frame);
153
154   gst_element_class_set_static_metadata (element_class,
155       "OpenMAX H.264 Video Encoder",
156       "Codec/Encoder/Video",
157       "Encode H.264 video streams",
158       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
159
160   gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.avc");
161 }
162
163 static void
164 gst_omx_h264_enc_set_property (GObject * object, guint prop_id,
165     const GValue * value, GParamSpec * pspec)
166 {
167   GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
168
169   switch (prop_id) {
170 #ifdef USE_OMX_TARGET_RPI
171     case PROP_INLINESPSPPSHEADERS:
172       self->inline_sps_pps_headers = g_value_get_boolean (value);
173       break;
174 #endif
175 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
176     case PROP_NUM_REF_FRAME:
177       self->reference_frame = g_value_get_int (value);
178       break;
179     case PROP_NUM_B_FRAME:
180       self->b_frame = g_value_get_int (value);
181       break;
182 #endif
183     case PROP_PERIODICITYOFIDRFRAMES:
184       self->periodicty_idr = g_value_get_uint (value);
185       break;
186     case PROP_INTERVALOFCODINGINTRAFRAMES:
187       self->interval_intraframes = g_value_get_uint (value);
188       break;
189     default:
190       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
191       break;
192   }
193 }
194
195 static void
196 gst_omx_h264_enc_get_property (GObject * object, guint prop_id, GValue * value,
197     GParamSpec * pspec)
198 {
199   GstOMXH264Enc *self = GST_OMX_H264_ENC (object);
200
201   switch (prop_id) {
202 #ifdef USE_OMX_TARGET_RPI
203     case PROP_INLINESPSPPSHEADERS:
204       g_value_set_boolean (value, self->inline_sps_pps_headers);
205       break;
206 #endif
207 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
208     case PROP_NUM_REF_FRAME:
209       g_value_set_uint (value, self->reference_frame);
210       break;
211     case PROP_NUM_B_FRAME:
212       g_value_set_uint (value, self->b_frame);
213       break;
214 #endif
215     case PROP_PERIODICITYOFIDRFRAMES:
216       g_value_set_uint (value, self->periodicty_idr);
217       break;
218     case PROP_INTERVALOFCODINGINTRAFRAMES:
219       g_value_set_uint (value, self->interval_intraframes);
220       break;
221     default:
222       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223       break;
224   }
225 }
226
227 static void
228 gst_omx_h264_enc_init (GstOMXH264Enc * self)
229 {
230 #ifdef USE_OMX_TARGET_RPI
231   self->inline_sps_pps_headers =
232       GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT;
233 #endif
234 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
235   self->reference_frame = GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT;
236 #endif
237   self->periodicty_idr =
238       GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT;
239   self->interval_intraframes =
240       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT;
241 }
242
243 static gboolean
244 gst_omx_h264_enc_flush (GstVideoEncoder * enc)
245 {
246   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
247
248   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
249   self->headers = NULL;
250
251   return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (enc);
252 }
253
254 static gboolean
255 gst_omx_h264_enc_stop (GstVideoEncoder * enc)
256 {
257   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
258
259   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
260   self->headers = NULL;
261
262   return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc);
263 }
264
265 static gboolean
266 gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
267     GstVideoCodecState * state)
268 {
269   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
270   GstCaps *peercaps;
271   OMX_PARAM_PORTDEFINITIONTYPE port_def;
272   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
273   OMX_VIDEO_CONFIG_AVCINTRAPERIOD config_avcintraperiod;
274 #ifdef USE_OMX_TARGET_RPI
275   OMX_CONFIG_PORTBOOLEANTYPE config_inline_header;
276 #endif
277 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
278   OMX_VIDEO_PARAM_AVCTYPE avc_param;
279 #endif
280   OMX_ERRORTYPE err;
281   const gchar *profile_string, *level_string;
282
283 #ifdef USE_OMX_TARGET_RPI
284   GST_OMX_INIT_STRUCT (&config_inline_header);
285   config_inline_header.nPortIndex =
286       GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
287   err =
288       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
289       OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header);
290   if (err != OMX_ErrorNone) {
291     GST_ERROR_OBJECT (self,
292         "can't get OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)",
293         gst_omx_error_to_string (err), err);
294     return FALSE;
295   }
296
297   if (self->inline_sps_pps_headers) {
298     config_inline_header.bEnabled = OMX_TRUE;
299   } else {
300     config_inline_header.bEnabled = OMX_FALSE;
301   }
302
303   err =
304       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
305       OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header);
306   if (err != OMX_ErrorNone) {
307     GST_ERROR_OBJECT (self,
308         "can't set OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)",
309         gst_omx_error_to_string (err), err);
310     return FALSE;
311   }
312 #endif
313 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
314   GST_OMX_INIT_STRUCT (&avc_param);
315
316   err =
317       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
318       OMX_IndexParamVideoAvc, &avc_param);
319   if (err != OMX_ErrorNone) {
320     GST_ERROR_OBJECT (self,
321         "can't get OMX_IndexParamVideoAvc %s (0x%08x)",
322         gst_omx_error_to_string (err), err);
323     return FALSE;
324   }
325
326   GST_DEBUG_OBJECT (self, "default nRefFrames:%u, nBFrames:%u",
327       (guint) avc_param.nRefFrames,
328       (guint) avc_param.nBFrames);
329
330   avc_param.nRefFrames = self->reference_frame;
331   avc_param.nBFrames = self->b_frame;
332   err =
333       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
334       OMX_IndexParamVideoAvc, &avc_param);
335   if (err != OMX_ErrorNone) {
336     GST_ERROR_OBJECT (self,
337         "can't set OMX_IndexParamVideoAvc %s (0x%08x)",
338         gst_omx_error_to_string (err), err);
339     return FALSE;
340   }
341
342 #endif
343
344   if (self->periodicty_idr !=
345       GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT
346       || self->interval_intraframes !=
347       GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
348
349
350     GST_OMX_INIT_STRUCT (&config_avcintraperiod);
351     config_avcintraperiod.nPortIndex =
352         GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
353     err =
354         gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
355         OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod);
356     if (err != OMX_ErrorNone) {
357       GST_ERROR_OBJECT (self,
358           "can't get OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
359           gst_omx_error_to_string (err), err);
360       return FALSE;
361     }
362
363     GST_DEBUG_OBJECT (self, "default nPFrames:%u, nIDRPeriod:%u",
364         (guint) config_avcintraperiod.nPFrames,
365         (guint) config_avcintraperiod.nIDRPeriod);
366
367     if (self->periodicty_idr !=
368         GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT) {
369       config_avcintraperiod.nIDRPeriod = self->periodicty_idr;
370     }
371
372     if (self->interval_intraframes !=
373         GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
374       config_avcintraperiod.nPFrames = self->interval_intraframes;
375     }
376
377     err =
378         gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
379         OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod);
380     if (err != OMX_ErrorNone) {
381       GST_ERROR_OBJECT (self,
382           "can't set OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
383           gst_omx_error_to_string (err), err);
384       return FALSE;
385     }
386   }
387
388   gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
389       &port_def);
390   port_def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
391   err =
392       gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
393       (self)->enc_out_port, &port_def);
394   if (err != OMX_ErrorNone)
395     return FALSE;
396
397   GST_OMX_INIT_STRUCT (&param);
398   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
399
400   err =
401       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
402       OMX_IndexParamVideoProfileLevelCurrent, &param);
403   if (err != OMX_ErrorNone) {
404     GST_WARNING_OBJECT (self,
405         "Setting profile/level not supported by component");
406     return TRUE;
407   }
408
409   peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc),
410       gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc)));
411   if (peercaps) {
412     GstStructure *s;
413
414     if (gst_caps_is_empty (peercaps)) {
415       gst_caps_unref (peercaps);
416       GST_ERROR_OBJECT (self, "Empty caps");
417       return FALSE;
418     }
419
420     s = gst_caps_get_structure (peercaps, 0);
421     profile_string = gst_structure_get_string (s, "profile");
422     if (profile_string) {
423       if (g_str_equal (profile_string, "baseline")) {
424         param.eProfile = OMX_VIDEO_AVCProfileBaseline;
425       } else if (g_str_equal (profile_string, "main")) {
426         param.eProfile = OMX_VIDEO_AVCProfileMain;
427       } else if (g_str_equal (profile_string, "extended")) {
428         param.eProfile = OMX_VIDEO_AVCProfileExtended;
429       } else if (g_str_equal (profile_string, "high")) {
430         param.eProfile = OMX_VIDEO_AVCProfileHigh;
431       } else if (g_str_equal (profile_string, "high-10")) {
432         param.eProfile = OMX_VIDEO_AVCProfileHigh10;
433       } else if (g_str_equal (profile_string, "high-4:2:2")) {
434         param.eProfile = OMX_VIDEO_AVCProfileHigh422;
435       } else if (g_str_equal (profile_string, "high-4:4:4")) {
436         param.eProfile = OMX_VIDEO_AVCProfileHigh444;
437       } else {
438         goto unsupported_profile;
439       }
440     }
441     level_string = gst_structure_get_string (s, "level");
442     if (level_string) {
443       if (g_str_equal (level_string, "1")) {
444         param.eLevel = OMX_VIDEO_AVCLevel1;
445       } else if (g_str_equal (level_string, "1b")) {
446         param.eLevel = OMX_VIDEO_AVCLevel1b;
447       } else if (g_str_equal (level_string, "1.1")) {
448         param.eLevel = OMX_VIDEO_AVCLevel11;
449       } else if (g_str_equal (level_string, "1.2")) {
450         param.eLevel = OMX_VIDEO_AVCLevel12;
451       } else if (g_str_equal (level_string, "1.3")) {
452         param.eLevel = OMX_VIDEO_AVCLevel13;
453       } else if (g_str_equal (level_string, "2")) {
454         param.eLevel = OMX_VIDEO_AVCLevel2;
455       } else if (g_str_equal (level_string, "2.1")) {
456         param.eLevel = OMX_VIDEO_AVCLevel21;
457       } else if (g_str_equal (level_string, "2.2")) {
458         param.eLevel = OMX_VIDEO_AVCLevel22;
459       } else if (g_str_equal (level_string, "3")) {
460         param.eLevel = OMX_VIDEO_AVCLevel3;
461       } else if (g_str_equal (level_string, "3.1")) {
462         param.eLevel = OMX_VIDEO_AVCLevel31;
463       } else if (g_str_equal (level_string, "3.2")) {
464         param.eLevel = OMX_VIDEO_AVCLevel32;
465       } else if (g_str_equal (level_string, "4")) {
466         param.eLevel = OMX_VIDEO_AVCLevel4;
467       } else if (g_str_equal (level_string, "4.1")) {
468         param.eLevel = OMX_VIDEO_AVCLevel41;
469       } else if (g_str_equal (level_string, "4.2")) {
470         param.eLevel = OMX_VIDEO_AVCLevel42;
471       } else if (g_str_equal (level_string, "5")) {
472         param.eLevel = OMX_VIDEO_AVCLevel5;
473       } else if (g_str_equal (level_string, "5.1")) {
474         param.eLevel = OMX_VIDEO_AVCLevel51;
475       } else {
476         goto unsupported_level;
477       }
478     }
479     gst_caps_unref (peercaps);
480   }
481
482   err =
483       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
484       OMX_IndexParamVideoProfileLevelCurrent, &param);
485   if (err == OMX_ErrorUnsupportedIndex) {
486     GST_WARNING_OBJECT (self,
487         "Setting profile/level not supported by component");
488   } else if (err != OMX_ErrorNone) {
489     GST_ERROR_OBJECT (self,
490         "Error setting profile %u and level %u: %s (0x%08x)",
491         (guint) param.eProfile, (guint) param.eLevel,
492         gst_omx_error_to_string (err), err);
493     return FALSE;
494   }
495
496   return TRUE;
497
498 unsupported_profile:
499   GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
500   gst_caps_unref (peercaps);
501   return FALSE;
502
503 unsupported_level:
504   GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
505   gst_caps_unref (peercaps);
506   return FALSE;
507 }
508
509 static GstCaps *
510 gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
511     GstVideoCodecState * state)
512 {
513   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
514   GstCaps *caps;
515   OMX_ERRORTYPE err;
516   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
517   const gchar *profile, *level;
518
519   caps = gst_caps_new_simple ("video/x-h264",
520       "stream-format", G_TYPE_STRING, "byte-stream",
521       "alignment", G_TYPE_STRING, "au", NULL);
522
523   GST_OMX_INIT_STRUCT (&param);
524   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
525
526   err =
527       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
528       OMX_IndexParamVideoProfileLevelCurrent, &param);
529   if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
530     return NULL;
531
532   if (err == OMX_ErrorNone) {
533     switch (param.eProfile) {
534       case OMX_VIDEO_AVCProfileBaseline:
535         profile = "baseline";
536         break;
537       case OMX_VIDEO_AVCProfileMain:
538         profile = "main";
539         break;
540       case OMX_VIDEO_AVCProfileExtended:
541         profile = "extended";
542         break;
543       case OMX_VIDEO_AVCProfileHigh:
544         profile = "high";
545         break;
546       case OMX_VIDEO_AVCProfileHigh10:
547         profile = "high-10";
548         break;
549       case OMX_VIDEO_AVCProfileHigh422:
550         profile = "high-4:2:2";
551         break;
552       case OMX_VIDEO_AVCProfileHigh444:
553         profile = "high-4:4:4";
554         break;
555       default:
556         g_assert_not_reached ();
557         return NULL;
558     }
559
560     switch (param.eLevel) {
561       case OMX_VIDEO_AVCLevel1:
562         level = "1";
563         break;
564       case OMX_VIDEO_AVCLevel1b:
565         level = "1b";
566         break;
567       case OMX_VIDEO_AVCLevel11:
568         level = "1.1";
569         break;
570       case OMX_VIDEO_AVCLevel12:
571         level = "1.2";
572         break;
573       case OMX_VIDEO_AVCLevel13:
574         level = "1.3";
575         break;
576       case OMX_VIDEO_AVCLevel2:
577         level = "2";
578         break;
579       case OMX_VIDEO_AVCLevel21:
580         level = "2.1";
581         break;
582       case OMX_VIDEO_AVCLevel22:
583         level = "2.2";
584         break;
585       case OMX_VIDEO_AVCLevel3:
586         level = "3";
587         break;
588       case OMX_VIDEO_AVCLevel31:
589         level = "3.1";
590         break;
591       case OMX_VIDEO_AVCLevel32:
592         level = "3.2";
593         break;
594       case OMX_VIDEO_AVCLevel4:
595         level = "4";
596         break;
597       case OMX_VIDEO_AVCLevel41:
598         level = "4.1";
599         break;
600       case OMX_VIDEO_AVCLevel42:
601         level = "4.2";
602         break;
603       case OMX_VIDEO_AVCLevel5:
604         level = "5";
605         break;
606       case OMX_VIDEO_AVCLevel51:
607         level = "5.1";
608         break;
609       default:
610         g_assert_not_reached ();
611         return NULL;
612     }
613     gst_caps_set_simple (caps,
614         "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level, NULL);
615   }
616
617   return caps;
618 }
619
620 static GstFlowReturn
621 gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * enc, GstOMXPort * port,
622     GstOMXBuffer * buf, GstVideoCodecFrame * frame)
623 {
624   GstOMXH264Enc *self = GST_OMX_H264_ENC (enc);
625
626   if (buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
627     /* The codec data is SPS/PPS with a startcode => bytestream stream format
628      * For bytestream stream format the SPS/PPS is only in-stream and not
629      * in the caps!
630      */
631     if (buf->omx_buf->nFilledLen >= 4 &&
632         GST_READ_UINT32_BE (buf->omx_buf->pBuffer +
633             buf->omx_buf->nOffset) == 0x00000001) {
634       GstBuffer *hdrs;
635       GstMapInfo map = GST_MAP_INFO_INIT;
636
637       GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
638
639       hdrs = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
640
641       gst_buffer_map (hdrs, &map, GST_MAP_WRITE);
642       memcpy (map.data,
643           buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
644           buf->omx_buf->nFilledLen);
645       gst_buffer_unmap (hdrs, &map);
646       self->headers = g_list_append (self->headers, hdrs);
647
648       if (frame)
649         gst_video_codec_frame_unref (frame);
650
651       return GST_FLOW_OK;
652     }
653   } else if (self->headers) {
654     gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), self->headers);
655     self->headers = NULL;
656   }
657
658   return
659       GST_OMX_VIDEO_ENC_CLASS
660       (gst_omx_h264_enc_parent_class)->handle_output_frame (enc, port, buf,
661       frame);
662 }