omxh265enc: add H265 encoder
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Wed, 12 Jul 2017 09:01:15 +0000 (11:01 +0200)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 6 Sep 2017 18:50:18 +0000 (14:50 -0400)
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

config/zynqultrascaleplus/gstomx.conf
configure.ac
meson.build
omx/Makefile.am
omx/gstomx.c
omx/gstomxh265enc.c [new file with mode: 0644]
omx/gstomxh265enc.h [new file with mode: 0644]
omx/gstomxh265utils.c [new file with mode: 0644]
omx/gstomxh265utils.h [new file with mode: 0644]
omx/meson.build

index 6850e1d..8e35821 100644 (file)
@@ -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
index 2edb265..5f8bf2c 100644 (file)
@@ -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
index 07c1a4a..5c6425b 100644 (file)
@@ -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'
index 11e1223..ec778d6 100644 (file)
@@ -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 \
index f2a2dd1..90b328d 100644 (file)
@@ -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 (file)
index 0000000..2aebd84
--- /dev/null
@@ -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 (file)
index 0000000..d2285d5
--- /dev/null
@@ -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 (file)
index 0000000..04c374e
--- /dev/null
@@ -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 (file)
index 0000000..15b7d2a
--- /dev/null
@@ -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__ */
index 3ddf85a..17f42e2 100644 (file)
@@ -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