omxvideoenc: drain encoder on ALLOCATION and DRAIN queries
[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
31 GST_DEBUG_CATEGORY_STATIC (gst_omx_h265_enc_debug_category);
32 #define GST_CAT_DEFAULT gst_omx_h265_enc_debug_category
33
34 /* prototypes */
35 static gboolean gst_omx_h265_enc_set_format (GstOMXVideoEnc * enc,
36     GstOMXPort * port, GstVideoCodecState * state);
37 static GstCaps *gst_omx_h265_enc_get_caps (GstOMXVideoEnc * enc,
38     GstOMXPort * port, GstVideoCodecState * state);
39 static void gst_omx_h265_enc_set_property (GObject * object, guint prop_id,
40     const GValue * value, GParamSpec * pspec);
41 static void gst_omx_h265_enc_get_property (GObject * object, guint prop_id,
42     GValue * value, GParamSpec * pspec);
43
44 enum
45 {
46   PROP_0,
47   PROP_PERIODICITYOFIDRFRAMES,
48   PROP_INTERVALOFCODINGINTRAFRAMES,
49   PROP_B_FRAMES,
50   PROP_CONSTRAINED_INTRA_PREDICTION,
51   PROP_LOOP_FILTER_MODE,
52 };
53
54 #define GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT    (0xffffffff)
55 #define GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
56 #define GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
57 #define GST_OMX_H265_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT (FALSE)
58 #define GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT (0xffffffff)
59
60 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
61 /* zynqultrascaleplus's OMX uses a param struct different of Android's one */
62 #define INDEX_PARAM_VIDEO_HEVC OMX_ALG_IndexParamVideoHevc
63 #else
64 #define INDEX_PARAM_VIDEO_HEVC OMX_IndexParamVideoHevc
65 #endif
66
67 /* class initialization */
68
69 #define DEBUG_INIT \
70   GST_DEBUG_CATEGORY_INIT (gst_omx_h265_enc_debug_category, "omxh265enc", 0, \
71       "debug category for gst-omx H265 video encoder");
72
73 #define parent_class gst_omx_h265_enc_parent_class
74 G_DEFINE_TYPE_WITH_CODE (GstOMXH265Enc, gst_omx_h265_enc,
75     GST_TYPE_OMX_VIDEO_ENC, DEBUG_INIT);
76
77 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
78 #define GST_TYPE_OMX_H265_ENC_LOOP_FILTER_MODE (gst_omx_h265_enc_loop_filter_mode_get_type ())
79 static GType
80 gst_omx_h265_enc_loop_filter_mode_get_type (void)
81 {
82   static GType qtype = 0;
83
84   if (qtype == 0) {
85     static const GEnumValue values[] = {
86       {OMX_ALG_VIDEO_HEVCLoopFilterEnable, "Enable deblocking filter",
87           "enable"},
88       {OMX_ALG_VIDEO_HEVCLoopFilterDisable, "Disable deblocking filter",
89           "disable"},
90       {OMX_ALG_VIDEO_HEVCLoopFilterDisableCrossSlice,
91           "Disable deblocking filter on slice boundary", "disable-cross-slice"},
92       {OMX_ALG_VIDEO_HEVCLoopFilterDisableCrossTile,
93           "Disable deblocking filter on tile boundary", "disable-cross-tile"},
94       {OMX_ALG_VIDEO_HEVCLoopFilterDisableCrossSliceAndTile,
95             "Disable deblocking filter on slice and tile boundary",
96           "disable-slice-and-tile"},
97       {0xffffffff, "Component Default", "default"},
98       {0, NULL, NULL}
99     };
100
101     qtype = g_enum_register_static ("GstOMXH265EncLoopFilter", values);
102   }
103   return qtype;
104 }
105 #endif
106
107 static void
108 gst_omx_h265_enc_class_init (GstOMXH265EncClass * klass)
109 {
110   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
111   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
112   GstOMXVideoEncClass *videoenc_class = GST_OMX_VIDEO_ENC_CLASS (klass);
113
114   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_h265_enc_set_format);
115   videoenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_h265_enc_get_caps);
116
117   gobject_class->set_property = gst_omx_h265_enc_set_property;
118   gobject_class->get_property = gst_omx_h265_enc_get_property;
119
120   g_object_class_install_property (gobject_class,
121       PROP_INTERVALOFCODINGINTRAFRAMES,
122       g_param_spec_uint ("interval-intraframes",
123           "Interval of coding Intra frames",
124           "Interval of coding Intra frames (0xffffffff=component default)", 0,
125           G_MAXUINT,
126           GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT,
127           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
128           GST_PARAM_MUTABLE_READY));
129
130 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
131   g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES,
132       g_param_spec_uint ("periodicity-idr", "IDR periodicity",
133           "Periodicity of IDR frames (0xffffffff=component default)",
134           0, G_MAXUINT,
135           GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
136           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
137           GST_PARAM_MUTABLE_READY));
138
139   g_object_class_install_property (gobject_class, PROP_B_FRAMES,
140       g_param_spec_uint ("b-frames", "Number of B-frames",
141           "Number of B-frames between two consecutive I-frames (0xffffffff=component default)",
142           0, G_MAXUINT, GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT,
143           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
144           GST_PARAM_MUTABLE_READY));
145
146   g_object_class_install_property (gobject_class,
147       PROP_CONSTRAINED_INTRA_PREDICTION,
148       g_param_spec_boolean ("constrained-intra-prediction",
149           "Constrained Intra Prediction",
150           "If enabled, prediction only uses residual data and decoded samples "
151           "from neighbouring coding blocks coded using intra prediction modes",
152           GST_OMX_H265_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT,
153           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
154           GST_PARAM_MUTABLE_READY));
155
156   g_object_class_install_property (gobject_class, PROP_LOOP_FILTER_MODE,
157       g_param_spec_enum ("loop-filter-mode", "Loop Filter mode",
158           "Enable or disable the deblocking filter (0xffffffff=component default)",
159           GST_TYPE_OMX_H265_ENC_LOOP_FILTER_MODE,
160           GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT,
161           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
162           GST_PARAM_MUTABLE_READY));
163 #endif
164
165   videoenc_class->cdata.default_src_template_caps = "video/x-h265, "
166       "width=(int) [ 1, MAX ], " "height=(int) [ 1, MAX ], "
167       "framerate = (fraction) [0, MAX], "
168       "stream-format=(string) byte-stream, alignment=(string) au ";
169
170   gst_element_class_set_static_metadata (element_class,
171       "OpenMAX H.265 Video Encoder",
172       "Codec/Encoder/Video/Hardware",
173       "Encode H.265 video streams",
174       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
175
176   gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.hevc");
177 }
178
179 static void
180 gst_omx_h265_enc_set_property (GObject * object, guint prop_id,
181     const GValue * value, GParamSpec * pspec)
182 {
183   GstOMXH265Enc *self = GST_OMX_H265_ENC (object);
184
185   switch (prop_id) {
186     case PROP_INTERVALOFCODINGINTRAFRAMES:
187       self->interval_intraframes = g_value_get_uint (value);
188       break;
189 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
190     case PROP_PERIODICITYOFIDRFRAMES:
191       self->periodicity_idr = g_value_get_uint (value);
192       break;
193     case PROP_B_FRAMES:
194       self->b_frames = g_value_get_uint (value);
195       break;
196     case PROP_CONSTRAINED_INTRA_PREDICTION:
197       self->constrained_intra_prediction = g_value_get_boolean (value);
198       break;
199     case PROP_LOOP_FILTER_MODE:
200       self->loop_filter_mode = g_value_get_enum (value);
201       break;
202 #endif
203     default:
204       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
205       break;
206   }
207 }
208
209 static void
210 gst_omx_h265_enc_get_property (GObject * object, guint prop_id, GValue * value,
211     GParamSpec * pspec)
212 {
213   GstOMXH265Enc *self = GST_OMX_H265_ENC (object);
214
215   switch (prop_id) {
216     case PROP_INTERVALOFCODINGINTRAFRAMES:
217       g_value_set_uint (value, self->interval_intraframes);
218       break;
219 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
220     case PROP_PERIODICITYOFIDRFRAMES:
221       g_value_set_uint (value, self->periodicity_idr);
222       break;
223     case PROP_B_FRAMES:
224       g_value_set_uint (value, self->b_frames);
225       break;
226     case PROP_CONSTRAINED_INTRA_PREDICTION:
227       g_value_set_boolean (value, self->constrained_intra_prediction);
228       break;
229     case PROP_LOOP_FILTER_MODE:
230       g_value_set_enum (value, self->loop_filter_mode);
231       break;
232 #endif
233     default:
234       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
235       break;
236   }
237 }
238
239 static void
240 gst_omx_h265_enc_init (GstOMXH265Enc * self)
241 {
242   self->interval_intraframes =
243       GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT;
244 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
245   self->periodicity_idr =
246       GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT;
247   self->b_frames = GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT;
248   self->constrained_intra_prediction =
249       GST_OMX_H265_VIDEO_ENC_CONSTRAINED_INTRA_PREDICTION_DEFAULT;
250   self->loop_filter_mode = GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT;
251 #endif
252 }
253
254 /* Update OMX_VIDEO_PARAM_PROFILELEVELTYPE.{eProfile,eLevel}
255  *
256  * Returns TRUE if succeeded or if not supported, FALSE if failed */
257 static gboolean
258 update_param_profile_level (GstOMXH265Enc * self,
259     OMX_VIDEO_HEVCPROFILETYPE profile, OMX_VIDEO_HEVCLEVELTYPE level)
260 {
261   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
262   OMX_ERRORTYPE err;
263
264   GST_OMX_INIT_STRUCT (&param);
265   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
266
267   err =
268       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
269       OMX_IndexParamVideoProfileLevelCurrent, &param);
270   if (err != OMX_ErrorNone) {
271     GST_WARNING_OBJECT (self,
272         "Getting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
273     return TRUE;
274   }
275
276   if (profile != OMX_VIDEO_HEVCProfileUnknown)
277     param.eProfile = profile;
278   if (level != OMX_VIDEO_HEVCLevelUnknown)
279     param.eLevel = level;
280
281   err =
282       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
283       OMX_IndexParamVideoProfileLevelCurrent, &param);
284   if (err == OMX_ErrorUnsupportedIndex) {
285     GST_WARNING_OBJECT (self,
286         "Setting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
287     return TRUE;
288   } else if (err != OMX_ErrorNone) {
289     GST_ERROR_OBJECT (self,
290         "Error setting profile %u and level %u: %s (0x%08x)",
291         (guint) param.eProfile, (guint) param.eLevel,
292         gst_omx_error_to_string (err), err);
293     return FALSE;
294   }
295
296   return TRUE;
297 }
298
299 /* Update OMX_ALG_VIDEO_PARAM_HEVCTYPE
300  *
301  * Returns TRUE if succeeded or if not supported, FALSE if failed */
302 static gboolean
303 update_param_hevc (GstOMXH265Enc * self,
304     OMX_VIDEO_HEVCPROFILETYPE profile, OMX_VIDEO_HEVCLEVELTYPE level)
305 {
306 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
307   OMX_ALG_VIDEO_PARAM_HEVCTYPE param;
308 #else
309   OMX_VIDEO_PARAM_HEVCTYPE param;
310 #endif
311   OMX_ERRORTYPE err;
312
313   GST_OMX_INIT_STRUCT (&param);
314   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
315
316   /* On Android the param struct is initialized manually with default
317    * settings rather than using GetParameter() to retrieve them.
318    * We should probably do the same when we'll add Android as target.
319    * See bgo#783862 for details. */
320
321 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
322   param.bConstIpred = self->constrained_intra_prediction;
323
324   if (self->loop_filter_mode != GST_OMX_H265_VIDEO_ENC_LOOP_FILTER_MODE_DEFAULT)
325     param.eLoopFilterMode = self->loop_filter_mode;
326
327   err =
328       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
329       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoHevc, &param);
330 #else
331   err =
332       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
333       (OMX_INDEXTYPE) OMX_IndexParamVideoHevc, &param);
334 #endif
335
336   if (err != OMX_ErrorNone) {
337     GST_WARNING_OBJECT (self,
338         "Getting OMX_ALG_IndexParamVideoHevc not supported by component");
339     return TRUE;
340   }
341
342   if (profile != OMX_VIDEO_HEVCProfileUnknown)
343 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
344     param.eProfile = (OMX_ALG_VIDEO_HEVCPROFILETYPE) profile;
345 #else
346     param.eProfile = profile;
347 #endif
348
349   if (level != OMX_VIDEO_HEVCLevelUnknown)
350 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
351     param.eLevel = (OMX_ALG_VIDEO_HEVCLEVELTYPE) level;
352 #else
353     param.eLevel = level;
354 #endif
355
356   /* GOP pattern */
357 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
358   /* The zynqultrascaleplus uses another PARAM_HEVCTYPE API allowing users to
359    * define the number of P and B frames while Android's API only expose the
360    * former. */
361   if (self->interval_intraframes !=
362       GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
363     param.nPFrames = self->interval_intraframes;
364
365     /* If user specified a specific number of B-frames, reduce the number of
366      * P-frames by this amount. If not ensure there is no B-frame to have the
367      * requested GOP length. */
368     if (self->b_frames != GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT) {
369       if (self->b_frames > self->interval_intraframes) {
370         GST_ERROR_OBJECT (self,
371             "The interval_intraframes perdiod (%u) needs to be higher than the number of B-frames (%u)",
372             self->interval_intraframes, self->b_frames);
373         return FALSE;
374       }
375       param.nPFrames -= self->b_frames;
376     } else {
377       param.nBFrames = 0;
378     }
379   }
380
381   if (self->b_frames != GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT)
382     param.nBFrames = self->b_frames;
383 #else
384   if (self->interval_intraframes !=
385       GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT)
386     param.nKeyFrameInterval = self->interval_intraframes;
387 #endif
388
389   err =
390       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
391       (OMX_INDEXTYPE) INDEX_PARAM_VIDEO_HEVC, &param);
392
393   if (err == OMX_ErrorUnsupportedIndex) {
394     GST_WARNING_OBJECT (self,
395         "Setting IndexParamVideoHevc not supported by component");
396     return TRUE;
397   } else if (err != OMX_ErrorNone) {
398     GST_ERROR_OBJECT (self,
399         "Error setting HEVC settings (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 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
409 static gboolean
410 set_intra_period (GstOMXH265Enc * self)
411 {
412   OMX_ALG_VIDEO_PARAM_INSTANTANEOUS_DECODING_REFRESH config_idr;
413   OMX_ERRORTYPE err;
414
415   GST_OMX_INIT_STRUCT (&config_idr);
416   config_idr.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
417
418   GST_DEBUG_OBJECT (self, "nIDRPeriod:%u",
419       (guint) config_idr.nInstantaneousDecodingRefreshFrequency);
420
421   config_idr.nInstantaneousDecodingRefreshFrequency = self->periodicity_idr;
422
423   err =
424       gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
425       (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoInstantaneousDecodingRefresh,
426       &config_idr);
427   if (err != OMX_ErrorNone) {
428     GST_ERROR_OBJECT (self,
429         "can't set OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
430         gst_omx_error_to_string (err), err);
431     return FALSE;
432   }
433
434   return TRUE;
435 }
436 #endif
437
438 static gboolean
439 gst_omx_h265_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
440     GstVideoCodecState * state)
441 {
442   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
443   GstCaps *peercaps;
444   OMX_PARAM_PORTDEFINITIONTYPE port_def;
445   OMX_ERRORTYPE err;
446   const gchar *profile_string, *level_string, *tier_string;
447   OMX_VIDEO_HEVCPROFILETYPE profile = OMX_VIDEO_HEVCProfileUnknown;
448   OMX_VIDEO_HEVCLEVELTYPE level = OMX_VIDEO_HEVCLevelUnknown;
449
450 #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
451   if (self->periodicity_idr !=
452       GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT)
453     set_intra_period (self);
454 #endif
455
456   gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
457       &port_def);
458   port_def.format.video.eCompressionFormat =
459       (OMX_VIDEO_CODINGTYPE) OMX_VIDEO_CodingHEVC;
460   err =
461       gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
462       (self)->enc_out_port, &port_def);
463   if (err != OMX_ErrorNone)
464     return FALSE;
465
466   /* Set profile and level */
467   peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc),
468       gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc)));
469   if (peercaps) {
470     GstStructure *s;
471
472     if (gst_caps_is_empty (peercaps)) {
473       gst_caps_unref (peercaps);
474       GST_ERROR_OBJECT (self, "Empty caps");
475       return FALSE;
476     }
477
478     s = gst_caps_get_structure (peercaps, 0);
479     profile_string = gst_structure_get_string (s, "profile");
480     if (profile_string) {
481       profile = gst_omx_h265_utils_get_profile_from_str (profile_string);
482       if (profile == OMX_VIDEO_HEVCProfileUnknown)
483         goto unsupported_profile;
484     }
485
486     level_string = gst_structure_get_string (s, "level");
487     tier_string = gst_structure_get_string (s, "tier");
488     if (level_string && tier_string) {
489       level = gst_omx_h265_utils_get_level_from_str (level_string, tier_string);
490       if (level == OMX_VIDEO_HEVCLevelUnknown)
491         goto unsupported_level;
492     }
493
494     gst_caps_unref (peercaps);
495   }
496
497   if (profile != OMX_VIDEO_HEVCProfileUnknown
498       || level != OMX_VIDEO_HEVCLevelUnknown) {
499     /* OMX provides 2 API to set the profile and level. We try using the
500      * generic one here and the H265 specific when calling
501      * update_param_hevc() */
502     if (!update_param_profile_level (self, profile, level))
503       return FALSE;
504   }
505
506   if (!update_param_hevc (self, profile, level))
507     return FALSE;
508
509   return TRUE;
510
511 unsupported_profile:
512   GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
513   gst_caps_unref (peercaps);
514   return FALSE;
515
516 unsupported_level:
517   GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
518   gst_caps_unref (peercaps);
519   return FALSE;
520 }
521
522 static GstCaps *
523 gst_omx_h265_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
524     GstVideoCodecState * state)
525 {
526   GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
527   GstCaps *caps;
528   OMX_ERRORTYPE err;
529   OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
530   const gchar *profile, *level, *tier;
531
532   GST_OMX_INIT_STRUCT (&param);
533   param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
534
535   err =
536       gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
537       OMX_IndexParamVideoProfileLevelCurrent, &param);
538   if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
539     return NULL;
540
541   caps = gst_caps_new_simple ("video/x-h265",
542       "stream-format", G_TYPE_STRING, "byte-stream",
543       "alignment", G_TYPE_STRING, "au", NULL);
544
545   if (err == OMX_ErrorNone) {
546     profile = gst_omx_h265_utils_get_profile_from_enum (param.eProfile);
547     if (!profile) {
548       g_assert_not_reached ();
549       gst_caps_unref (caps);
550       return NULL;
551     }
552
553     switch (param.eLevel) {
554       case OMX_VIDEO_HEVCMainTierLevel1:
555         tier = "main";
556         level = "1";
557         break;
558       case OMX_VIDEO_HEVCMainTierLevel2:
559         tier = "main";
560         level = "2";
561         break;
562       case OMX_VIDEO_HEVCMainTierLevel21:
563         tier = "main";
564         level = "2.1";
565         break;
566       case OMX_VIDEO_HEVCMainTierLevel3:
567         tier = "main";
568         level = "3";
569         break;
570       case OMX_VIDEO_HEVCMainTierLevel31:
571         tier = "main";
572         level = "3.1";
573         break;
574       case OMX_VIDEO_HEVCMainTierLevel4:
575         tier = "main";
576         level = "4";
577         break;
578       case OMX_VIDEO_HEVCMainTierLevel41:
579         tier = "main";
580         level = "4.1";
581         break;
582       case OMX_VIDEO_HEVCMainTierLevel5:
583         tier = "main";
584         level = "5";
585         break;
586       case OMX_VIDEO_HEVCMainTierLevel51:
587         tier = "main";
588         level = "5.1";
589         break;
590       case OMX_VIDEO_HEVCMainTierLevel52:
591         tier = "main";
592         level = "5.2";
593         break;
594       case OMX_VIDEO_HEVCMainTierLevel6:
595         tier = "main";
596         level = "6";
597         break;
598       case OMX_VIDEO_HEVCMainTierLevel61:
599         tier = "main";
600         level = "6.1";
601         break;
602       case OMX_VIDEO_HEVCMainTierLevel62:
603         tier = "main";
604         level = "6.2";
605         break;
606       case OMX_VIDEO_HEVCHighTierLevel4:
607         tier = "high";
608         level = "4";
609         break;
610       case OMX_VIDEO_HEVCHighTierLevel41:
611         tier = "high";
612         level = "4.1";
613         break;
614       case OMX_VIDEO_HEVCHighTierLevel5:
615         tier = "high";
616         level = "5";
617         break;
618       case OMX_VIDEO_HEVCHighTierLevel51:
619         tier = "high";
620         level = "5.1";
621         break;
622       case OMX_VIDEO_HEVCHighTierLevel52:
623         tier = "high";
624         level = "5.2";
625         break;
626       case OMX_VIDEO_HEVCHighTierLevel6:
627         tier = "high";
628         level = "6";
629         break;
630       case OMX_VIDEO_HEVCHighTierLevel61:
631         tier = "high";
632         level = "6.1";
633         break;
634       case OMX_VIDEO_HEVCHighTierLevel62:
635         tier = "high";
636         level = "6.2";
637         break;
638       default:
639         g_assert_not_reached ();
640         gst_caps_unref (caps);
641         return NULL;
642     }
643
644     gst_caps_set_simple (caps,
645         "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level,
646         "tier", G_TYPE_STRING, tier, NULL);
647   }
648
649   return caps;
650 }