diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2017-07-12 11:01:15 +0200 |
---|---|---|
committer | Nicolas Dufresne <nicolas.dufresne@collabora.com> | 2017-09-06 14:50:18 -0400 |
commit | cf9f1903db84a1e6745de26455baec9a7d138a1b (patch) | |
tree | c217c5dae1f6afa429e774512a41b461ffd41d43 | |
parent | 79df3b0e8e003304808fc5d62d3bd8903386b108 (diff) | |
download | gst-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.conf | 9 | ||||
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | meson.build | 10 | ||||
-rw-r--r-- | omx/Makefile.am | 11 | ||||
-rw-r--r-- | omx/gstomx.c | 4 | ||||
-rw-r--r-- | omx/gstomxh265enc.c | 583 | ||||
-rw-r--r-- | omx/gstomxh265enc.h | 68 | ||||
-rw-r--r-- | omx/gstomxh265utils.c | 97 | ||||
-rw-r--r-- | omx/gstomxh265utils.h | 35 | ||||
-rw-r--r-- | omx/meson.build | 5 |
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 (¶m); + 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, ¶m); + 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, ¶m); + 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 (¶m); + 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, ¶m); +#else + err = + gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc, + (OMX_INDEXTYPE) OMX_IndexParamVideoHevc, ¶m); +#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, ¶m); + + 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 (¶m); + 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, ¶m); + 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 |