summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2017-07-12 11:01:15 +0200
committerNicolas Dufresne <nicolas.dufresne@collabora.com>2017-09-06 14:50:18 -0400
commitcf9f1903db84a1e6745de26455baec9a7d138a1b (patch)
treec217c5dae1f6afa429e774512a41b461ffd41d43
parent79df3b0e8e003304808fc5d62d3bd8903386b108 (diff)
downloadgst-omx-cf9f1903db84a1e6745de26455baec9a7d138a1b.tar.gz
omxh265enc: add H265 encoder
The OMX spec doesn't support HEVC but the OMX stack of the zynqultrascaleplus adds it as a custom extension. It uses the same API as the one of Android's OMX stack. I used the H264 encoder code as a template. https://bugzilla.gnome.org/show_bug.cgi?id=785434
-rw-r--r--config/zynqultrascaleplus/gstomx.conf9
-rw-r--r--configure.ac9
-rw-r--r--meson.build10
-rw-r--r--omx/Makefile.am11
-rw-r--r--omx/gstomx.c4
-rw-r--r--omx/gstomxh265enc.c583
-rw-r--r--omx/gstomxh265enc.h68
-rw-r--r--omx/gstomxh265utils.c97
-rw-r--r--omx/gstomxh265utils.h35
-rw-r--r--omx/meson.build5
10 files changed, 831 insertions, 0 deletions
diff --git a/config/zynqultrascaleplus/gstomx.conf b/config/zynqultrascaleplus/gstomx.conf
index 6850e1d..8e35821 100644
--- a/config/zynqultrascaleplus/gstomx.conf
+++ b/config/zynqultrascaleplus/gstomx.conf
@@ -15,3 +15,12 @@ in-port-index=0
out-port-index=1
rank=257
hacks=no-disable-outport;pass-profile-to-decoder
+
+[omxh265enc]
+type-name=GstOMXH265Enc
+core-name=/usr/lib/libOMX.allegro.core.so.1
+component-name=OMX.allegro.h265.encoder
+in-port-index=0
+out-port-index=1
+rank=257
+hacks=no-disable-outport
diff --git a/configure.ac b/configure.ac
index 2edb265..5f8bf2c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -287,6 +287,15 @@ AC_CHECK_DECLS([OMX_VIDEO_CodingTheora],
], [[$VIDEO_HEADERS]])
AM_CONDITIONAL(HAVE_THEORA, test "x$HAVE_THEORA" = "xyes")
+AC_CHECK_DECLS([OMX_VIDEO_CodingHEVC],
+ [
+ AC_DEFINE(HAVE_HEVC, 1, [OpenMAX IL has HEVC support])
+ HAVE_HEVC=yes
+ ], [
+ HAVE_HEVC=no
+ ], [[$VIDEO_HEADERS]])
+AM_CONDITIONAL(HAVE_HEVC, test "x$HAVE_HEVC" = "xyes")
+
dnl *** set variables based on configure arguments ***
dnl set license and copyright notice
diff --git a/meson.build b/meson.build
index 07c1a4a..5c6425b 100644
--- a/meson.build
+++ b/meson.build
@@ -228,6 +228,16 @@ if have_omx_theora
cdata.set('HAVE_THEORA', 1)
endif
+have_omx_hevc = cc.has_header_symbol(
+ 'OMX_Video.h',
+ 'OMX_VIDEO_CodingHEVC',
+ prefix : extra_video_headers,
+ args : gst_omx_args,
+ required : false)
+if have_omx_hevc
+ cdata.set('HAVE_HEVC', 1)
+endif
+
default_omx_struct_packing = 0
omx_target = get_option ('with_omx_target')
if omx_target == 'generic'
diff --git a/omx/Makefile.am b/omx/Makefile.am
index 11e1223..ec778d6 100644
--- a/omx/Makefile.am
+++ b/omx/Makefile.am
@@ -10,6 +10,15 @@ THEORA_C_FILES=gstomxtheoradec.c
THEORA_H_FILES=gstomxtheoradec.h
endif
+if HAVE_HEVC
+H265_C_FILES = \
+ gstomxh265enc.c \
+ gstomxh265utils.c
+H265_H_FILES = \
+ gstomxh265enc.h \
+ gstomxh265utils.h
+endif
+
libgstomx_la_SOURCES = \
gstomx.c \
gstomxbufferpool.c \
@@ -27,6 +36,7 @@ libgstomx_la_SOURCES = \
gstomxwmvdec.c \
$(VP8_C_FILES) \
$(THEORA_C_FILES) \
+ $(H265_C_FILES) \
gstomxmpeg4videoenc.c \
gstomxh264enc.c \
gstomxh263enc.c \
@@ -56,6 +66,7 @@ noinst_HEADERS = \
gstomxwmvdec.h \
$(VP8_H_FILES) \
$(THEORA_H_FILES) \
+ $(H265_H_FILES) \
gstomxmpeg4videoenc.h \
gstomxh264enc.h \
gstomxh263enc.h \
diff --git a/omx/gstomx.c b/omx/gstomx.c
index f2a2dd1..90b328d 100644
--- a/omx/gstomx.c
+++ b/omx/gstomx.c
@@ -39,6 +39,7 @@
#include "gstomxmpeg4videoenc.h"
#include "gstomxh264enc.h"
#include "gstomxh263enc.h"
+#include "gstomxh265enc.h"
#include "gstomxaacdec.h"
#include "gstomxmp3dec.h"
#include "gstomxmp3enc.h"
@@ -2307,6 +2308,9 @@ static const GGetTypeFunction types[] = {
#ifdef HAVE_THEORA
, gst_omx_theora_dec_get_type
#endif
+#ifdef HAVE_HEVC
+ , gst_omx_h265_enc_get_type
+#endif
};
struct TypeOffest
diff --git a/omx/gstomxh265enc.c b/omx/gstomxh265enc.c
new file mode 100644
index 0000000..2aebd84
--- /dev/null
+++ b/omx/gstomxh265enc.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2017 Xilinx, Inc.
+ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstomxh265enc.h"
+#include "gstomxh265utils.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_omx_h265_enc_debug_category);
+#define GST_CAT_DEFAULT gst_omx_h265_enc_debug_category
+
+/* prototypes */
+static gboolean gst_omx_h265_enc_set_format (GstOMXVideoEnc * enc,
+ GstOMXPort * port, GstVideoCodecState * state);
+static GstCaps *gst_omx_h265_enc_get_caps (GstOMXVideoEnc * enc,
+ GstOMXPort * port, GstVideoCodecState * state);
+static void gst_omx_h265_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_omx_h265_enc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+enum
+{
+ PROP_0,
+ PROP_PERIODICITYOFIDRFRAMES,
+ PROP_INTERVALOFCODINGINTRAFRAMES,
+ PROP_B_FRAMES,
+};
+
+#define GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT (0xffffffff)
+#define GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff)
+#define GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT (0xffffffff)
+
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+/* zynqultrascaleplus's OMX uses a param struct different of Android's one */
+#define INDEX_PARAM_VIDEO_HEVC OMX_ALG_IndexParamVideoHevc
+#else
+#define INDEX_PARAM_VIDEO_HEVC OMX_IndexParamVideoHevc
+#endif
+
+/* class initialization */
+
+#define DEBUG_INIT \
+ GST_DEBUG_CATEGORY_INIT (gst_omx_h265_enc_debug_category, "omxh265enc", 0, \
+ "debug category for gst-omx H265 video encoder");
+
+#define parent_class gst_omx_h265_enc_parent_class
+G_DEFINE_TYPE_WITH_CODE (GstOMXH265Enc, gst_omx_h265_enc,
+ GST_TYPE_OMX_VIDEO_ENC, DEBUG_INIT);
+
+static void
+gst_omx_h265_enc_class_init (GstOMXH265EncClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstOMXVideoEncClass *videoenc_class = GST_OMX_VIDEO_ENC_CLASS (klass);
+
+ videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_h265_enc_set_format);
+ videoenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_h265_enc_get_caps);
+
+ gobject_class->set_property = gst_omx_h265_enc_set_property;
+ gobject_class->get_property = gst_omx_h265_enc_get_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_INTERVALOFCODINGINTRAFRAMES,
+ g_param_spec_uint ("interval-intraframes",
+ "Interval of coding Intra frames",
+ "Interval of coding Intra frames (0xffffffff=component default)", 0,
+ G_MAXUINT,
+ GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES,
+ g_param_spec_uint ("periodicty-idr", "Target Bitrate",
+ "Periodicity of IDR frames (0xffffffff=component default)",
+ 0, G_MAXUINT,
+ GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+
+ g_object_class_install_property (gobject_class, PROP_B_FRAMES,
+ g_param_spec_uint ("b-frames", "Number of B-frames",
+ "Number of B-frames between two consecutive I-frames (0xffffffff=component default)",
+ 0, G_MAXUINT, GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+#endif
+
+ videoenc_class->cdata.default_src_template_caps = "video/x-h265, "
+ "width=(int) [ 1, MAX ], " "height=(int) [ 1, MAX ], "
+ "framerate = (fraction) [0, MAX], "
+ "stream-format=(string) byte-stream, alignment=(string) au ";
+
+ gst_element_class_set_static_metadata (element_class,
+ "OpenMAX H.265 Video Encoder",
+ "Codec/Encoder/Video",
+ "Encode H.265 video streams",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+ gst_omx_set_default_role (&videoenc_class->cdata, "video_encoder.hevc");
+}
+
+static void
+gst_omx_h265_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstOMXH265Enc *self = GST_OMX_H265_ENC (object);
+
+ switch (prop_id) {
+ case PROP_INTERVALOFCODINGINTRAFRAMES:
+ self->interval_intraframes = g_value_get_uint (value);
+ break;
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ case PROP_PERIODICITYOFIDRFRAMES:
+ self->periodicity_idr = g_value_get_uint (value);
+ break;
+ case PROP_B_FRAMES:
+ self->b_frames = g_value_get_uint (value);
+ break;
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_omx_h265_enc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstOMXH265Enc *self = GST_OMX_H265_ENC (object);
+
+ switch (prop_id) {
+ case PROP_INTERVALOFCODINGINTRAFRAMES:
+ g_value_set_uint (value, self->interval_intraframes);
+ break;
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ case PROP_PERIODICITYOFIDRFRAMES:
+ g_value_set_uint (value, self->periodicity_idr);
+ break;
+ case PROP_B_FRAMES:
+ g_value_set_uint (value, self->b_frames);
+ break;
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_omx_h265_enc_init (GstOMXH265Enc * self)
+{
+ self->interval_intraframes =
+ GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT;
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ self->periodicity_idr =
+ GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT;
+ self->b_frames = GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT;
+#endif
+}
+
+/* Update OMX_VIDEO_PARAM_PROFILELEVELTYPE.{eProfile,eLevel}
+ *
+ * Returns TRUE if succeeded or if not supported, FALSE if failed */
+static gboolean
+update_param_profile_level (GstOMXH265Enc * self,
+ OMX_VIDEO_HEVCPROFILETYPE profile, OMX_VIDEO_HEVCLEVELTYPE level)
+{
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+ OMX_ERRORTYPE err;
+
+ GST_OMX_INIT_STRUCT (&param);
+ param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
+
+ err =
+ gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ OMX_IndexParamVideoProfileLevelCurrent, &param);
+ if (err != OMX_ErrorNone) {
+ GST_WARNING_OBJECT (self,
+ "Getting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
+ return TRUE;
+ }
+
+ if (profile != OMX_VIDEO_HEVCProfileUnknown)
+ param.eProfile = profile;
+ if (level != OMX_VIDEO_HEVCLevelUnknown)
+ param.eLevel = level;
+
+ err =
+ gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ OMX_IndexParamVideoProfileLevelCurrent, &param);
+ if (err == OMX_ErrorUnsupportedIndex) {
+ GST_WARNING_OBJECT (self,
+ "Setting OMX_IndexParamVideoProfileLevelCurrent not supported by component");
+ return TRUE;
+ } else if (err != OMX_ErrorNone) {
+ GST_ERROR_OBJECT (self,
+ "Error setting profile %u and level %u: %s (0x%08x)",
+ (guint) param.eProfile, (guint) param.eLevel,
+ gst_omx_error_to_string (err), err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Update OMX_ALG_VIDEO_PARAM_HEVCTYPE
+ *
+ * Returns TRUE if succeeded or if not supported, FALSE if failed */
+static gboolean
+update_param_hevc (GstOMXH265Enc * self,
+ OMX_VIDEO_HEVCPROFILETYPE profile, OMX_VIDEO_HEVCLEVELTYPE level)
+{
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ OMX_ALG_VIDEO_PARAM_HEVCTYPE param;
+#else
+ OMX_VIDEO_PARAM_HEVCTYPE param;
+#endif
+ OMX_ERRORTYPE err;
+
+ GST_OMX_INIT_STRUCT (&param);
+ param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
+
+ /* On Android the param struct is initialized manually with default
+ * settings rather than using GetParameter() to retrieve them.
+ * We should probably do the same when we'll add Android as target.
+ * See bgo#783862 for details. */
+
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ err =
+ gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ (OMX_INDEXTYPE) OMX_ALG_IndexParamVideoHevc, &param);
+#else
+ err =
+ gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ (OMX_INDEXTYPE) OMX_IndexParamVideoHevc, &param);
+#endif
+
+ if (err != OMX_ErrorNone) {
+ GST_WARNING_OBJECT (self,
+ "Getting OMX_ALG_IndexParamVideoHevc not supported by component");
+ return TRUE;
+ }
+
+ if (profile != OMX_VIDEO_HEVCProfileUnknown)
+ param.eProfile = profile;
+ if (level != OMX_VIDEO_HEVCLevelUnknown)
+ param.eLevel = level;
+
+ /* GOP pattern */
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ /* The zynqultrascaleplus uses another PARAM_HEVCTYPE API allowing users to
+ * define the number of P and B frames while Android's API only expose the
+ * former. */
+ if (self->interval_intraframes !=
+ GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) {
+ param.nPFrames = self->interval_intraframes;
+
+ /* If user specified a specific number of B-frames, reduce the number of
+ * P-frames by this amount. If not ensure there is no B-frame to have the
+ * requested GOP length. */
+ if (self->b_frames != GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT) {
+ if (self->b_frames > self->interval_intraframes) {
+ GST_ERROR_OBJECT (self,
+ "The interval_intraframes perdiod (%u) needs to be higher than the number of B-frames (%u)",
+ self->interval_intraframes, self->b_frames);
+ return FALSE;
+ }
+ param.nPFrames -= self->b_frames;
+ } else {
+ param.nBFrames = 0;
+ }
+ }
+
+ if (self->b_frames != GST_OMX_H265_VIDEO_ENC_B_FRAMES_DEFAULT)
+ param.nBFrames = self->b_frames;
+#else
+ if (self->interval_intraframes !=
+ GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT)
+ param.nKeyFrameInterval = self->interval_intraframes;
+#endif
+
+ err =
+ gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ (OMX_INDEXTYPE) INDEX_PARAM_VIDEO_HEVC, &param);
+
+ if (err == OMX_ErrorUnsupportedIndex) {
+ GST_WARNING_OBJECT (self,
+ "Setting IndexParamVideoHevc not supported by component");
+ return TRUE;
+ } else if (err != OMX_ErrorNone) {
+ GST_ERROR_OBJECT (self,
+ "Error setting HEVC settings (profile %u and level %u): %s (0x%08x)",
+ (guint) param.eProfile, (guint) param.eLevel,
+ gst_omx_error_to_string (err), err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+static gboolean
+set_intra_period (GstOMXH265Enc * self)
+{
+ OMX_ALG_VIDEO_PARAM_INSTANTANEOUS_DECODING_REFRESH config_idr;
+ OMX_ERRORTYPE err;
+
+ GST_OMX_INIT_STRUCT (&config_idr);
+ config_idr.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
+
+ GST_DEBUG_OBJECT (self, "nIDRPeriod:%u",
+ (guint) config_idr.nInstantaneousDecodingRefreshFrequency);
+
+ config_idr.nInstantaneousDecodingRefreshFrequency = self->periodicity_idr;
+
+ err =
+ gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ OMX_ALG_IndexParamVideoInstantaneousDecodingRefresh, &config_idr);
+ if (err != OMX_ErrorNone) {
+ GST_ERROR_OBJECT (self,
+ "can't set OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)",
+ gst_omx_error_to_string (err), err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
+static gboolean
+gst_omx_h265_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port,
+ GstVideoCodecState * state)
+{
+ GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
+ GstCaps *peercaps;
+ OMX_PARAM_PORTDEFINITIONTYPE port_def;
+ OMX_ERRORTYPE err;
+ const gchar *profile_string, *level_string, *tier_string;
+ OMX_VIDEO_HEVCPROFILETYPE profile = OMX_VIDEO_HEVCProfileUnknown;
+ OMX_VIDEO_HEVCLEVELTYPE level = OMX_VIDEO_HEVCLevelUnknown;
+
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ if (self->periodicity_idr !=
+ GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT)
+ set_intra_period (self);
+#endif
+
+ gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port,
+ &port_def);
+ port_def.format.video.eCompressionFormat =
+ (OMX_VIDEO_CODINGTYPE) OMX_VIDEO_CodingHEVC;
+ err =
+ gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC
+ (self)->enc_out_port, &port_def);
+ if (err != OMX_ErrorNone)
+ return FALSE;
+
+ /* Set profile and level */
+ peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc),
+ gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc)));
+ if (peercaps) {
+ GstStructure *s;
+
+ if (gst_caps_is_empty (peercaps)) {
+ gst_caps_unref (peercaps);
+ GST_ERROR_OBJECT (self, "Empty caps");
+ return FALSE;
+ }
+
+ s = gst_caps_get_structure (peercaps, 0);
+ profile_string = gst_structure_get_string (s, "profile");
+ if (profile_string) {
+ profile = gst_omx_h265_utils_get_profile_from_str (profile_string);
+ if (profile == OMX_VIDEO_HEVCProfileUnknown)
+ goto unsupported_profile;
+ }
+
+ level_string = gst_structure_get_string (s, "level");
+ tier_string = gst_structure_get_string (s, "tier");
+ if (level_string && tier_string) {
+ level = gst_omx_h265_utils_get_level_from_str (level_string, tier_string);
+ if (level == OMX_VIDEO_HEVCLevelUnknown)
+ goto unsupported_level;
+ }
+
+ gst_caps_unref (peercaps);
+
+ if (profile != OMX_VIDEO_HEVCProfileUnknown
+ || level != OMX_VIDEO_HEVCLevelUnknown) {
+ /* OMX provides 2 API to set the profile and level. We try using the
+ * generic on here and the H265 specific when calling
+ * update_param_hevc() */
+ if (!update_param_profile_level (self, profile, level))
+ return FALSE;
+ }
+ }
+
+ if (!update_param_hevc (self, profile, level))
+ return FALSE;
+
+ return TRUE;
+
+unsupported_profile:
+ GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string);
+ gst_caps_unref (peercaps);
+ return FALSE;
+
+unsupported_level:
+ GST_ERROR_OBJECT (self, "Unsupported level %s", level_string);
+ gst_caps_unref (peercaps);
+ return FALSE;
+}
+
+static GstCaps *
+gst_omx_h265_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
+ GstVideoCodecState * state)
+{
+ GstOMXH265Enc *self = GST_OMX_H265_ENC (enc);
+ GstCaps *caps;
+ OMX_ERRORTYPE err;
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+ const gchar *profile, *level, *tier;
+
+ caps = gst_caps_new_simple ("video/x-h265",
+ "stream-format", G_TYPE_STRING, "byte-stream",
+ "alignment", G_TYPE_STRING, "au", NULL);
+
+ GST_OMX_INIT_STRUCT (&param);
+ param.nPortIndex = GST_OMX_VIDEO_ENC (self)->enc_out_port->index;
+
+ err =
+ gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc,
+ OMX_IndexParamVideoProfileLevelCurrent, &param);
+ if (err != OMX_ErrorNone && err != OMX_ErrorUnsupportedIndex)
+ return NULL;
+
+ if (err == OMX_ErrorNone) {
+ switch (param.eProfile) {
+ case OMX_VIDEO_HEVCProfileMain:
+ profile = "main";
+ break;
+ case OMX_VIDEO_HEVCProfileMain10:
+ profile = "main-10";
+ break;
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ case OMX_ALG_VIDEO_HEVCProfileMainStill:
+ profile = "main-still-picture";
+ break;
+ case OMX_ALG_VIDEO_HEVCProfileMain422:
+ profile = "main422";
+ break;
+ case OMX_ALG_VIDEO_HEVCProfileMain422_10:
+ profile = "main422-10";
+ break;
+#endif
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ switch (param.eLevel) {
+ case OMX_VIDEO_HEVCMainTierLevel1:
+ tier = "main";
+ level = "1";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel2:
+ tier = "main";
+ level = "2";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel21:
+ tier = "main";
+ level = "2.1";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel3:
+ tier = "main";
+ level = "3";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel31:
+ tier = "main";
+ level = "3.1";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel4:
+ tier = "main";
+ level = "4";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel41:
+ tier = "main";
+ level = "4.1";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel5:
+ tier = "main";
+ level = "5";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel51:
+ tier = "main";
+ level = "5.1";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel52:
+ tier = "main";
+ level = "5.2";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel6:
+ tier = "main";
+ level = "6";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel61:
+ tier = "main";
+ level = "6.1";
+ break;
+ case OMX_VIDEO_HEVCMainTierLevel62:
+ tier = "main";
+ level = "6.2";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel4:
+ tier = "high";
+ level = "4";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel41:
+ tier = "high";
+ level = "4.1";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel5:
+ tier = "high";
+ level = "5";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel51:
+ tier = "high";
+ level = "5.1";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel52:
+ tier = "high";
+ level = "5.2";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel6:
+ tier = "high";
+ level = "6";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel61:
+ tier = "high";
+ level = "6.1";
+ break;
+ case OMX_VIDEO_HEVCHighTierLevel62:
+ tier = "high";
+ level = "6.2";
+ break;
+ default:
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ gst_caps_set_simple (caps,
+ "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level,
+ "tier", G_TYPE_STRING, tier, NULL);
+ }
+
+ return caps;
+}
diff --git a/omx/gstomxh265enc.h b/omx/gstomxh265enc.h
new file mode 100644
index 0000000..d2285d5
--- /dev/null
+++ b/omx/gstomxh265enc.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2017 Xilinx, Inc.
+ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GST_OMX_H265_ENC_H__
+#define __GST_OMX_H265_ENC_H__
+
+#include <gst/gst.h>
+#include "gstomxvideoenc.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OMX_H265_ENC \
+ (gst_omx_h265_enc_get_type())
+#define GST_OMX_H265_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OMX_H265_ENC,GstOMXH265Enc))
+#define GST_OMX_H265_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OMX_H265_ENC,GstOMXH265EncClass))
+#define GST_OMX_H265_ENC_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OMX_H265_ENC,GstOMXH265EncClass))
+#define GST_IS_OMX_H265_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OMX_H265_ENC))
+#define GST_IS_OMX_H265_ENC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OMX_H265_ENC))
+
+typedef struct _GstOMXH265Enc GstOMXH265Enc;
+typedef struct _GstOMXH265EncClass GstOMXH265EncClass;
+
+struct _GstOMXH265Enc
+{
+ GstOMXVideoEnc parent;
+
+ /* properties */
+ guint32 interval_intraframes;
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ guint32 periodicity_idr;
+ guint32 b_frames;
+#endif
+};
+
+struct _GstOMXH265EncClass
+{
+ GstOMXVideoEncClass parent_class;
+};
+
+GType gst_omx_h265_enc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OMX_H265_ENC_H__ */
+
diff --git a/omx/gstomxh265utils.c b/omx/gstomxh265utils.c
new file mode 100644
index 0000000..04c374e
--- /dev/null
+++ b/omx/gstomxh265utils.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2017 Xilinx, Inc.
+ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstomxh265utils.h"
+
+OMX_VIDEO_HEVCPROFILETYPE
+gst_omx_h265_utils_get_profile_from_str (const gchar * profile)
+{
+ if (g_str_equal (profile, "main")) {
+ return OMX_VIDEO_HEVCProfileMain;
+ } else if (g_str_equal (profile, "main-10")) {
+ return OMX_VIDEO_HEVCProfileMain10;
+#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+ } else if (g_str_equal (profile, "main-still-picture")) {
+ return OMX_ALG_VIDEO_HEVCProfileMainStill;
+ } else if (g_str_equal (profile, "main422")) {
+ return OMX_ALG_VIDEO_HEVCProfileMain422;
+ } else if (g_str_equal (profile, "main422-10")) {
+ return OMX_ALG_VIDEO_HEVCProfileMain422_10;
+#endif
+ }
+ return OMX_VIDEO_HEVCProfileUnknown;
+}
+
+OMX_VIDEO_HEVCLEVELTYPE
+gst_omx_h265_utils_get_level_from_str (const gchar * level, const gchar * tier)
+{
+ if (g_str_equal (tier, "main")) {
+ if (g_str_equal (level, "1"))
+ return OMX_VIDEO_HEVCMainTierLevel1;
+ else if (g_str_equal (level, "2"))
+ return OMX_VIDEO_HEVCMainTierLevel2;
+ else if (g_str_equal (level, "2.1"))
+ return OMX_VIDEO_HEVCMainTierLevel21;
+ else if (g_str_equal (level, "3"))
+ return OMX_VIDEO_HEVCMainTierLevel3;
+ else if (g_str_equal (level, "3.1"))
+ return OMX_VIDEO_HEVCMainTierLevel31;
+ else if (g_str_equal (level, "4"))
+ return OMX_VIDEO_HEVCMainTierLevel4;
+ else if (g_str_equal (level, "4.1"))
+ return OMX_VIDEO_HEVCMainTierLevel41;
+ else if (g_str_equal (level, "5"))
+ return OMX_VIDEO_HEVCMainTierLevel5;
+ else if (g_str_equal (level, "5.1"))
+ return OMX_VIDEO_HEVCMainTierLevel51;
+ else if (g_str_equal (level, "5.2"))
+ return OMX_VIDEO_HEVCMainTierLevel52;
+ else if (g_str_equal (level, "6"))
+ return OMX_VIDEO_HEVCMainTierLevel6;
+ else if (g_str_equal (level, "6.1"))
+ return OMX_VIDEO_HEVCMainTierLevel61;
+ else if (g_str_equal (level, "6.2"))
+ return OMX_VIDEO_HEVCMainTierLevel62;
+ } else if (g_str_equal (tier, "high")) {
+ if (g_str_equal (level, "4"))
+ return OMX_VIDEO_HEVCHighTierLevel4;
+ else if (g_str_equal (level, "4.1"))
+ return OMX_VIDEO_HEVCHighTierLevel41;
+ else if (g_str_equal (level, "5"))
+ return OMX_VIDEO_HEVCHighTierLevel5;
+ else if (g_str_equal (level, "5.1"))
+ return OMX_VIDEO_HEVCHighTierLevel51;
+ else if (g_str_equal (level, "5.2"))
+ return OMX_VIDEO_HEVCHighTierLevel52;
+ else if (g_str_equal (level, "6"))
+ return OMX_VIDEO_HEVCHighTierLevel6;
+ else if (g_str_equal (level, "6.1"))
+ return OMX_VIDEO_HEVCHighTierLevel61;
+ else if (g_str_equal (level, "6.2"))
+ return OMX_VIDEO_HEVCHighTierLevel62;
+ }
+
+ return OMX_VIDEO_HEVCLevelUnknown;
+}
diff --git a/omx/gstomxh265utils.h b/omx/gstomxh265utils.h
new file mode 100644
index 0000000..15b7d2a
--- /dev/null
+++ b/omx/gstomxh265utils.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2017 Xilinx, Inc.
+ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GST_OMX_H265_UTILS_H__
+#define __GST_OMX_H265_UTILS_H__
+
+#include "gstomx.h"
+
+G_BEGIN_DECLS
+
+OMX_VIDEO_HEVCPROFILETYPE gst_omx_h265_utils_get_profile_from_str (const
+ gchar * profile);
+OMX_VIDEO_HEVCLEVELTYPE gst_omx_h265_utils_get_level_from_str (const gchar *
+ level, const gchar * tier);
+
+G_END_DECLS
+#endif /* __GST_OMX_H265_UTILS_H__ */
diff --git a/omx/meson.build b/omx/meson.build
index 3ddf85a..17f42e2 100644
--- a/omx/meson.build
+++ b/omx/meson.build
@@ -37,6 +37,11 @@ if have_omx_theora
omx_sources += 'gstomxtheoradec.c'
endif
+if have_omx_hevc
+ omx_sources += 'gstomxh265utils.c'
+ omx_sources += 'gstomxh265enc.c'
+endif
+
if not have_external_omx
extra_inc += include_directories ('openmax')
endif