omxvideodec: support interlace-mode=interleaved input
[platform/upstream/gstreamer.git] / omx / gstomxh265enc.c
1 /*
2  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3  * Copyright (C) 2017 Xilinx, Inc.
4  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gst/gst.h>
27
28 #include "gstomxh265enc.h"
29 #include "gstomxh265utils.h"
30 #include "gstomxvideo.h"
31
32 GST_DEBUG_CATEGORY_STATIC (gst_omx_h265_enc_debug_category);
33 #define GST_CAT_DEFAULT gst_omx_h265_enc_debug_category
34
35 /* prototypes */
36 static gboolean gst_omx_h265_enc_set_format (GstOMXVideoEnc * enc,
37     GstOMXPort * port, GstVideoCodecState * state);
38 static GstCaps *gst_omx_h265_enc_get_caps (GstOMXVideoEnc * enc,
39     GstOMXPort * port, GstVideoCodecState * state);
40 static void gst_omx_h265_enc_set_property (GObject * object, guint prop_id,
41     const GValue * value, GParamSpec * pspec);
42 static void gst_omx_h265_enc_get_property (GObject * object, guint prop_id,
43     GValue * value, GParamSpec * pspec);
44 static GstFlowReturn gst_omx_h265_enc_handle_output_frame (GstOMXVideoEnc *
45     self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame);
46
47 enum
48 {
49   PROP_0,
50   PROP_PERIODICITYOFIDRFRAMES,
51   PROP_INTERVALOFCODINGINTRAFRAMES,
52   PROP_B_FRAMES,
53   PROP_CONSTRAINED_INTRA_PREDICTION,
54   PROP_LOOP_FILTER_MODE,
55 };
56
57 #define GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT    (0xffffffff)
58 #define GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
59 #define GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
60 #define GST_OMX_H265_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT (FALSE)
61 #define GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT (0xffffffff)
62
63 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
64 /* zynqultrascaleplus's OMX uses a param struct different of Android's one */
65 #define INDEX_PARAM_VIDEO_HEVC OMX_ALG_IndexParamVideoHevc
66 #define ALIGNMENT "{ au, nal }"
67 #else
68 #define INDEX_PARAM_VIDEO_HEVC OMX_IndexParamVideoHevc
69 #define ALIGNMENT "au"
70 #endif
71
72 /* class initialization */
73
74 #define DEBUG_INIT \
75   GST_DEBUG_CATEGORY_INIT (gst_omx_h265_enc_debug_category, "omxh265enc", 0, \
76       "debug category for gst-omx H265 video encoder");
77
78 #define parent_class gst_omx_h265_enc_parent_class
79 G_DEFINE_TYPE_WITH_CODE (GstOMXH265Enc, gst_omx_h265_enc,
80     GST_TYPE_OMX_VIDEO_ENC, DEBUG_INIT);
81
82 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
83 #define GST_TYPE_OMX_H265_ENC_LOOP_FILTER_MODE (gst_omx_h265_enc_loop_filter_mode_get_type ())
84 static GType
85 gst_omx_h265_enc_loop_filter_mode_get_type (void)
86 {
87   static GType qtype = 0;
88
89   if (qtype == 0) {
90     static const GEnumValue values[] = {
91       {OMX_ALG_VIDEO_HEVCLoopFilterEnable, "Enable deblocking filter",
92           "enable"},
93       {OMX_ALG_VIDEO_HEVCLoopFilterDisable, "Disable deblocking filter",
94           "disable"},
95       {OMX_ALG_VIDEO_HEVCLoopFilterDisableCrossSlice,
96           "Disable deblocking filter on slice boundary", "disable-cross-slice"},
97       {OMX_ALG_VIDEO_HEVCLoopFilterDisableCrossTile,
98           "Disable deblocking filter on tile boundary", "disable-cross-tile"},
99       {OMX_ALG_VIDEO_HEVCLoopFilterDisableCrossSliceAndTile,
100             "Disable deblocking filter on slice and tile boundary",
101           "disable-slice-and-tile"},
102       {0xffffffff, "Component Default", "default"},
103       {0, NULL, NULL}
104     };
105
106     qtype = g_enum_register_static ("GstOMXH265EncLoopFilter", values);
107   }
108   return qtype;
109 }
110 #endif
111
112 static gboolean
113 gst_omx_h265_enc_flush (GstVideoEncoder * enc)
114 {
115   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
116
117   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
118   self->headers = NULL;
119
120   return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (enc);
121 }
122
123 static gboolean
124 gst_omx_h265_enc_stop (GstVideoEncoder * enc)
125 {
126   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
127
128   g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref);
129   self->headers = NULL;
130
131   return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc);
132 }
133
134 static void
135 gst_omx_h265_enc_class_init (GstOMXH265EncClass * klass)
136 {
137   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
138   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
139   GstVideoEncoderClass *basevideoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
140   GstOMXVideoEncClass *videoenc_class = GST_OMX_VIDEO_ENC_CLASS (klass);
141
142   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_h265_enc_set_format);
143   videoenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_h265_enc_get_caps);
144   videoenc_class->handle_output_frame =
145       GST_DEBUG_FUNCPTR (gst_omx_h265_enc_handle_output_frame);
146
147   basevideoenc_class->flush = gst_omx_h265_enc_flush;
148   basevideoenc_class->stop = gst_omx_h265_enc_stop;
149
150   gobject_class->set_property = gst_omx_h265_enc_set_property;
151   gobject_class->get_property = gst_omx_h265_enc_get_property;
152
153   g_object_class_install_property (gobject_class,
154       PROP_INTERVALOFCODINGINTRAFRAMES,
155       g_param_spec_uint ("interval-intraframes",
156           "Interval of coding Intra frames",
157           "Interval of coding Intra frames (0xffffffff=component default)", 0,
158           G_MAXUINT,
159           GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT,
160           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
161           GST_PARAM_MUTABLE_READY));
162
163 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
164   g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES,
165       g_param_spec_uint ("periodicity-idr", "IDR periodicity",
166           "Periodicity of IDR frames (0xffffffff=component default)",
167           0, G_MAXUINT,
168           GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
169           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
170           GST_PARAM_MUTABLE_READY));
171
172   g_object_class_install_property (gobject_class, PROP_B_FRAMES,
173       g_param_spec_uint ("b-frames", "Number of B-frames",
174           "Number of B-frames between two consecutive I-frames (0xffffffff=component default)",
175           0, G_MAXUINT, GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT,
176           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
177           GST_PARAM_MUTABLE_READY));
178
179   g_object_class_install_property (gobject_class,
180       PROP_CONSTRAINED_INTRA_PREDICTION,
181       g_param_spec_boolean ("constrained-intra-prediction",
182           "Constrained Intra Prediction",
183           "If enabled, prediction only uses residual data and decoded samples "
184           "from neighbouring coding blocks coded using intra prediction modes",
185           GST_OMX_H265_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT,
186           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
187           GST_PARAM_MUTABLE_READY));
188
189   g_object_class_install_property (gobject_class, PROP_LOOP_FILTER_MODE,
190       g_param_spec_enum ("loop-filter-mode", "Loop Filter mode",
191           "Enable or disable the deblocking filter (0xffffffff=component default)",
192           GST_TYPE_OMX_H265_ENC_LOOP_FILTER_MODE,
193           GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT,
194           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
195           GST_PARAM_MUTABLE_READY));
196 #endif
197
198   videoenc_class->cdata.default_sink_template_caps =
199 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
200       GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_FORMAT_INTERLACED,
201       GST_OMX_VIDEO_ENC_SUPPORTED_FORMATS)
202       ", interlace-mode = (string) alternate ; "
203 #endif
204       GST_VIDEO_CAPS_MAKE (GST_OMX_VIDEO_ENC_SUPPORTED_FORMATS);
205
206   videoenc_class->cdata.default_src_template_caps = "video/x-h265, "
207       "width=(int) [ 1, MAX ], " "height=(int) [ 1, MAX ], "
208       "framerate = (fraction) [0, MAX], stream-format=(string) byte-stream, "
209       "aligmment = (string) " ALIGNMENT;
210
211   gst_element_class_set_static_metadata (element_class,
212       "OpenMAX H.265 Video Encoder",
213       "Codec/Encoder/Video/Hardware",
214       "Encode H.265 video streams",
215       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
216
217   gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.hevc");
218 }
219
220 static void
221 gst_omx_h265_enc_set_property (GObject * object, guint prop_id,
222     const GValue * value, GParamSpec * pspec)
223 {
224   GstOMXH265Enc *self = GST_OMX_H265_ENC (object);
225
226   switch (prop_id) {
227     case PROP_INTERVALOFCODINGINTRAFRAMES:
228       self->interval_intraframes = g_value_get_uint (value);
229       break;
230 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
231     case PROP_PERIODICITYOFIDRFRAMES:
232       self->periodicity_idr = g_value_get_uint (value);
233       break;
234     case PROP_B_FRAMES:
235       self->b_frames = g_value_get_uint (value);
236       break;
237     case PROP_CONSTRAINED_INTRA_PREDICTION:
238       self->constrained_intra_prediction = g_value_get_boolean (value);
239       break;
240     case PROP_LOOP_FILTER_MODE:
241       self->loop_filter_mode = g_value_get_enum (value);
242       break;
243 #endif
244     default:
245       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
246       break;
247   }
248 }
249
250 static void
251 gst_omx_h265_enc_get_property (GObject * object, guint prop_id, GValue * value,
252     GParamSpec * pspec)
253 {
254   GstOMXH265Enc *self = GST_OMX_H265_ENC (object);
255
256   switch (prop_id) {
257     case PROP_INTERVALOFCODINGINTRAFRAMES:
258       g_value_set_uint (value, self->interval_intraframes);
259       break;
260 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
261     case PROP_PERIODICITYOFIDRFRAMES:
262       g_value_set_uint (value, self->periodicity_idr);
263       break;
264     case PROP_B_FRAMES:
265       g_value_set_uint (value, self->b_frames);
266       break;
267     case PROP_CONSTRAINED_INTRA_PREDICTION:
268       g_value_set_boolean (value, self->constrained_intra_prediction);
269       break;
270     case PROP_LOOP_FILTER_MODE:
271       g_value_set_enum (value, self->loop_filter_mode);
272       break;
273 #endif
274     default:
275       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276       break;
277   }
278 }
279
280 static void
281 gst_omx_h265_enc_init (GstOMXH265Enc * self)
282 {
283   self->interval_intraframes =
284       GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT;
285 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
286   self->periodicity_idr =
287       GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT;
288   self->b_frames = GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT;
289   self->constrained_intra_prediction =
290       GST_OMX_H265_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT;
291   self->loop_filter_mode = GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT;
292 #endif
293 }
294
295 /* Update OMX_VIDEO_PARAM_PROFILELEVELTYPE.{eProfile,eLevel}
296  *
297  * Returns TRUE if succeeded or if not supported, FALSE if failed */
298 static gboolean
299 update_param_profile_level (GstOMXH265Enc * self,
300     OMX_VIDEO_HEVCPROFILETYPE profile, OMX_VIDEO_HEVCLEVELTYPE level)
301 {
302   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
303   OMX_ERRORTYPE err;
304
305   GST_OMX_INIT_STRUCT (&param);
306   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
307
308   err =
309       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
310       OMX_IndexParamVideoProfileLevelCurrent, &param);
311   if (err != OMX_ErrorNone) {
312     GST_WARNING_OBJECT (self,
313         "Getting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
314     return TRUE;
315   }
316
317   if (profile != OMX_VIDEO_HEVCProfileUnknown)
318     param.eProfile = profile;
319   if (level != OMX_VIDEO_HEVCLevelUnknown)
320     param.eLevel = level;
321
322   err =
323       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
324       OMX_IndexParamVideoProfileLevelCurrent, &param);
325   if (err == OMX_ErrorUnsupportedIndex) {
326     GST_WARNING_OBJECT (self,
327         "Setting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
328     return TRUE;
329   } else if (err != OMX_ErrorNone) {
330     GST_ERROR_OBJECT (self,
331         "Error setting profile %u and level %u: %s (0x%08x)",
332         (guint) param.eProfile, (guint) param.eLevel,
333         gst_omx_error_to_string (err), err);
334     return FALSE;
335   }
336
337   return TRUE;
338 }
339
340 /* Update OMX_ALG_VIDEO_PARAM_HEVCTYPE
341  *
342  * Returns TRUE if succeeded or if not supported, FALSE if failed */
343 static gboolean
344 update_param_hevc (GstOMXH265Enc * self,
345     OMX_VIDEO_HEVCPROFILETYPE profile, OMX_VIDEO_HEVCLEVELTYPE level)
346 {
347 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
348   OMX_ALG_VIDEO_PARAM_HEVCTYPE param;
349 #else
350   OMX_VIDEO_PARAM_HEVCTYPE param;
351 #endif
352   OMX_ERRORTYPE err;
353
354   GST_OMX_INIT_STRUCT (&param);
355   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
356
357   /* On Android the param struct is initialized manually with default
358    * settings rather than using GetParameter() to retrieve them.
359    * We should probably do the same when we'll add Android as target.
360    * See bgo#783862 for details. */
361
362 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
363   param.bConstIpred = self->constrained_intra_prediction;
364
365   if (self->loop_filter_mode != GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT)
366     param.eLoopFilterMode = self->loop_filter_mode;
367
368   err =
369       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
370       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoHevc, &param);
371 #else
372   err =
373       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
374       (OMX_INDEXTYPE) OMX_IndexParamVideoHevc, &param);
375 #endif
376
377   if (err != OMX_ErrorNone) {
378     GST_WARNING_OBJECT (self,
379         "Getting OMX_ALG_IndexParamVideoHevc not supported by component");
380     return TRUE;
381   }
382
383   if (profile != OMX_VIDEO_HEVCProfileUnknown)
384 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
385     param.eProfile = (OMX_ALG_VIDEO_HEVCPROFILETYPE) profile;
386 #else
387     param.eProfile = profile;
388 #endif
389
390   if (level != OMX_VIDEO_HEVCLevelUnknown)
391 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
392     param.eLevel = (OMX_ALG_VIDEO_HEVCLEVELTYPE) level;
393 #else
394     param.eLevel = level;
395 #endif
396
397   /* GOP pattern */
398 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
399   /* The zynqultrascaleplus uses another PARAM_HEVCTYPE API allowing users to
400    * define the number of P and B frames while Android's API only expose the
401    * former. */
402   if (self->interval_intraframes !=
403       GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
404     param.nPFrames = self->interval_intraframes;
405
406     /* If user specified a specific number of B-frames, reduce the number of
407      * P-frames by this amount. If not ensure there is no B-frame to have the
408      * requested GOP length. */
409     if (self->b_frames != GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT) {
410       if (self->b_frames > self->interval_intraframes) {
411         GST_ERROR_OBJECT (self,
412             "The interval_intraframes perdiod (%u) needs to be higher than the number of B-frames (%u)",
413             self->interval_intraframes, self->b_frames);
414         return FALSE;
415       }
416       param.nPFrames -= self->b_frames;
417     } else {
418       param.nBFrames = 0;
419     }
420   }
421
422   if (self->b_frames != GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT)
423     param.nBFrames = self->b_frames;
424 #else
425   if (self->interval_intraframes !=
426       GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT)
427     param.nKeyFrameInterval = self->interval_intraframes;
428 #endif
429
430   err =
431       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
432       (OMX_INDEXTYPE) INDEX_PARAM_VIDEO_HEVC, &param);
433
434   if (err == OMX_ErrorUnsupportedIndex) {
435     GST_WARNING_OBJECT (self,
436         "Setting IndexParamVideoHevc not supported by component");
437     return TRUE;
438   } else if (err != OMX_ErrorNone) {
439     GST_ERROR_OBJECT (self,
440         "Error setting HEVC settings (profile %u and level %u): %s (0x%08x)",
441         (guint) param.eProfile, (guint) param.eLevel,
442         gst_omx_error_to_string (err), err);
443     return FALSE;
444   }
445
446   return TRUE;
447 }
448
449 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
450 static gboolean
451 set_intra_period (GstOMXH265Enc * self)
452 {
453   OMX_ALG_VIDEO_PARAM_INSTANTANEOUS_DECODING_REFRESH config_idr;
454   OMX_ERRORTYPE err;
455
456   GST_OMX_INIT_STRUCT (&config_idr);
457   config_idr.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
458
459   GST_DEBUG_OBJECT (self, "nIDRPeriod:%u",
460       (guint) config_idr.nInstantaneousDecodingRefreshFrequency);
461
462   config_idr.nInstantaneousDecodingRefreshFrequency = self->periodicity_idr;
463
464   err =
465       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
466       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoInstantaneousDecodingRefresh,
467       &config_idr);
468   if (err != OMX_ErrorNone) {
469     GST_ERROR_OBJECT (self,
470         "can't set OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
471         gst_omx_error_to_string (err), err);
472     return FALSE;
473   }
474
475   return TRUE;
476 }
477 #endif
478
479 static gboolean
480 gst_omx_h265_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
481     GstVideoCodecState * state)
482 {
483   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
484   GstCaps *peercaps;
485   OMX_PARAM_PORTDEFINITIONTYPE port_def;
486   OMX_ERRORTYPE err;
487   const gchar *profile_string, *level_string, *tier_string;
488   OMX_VIDEO_HEVCPROFILETYPE profile = OMX_VIDEO_HEVCProfileUnknown;
489   OMX_VIDEO_HEVCLEVELTYPE level = OMX_VIDEO_HEVCLevelUnknown;
490   gboolean enable_subframe = FALSE;
491
492 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
493   if (self->periodicity_idr !=
494       GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT)
495     set_intra_period (self);
496 #endif
497
498   gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
499       &port_def);
500   port_def.format.video.eCompressionFormat =
501       (OMX_VIDEO_CODINGTYPE) OMX_VIDEO_CodingHEVC;
502   err =
503       gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
504       (self)->enc_out_port, &port_def);
505   if (err != OMX_ErrorNone)
506     return FALSE;
507
508   /* Set profile and level */
509   peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc),
510       gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc)));
511   if (peercaps) {
512     GstStructure *s;
513     const gchar *alignment_string;
514
515     if (gst_caps_is_empty (peercaps)) {
516       gst_caps_unref (peercaps);
517       GST_ERROR_OBJECT (self, "Empty caps");
518       return FALSE;
519     }
520
521     s = gst_caps_get_structure (peercaps, 0);
522     profile_string = gst_structure_get_string (s, "profile");
523     if (profile_string) {
524       profile = gst_omx_h265_utils_get_profile_from_str (profile_string);
525       if (profile == OMX_VIDEO_HEVCProfileUnknown)
526         goto unsupported_profile;
527     }
528
529     level_string = gst_structure_get_string (s, "level");
530     tier_string = gst_structure_get_string (s, "tier");
531     if (level_string && tier_string) {
532       level = gst_omx_h265_utils_get_level_from_str (level_string, tier_string);
533       if (level == OMX_VIDEO_HEVCLevelUnknown)
534         goto unsupported_level;
535     }
536
537     alignment_string = gst_structure_get_string (s, "alignment");
538     if (alignment_string && g_str_equal (alignment_string, "nal"))
539       enable_subframe = TRUE;
540
541     gst_caps_unref (peercaps);
542   }
543
544   if (profile != OMX_VIDEO_HEVCProfileUnknown
545       || level != OMX_VIDEO_HEVCLevelUnknown) {
546     /* OMX provides 2 API to set the profile and level. We try using the
547      * generic one here and the H265 specific when calling
548      * update_param_hevc() */
549     if (!update_param_profile_level (self, profile, level))
550       return FALSE;
551   }
552
553   if (!update_param_hevc (self, profile, level))
554     return FALSE;
555
556   gst_omx_port_set_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port,
557       enable_subframe);
558
559   return TRUE;
560
561 unsupported_profile:
562   GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
563   gst_caps_unref (peercaps);
564   return FALSE;
565
566 unsupported_level:
567   GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
568   gst_caps_unref (peercaps);
569   return FALSE;
570 }
571
572 static GstCaps *
573 gst_omx_h265_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
574     GstVideoCodecState * state)
575 {
576   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
577   GstCaps *caps;
578   OMX_ERRORTYPE err;
579   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
580   const gchar *profile, *level, *tier, *alignment;
581
582   GST_OMX_INIT_STRUCT (&param);
583   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
584
585   err =
586       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
587       OMX_IndexParamVideoProfileLevelCurrent, &param);
588   if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
589     return NULL;
590
591   if (gst_omx_port_get_subframe (GST_OMX_VIDEO_ENC (self)->enc_out_port))
592     alignment = "nal";
593   else
594     alignment = "au";
595
596   caps = gst_caps_new_simple ("video/x-h265",
597       "stream-format", G_TYPE_STRING, "byte-stream",
598       "alignment", G_TYPE_STRING, alignment, NULL);
599
600   if (err == OMX_ErrorNone) {
601     profile = gst_omx_h265_utils_get_profile_from_enum (param.eProfile);
602     if (!profile) {
603       g_assert_not_reached ();
604       gst_caps_unref (caps);
605       return NULL;
606     }
607
608     switch (param.eLevel) {
609       case OMX_VIDEO_HEVCMainTierLevel1:
610         tier = "main";
611         level = "1";
612         break;
613       case OMX_VIDEO_HEVCMainTierLevel2:
614         tier = "main";
615         level = "2";
616         break;
617       case OMX_VIDEO_HEVCMainTierLevel21:
618         tier = "main";
619         level = "2.1";
620         break;
621       case OMX_VIDEO_HEVCMainTierLevel3:
622         tier = "main";
623         level = "3";
624         break;
625       case OMX_VIDEO_HEVCMainTierLevel31:
626         tier = "main";
627         level = "3.1";
628         break;
629       case OMX_VIDEO_HEVCMainTierLevel4:
630         tier = "main";
631         level = "4";
632         break;
633       case OMX_VIDEO_HEVCMainTierLevel41:
634         tier = "main";
635         level = "4.1";
636         break;
637       case OMX_VIDEO_HEVCMainTierLevel5:
638         tier = "main";
639         level = "5";
640         break;
641       case OMX_VIDEO_HEVCMainTierLevel51:
642         tier = "main";
643         level = "5.1";
644         break;
645       case OMX_VIDEO_HEVCMainTierLevel52:
646         tier = "main";
647         level = "5.2";
648         break;
649       case OMX_VIDEO_HEVCMainTierLevel6:
650         tier = "main";
651         level = "6";
652         break;
653       case OMX_VIDEO_HEVCMainTierLevel61:
654         tier = "main";
655         level = "6.1";
656         break;
657       case OMX_VIDEO_HEVCMainTierLevel62:
658         tier = "main";
659         level = "6.2";
660         break;
661       case OMX_VIDEO_HEVCHighTierLevel4:
662         tier = "high";
663         level = "4";
664         break;
665       case OMX_VIDEO_HEVCHighTierLevel41:
666         tier = "high";
667         level = "4.1";
668         break;
669       case OMX_VIDEO_HEVCHighTierLevel5:
670         tier = "high";
671         level = "5";
672         break;
673       case OMX_VIDEO_HEVCHighTierLevel51:
674         tier = "high";
675         level = "5.1";
676         break;
677       case OMX_VIDEO_HEVCHighTierLevel52:
678         tier = "high";
679         level = "5.2";
680         break;
681       case OMX_VIDEO_HEVCHighTierLevel6:
682         tier = "high";
683         level = "6";
684         break;
685       case OMX_VIDEO_HEVCHighTierLevel61:
686         tier = "high";
687         level = "6.1";
688         break;
689       case OMX_VIDEO_HEVCHighTierLevel62:
690         tier = "high";
691         level = "6.2";
692         break;
693       default:
694         g_assert_not_reached ();
695         gst_caps_unref (caps);
696         return NULL;
697     }
698
699     gst_caps_set_simple (caps,
700         "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level,
701         "tier", G_TYPE_STRING, tier, NULL);
702   }
703
704   return caps;
705 }
706
707 static GstFlowReturn
708 gst_omx_h265_enc_handle_output_frame (GstOMXVideoEnc * enc, GstOMXPort * port,
709     GstOMXBuffer * buf, GstVideoCodecFrame * frame)
710 {
711   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
712
713   if (buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
714     /* The codec data is SPS/PPS but our output is stream-format=byte-stream.
715      * For bytestream stream format the SPS/PPS is only in-stream and not
716      * in the caps!
717      */
718     GstBuffer *hdrs;
719     GstMapInfo map = GST_MAP_INFO_INIT;
720     GstFlowReturn flow_ret;
721
722     GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format");
723
724     hdrs = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
725     GST_BUFFER_FLAG_SET (hdrs, GST_BUFFER_FLAG_HEADER);
726
727     gst_buffer_map (hdrs, &map, GST_MAP_WRITE);
728     memcpy (map.data,
729         buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
730         buf->omx_buf->nFilledLen);
731     gst_buffer_unmap (hdrs, &map);
732     self->headers = g_list_append (self->headers, gst_buffer_ref (hdrs));
733     frame->output_buffer = hdrs;
734     flow_ret =
735         gst_video_encoder_finish_subframe (GST_VIDEO_ENCODER (self), frame);
736     gst_video_codec_frame_unref (frame);
737
738     return flow_ret;
739   } else if (self->headers) {
740     gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), self->headers);
741     self->headers = NULL;
742   }
743
744   return
745       GST_OMX_VIDEO_ENC_CLASS
746       (gst_omx_h265_enc_parent_class)->handle_output_frame (enc, port, buf,
747       frame);
748 }