From 2f835a3f8f1d9151cce3c23791c011377d19de38 Mon Sep 17 00:00:00 2001 From: Sejun Park Date: Thu, 27 Apr 2017 11:08:05 +0900 Subject: [PATCH] enable encoder and add hevc encoder Change-Id: Idc8b228b4d51a2ddb4d17eecbf16b492802d27f6 --- config/exynos/gstomx.conf | 17 +- omx/Makefile.am | 6 +- omx/gstomx.c | 37 +-- omx/gstomx.h | 14 +- omx/gstomxh264enc.c | 78 ++++++ omx/gstomxh264enc.h | 4 + omx/gstomxh265enc.c | 613 ++++++++++++++++++++++++++++++++++++++++++++++ omx/gstomxh265enc.h | 68 +++++ omx/gstomxvideodec.c | 23 +- omx/gstomxvideodec.h | 19 +- omx/gstomxvideoenc.c | 125 +++++++++- omx/gstomxvideoenc.h | 2 +- 12 files changed, 939 insertions(+), 67 deletions(-) create mode 100644 omx/gstomxh265enc.c create mode 100644 omx/gstomxh265enc.h diff --git a/config/exynos/gstomx.conf b/config/exynos/gstomx.conf index c667b34..e83ec55 100644 --- a/config/exynos/gstomx.conf +++ b/config/exynos/gstomx.conf @@ -95,11 +95,22 @@ rank=258 in-port-index=0 out-port-index=1 in-port-usebuffer=1 -out-port-usebuffer=1 +out-port-usebuffer=0 hacks=no-disable-outport;no-component-role sink-template-caps=video/x-raw, format=(string)SN12, width=(int) [1,1920], height=(int) [1,1080], framerate=(fraction)[0/1, MAX] src-template-caps=video/x-h264, width=(int) [1,1920], height=(int) [1,1080], framerate=(fraction) [0/1, MAX], alignment=(string) au, stream-format = (string){ avc, byte-stream } +[omxenc_h265] +type-name=GstOMXH265Enc +core-name=/usr/lib/libExynosOMX_Core.so +component-name=OMX.Exynos.HEVC.Encoder +rank=258 +in-port-index=0 +out-port-index=1 +in-port-usebuffer=1 +out-port-usebuffer=0 +hacks=no-disable-outport;no-component-role + [omxenc_mpeg4] type-name=GstOMXMPEG4VideoEnc core-name=/usr/lib/libExynosOMX_Core.so @@ -108,7 +119,7 @@ rank=258 in-port-index=0 out-port-index=1 in-port-usebuffer=1 -out-port-usebuffer=1 +out-port-usebuffer=0 hacks=no-component-role;no-disable-outport [omxenc_h263] @@ -119,5 +130,5 @@ rank=258 in-port-index=0 out-port-index=1 in-port-usebuffer=1 -out-port-usebuffer=1 +out-port-usebuffer=0 hacks=no-component-role;no-disable-outport diff --git a/omx/Makefile.am b/omx/Makefile.am index ad740bf..23742f3 100644 --- a/omx/Makefile.am +++ b/omx/Makefile.am @@ -16,8 +16,10 @@ THEORA_H_FILES=gstomxtheoradec.h endif if HAVE_HEVC -HEVC_C_FILES=gstomxh265dec.c -HEVC_H_FILES=gstomxh265dec.h +HEVC_C_FILES=gstomxh265dec.c \ + gstomxh265enc.c +HEVC_H_FILES=gstomxh265dec.h \ + gstomxh265enc.h endif libgstomx_la_SOURCES = \ diff --git a/omx/gstomx.c b/omx/gstomx.c index 4f263e5..3269dfd 100644 --- a/omx/gstomx.c +++ b/omx/gstomx.c @@ -39,6 +39,7 @@ #include "gstomxtheoradec.h" #include "gstomxwmvdec.h" #include "gstomxmpeg4videoenc.h" +#include "gstomxh265enc.h" #include "gstomxh264enc.h" #include "gstomxh263enc.h" #include "gstomxaacdec.h" @@ -1447,7 +1448,7 @@ gst_omx_port_release_buffer (GstOMXPort * port, GstOMXBuffer * buf) err = OMX_EmptyThisBuffer (comp->handle, buf->omx_buf); } else { GST_LOG_OBJECT (comp->parent,"Calling OMX_FillThisBuffer. dmabuf_fd : [%d(%p)]\n", - buf->mm_vbuffer->handle.dmabuf_fd[0], buf); + buf->mm_vbuffer ? buf->mm_vbuffer->handle.dmabuf_fd[0] : 0, buf); err = OMX_FillThisBuffer (comp->handle, buf->omx_buf); } GST_DEBUG_OBJECT (comp->parent, "Released buffer %p to %s port %u: %s " @@ -1818,12 +1819,13 @@ gst_omx_port_tbm_allocate_dec_buffers (GstOMXPort * port, tbm_bufmgr bufmgr, int /* NOTE: Uses comp->lock and comp->messages_lock */ OMX_ERRORTYPE -gst_omx_port_tbm_allocate_enc_buffers (GstOMXPort * port, tbm_bufmgr bufmgr, int eCompressionFormat) +gst_omx_port_tbm_allocate_enc_buffers (GstOMXPort * port, tbm_bufmgr bufmgr, int eCompressionFormat, gboolean use_buffer) { int y_size = 0; int uv_size = 0; OMX_ERRORTYPE err = OMX_ErrorNone; guint n = 0; + gint num = 0; GList *buffers = NULL; tbm_bo_handle handle_bo; MMVideoBuffer *mm_vbuffer[MAX_INPUT_BUFFER]; @@ -1834,27 +1836,29 @@ gst_omx_port_tbm_allocate_enc_buffers (GstOMXPort * port, tbm_bufmgr bufmgr, int /*deallocate previous allocated buffers...*/ if (port->buffers) - gst_omx_port_deallocate_buffers(port); + gst_omx_port_deallocate_buffers (port); n = port->port_def.nBufferCountActual; - for (int i = 0; i < n; i++) { - mm_vbuffer[i] = (MMVideoBuffer*)malloc(sizeof(MMVideoBuffer)); + if (use_buffer) { + for (int i = 0; i < n; i++) { + mm_vbuffer[i] = (MMVideoBuffer*)malloc(sizeof(MMVideoBuffer)); - if (port->index == 1) { - mm_vbuffer[i]->handle.bo[0] = tbm_bo_alloc(bufmgr, port->port_def.nBufferSize, TBM_BO_WC); - handle_bo = tbm_bo_get_handle(mm_vbuffer[i]->handle.bo[0], TBM_DEVICE_MM); - mm_vbuffer[i]->handle.dmabuf_fd[0] = handle_bo.u32; + if (port->index == 1) { + mm_vbuffer[i]->handle.bo[0] = tbm_bo_alloc (bufmgr, port->port_def.nBufferSize, TBM_BO_WC); + handle_bo = tbm_bo_get_handle (mm_vbuffer[i]->handle.bo[0], TBM_DEVICE_MM); + mm_vbuffer[i]->handle.dmabuf_fd[0] = handle_bo.u32; - handle_bo = tbm_bo_get_handle(mm_vbuffer[i]->handle.bo[0], TBM_DEVICE_CPU); - mm_vbuffer[i]->data[0] = handle_bo.ptr; - mm_vbuffer[i]->type = MM_VIDEO_BUFFER_TYPE_TBM_BO; - mm_vbuffer[i]->size[0] = port->port_def.nBufferSize; - mm_vbuffer[i]->handle_num = 1; + handle_bo = tbm_bo_get_handle (mm_vbuffer[i]->handle.bo[0], TBM_DEVICE_CPU); + mm_vbuffer[i]->data[0] = handle_bo.ptr; + mm_vbuffer[i]->type = MM_VIDEO_BUFFER_TYPE_TBM_BO; + mm_vbuffer[i]->size[0] = port->port_def.nBufferSize; + mm_vbuffer[i]->handle_num = 1; + } + buffers = g_list_append (buffers, (gpointer)mm_vbuffer[i]); } - buffers = g_list_append(buffers,(gpointer)mm_vbuffer[i]); } - n = g_list_length ((GList *) buffers); + num = use_buffer ? g_list_length ((GList *) buffers) : -1; err = gst_omx_port_allocate_buffers_unlocked (port, buffers, NULL, n); g_mutex_unlock (&port->comp->lock); @@ -2435,6 +2439,7 @@ static const GGetTypeFunction types[] = { #endif #ifdef HAVE_HEVC , gst_omx_h265_dec_get_type + , gst_omx_h265_enc_get_type #endif #ifdef HAVE_THEORA , gst_omx_theora_dec_get_type diff --git a/omx/gstomx.h b/omx/gstomx.h index a245b88..c0273da 100644 --- a/omx/gstomx.h +++ b/omx/gstomx.h @@ -78,6 +78,15 @@ G_BEGIN_DECLS (st)->nVersion.s.nStep = OMX_VERSION_STEP; \ } G_STMT_END +#ifdef USE_OMX_TARGET_EXYNOS +#define OMX_INIT_PARAM(param) G_STMT_START { \ + memset (&(param), 0, sizeof ((param))); \ + (param).nSize = sizeof (param); \ + (param).nVersion.s.nVersionMajor = 1; \ + (param).nVersion.s.nVersionMinor = 1; \ +} G_STMT_END +#endif + /* Different hacks that are required to work around * bugs in different OpenMAX implementations */ @@ -145,6 +154,7 @@ typedef enum GOmxVendor GOmxVendor; /* check omx vender */ typedef struct _TBMBuffer TBMBuffer; typedef struct _TBMInputBuffer TBMInputBuffer; typedef struct _TBMOutputBuffer TBMOutputBuffer; +typedef struct _EnableGemBuffersParams EnableGemBuffersParams; struct _TBMBuffer { @@ -168,8 +178,6 @@ struct _TBMOutputBuffer GList *buffers; }; -typedef struct _EnableGemBuffersParams EnableGemBuffersParams; - struct _EnableGemBuffersParams { OMX_U32 nSize; @@ -449,7 +457,7 @@ gboolean gst_omx_port_is_flushing (GstOMXPort *port); OMX_ERRORTYPE gst_omx_port_allocate_buffers (GstOMXPort *port); #ifdef TIZEN_FEATURE_OMX OMX_ERRORTYPE gst_omx_port_tbm_allocate_dec_buffers (GstOMXPort * port, tbm_bufmgr bufMgr, int eCompressionFormat, gboolean use_buffer); -OMX_ERRORTYPE gst_omx_port_tbm_allocate_enc_buffers (GstOMXPort * port, tbm_bufmgr bufMgr, int eCompressionFormat); +OMX_ERRORTYPE gst_omx_port_tbm_allocate_enc_buffers (GstOMXPort * port, tbm_bufmgr bufMgr, int eCompressionFormat, gboolean use_buffer); #endif OMX_ERRORTYPE gst_omx_port_use_buffers (GstOMXPort *port, const GList *buffers); OMX_ERRORTYPE gst_omx_port_use_eglimages (GstOMXPort *port, const GList *images); diff --git a/omx/gstomxh264enc.c b/omx/gstomxh264enc.c index aa33ae5..6ddfe85 100644 --- a/omx/gstomxh264enc.c +++ b/omx/gstomxh264enc.c @@ -54,6 +54,10 @@ enum #ifdef USE_OMX_TARGET_RPI PROP_INLINESPSPPSHEADERS, #endif +#ifdef USE_OMX_TARGET_EXYNOS + PROP_NUM_REF_FRAME, + PROP_NUM_B_FRAME, +#endif PROP_PERIODICITYOFIDRFRAMES, PROP_INTERVALOFCODINGINTRAFRAMES }; @@ -61,6 +65,12 @@ enum #ifdef USE_OMX_TARGET_RPI #define GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT TRUE #endif +#ifdef USE_OMX_TARGET_EXYNOS +#define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT (0x00000001) +#define GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX (0x00000002) +#define GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT (0x00000001) +#define GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX (0x00000002) +#endif #define GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT (0xffffffff) #define GST_OMX_H264_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT (0xffffffff) @@ -98,7 +108,23 @@ gst_omx_h264_enc_class_init (GstOMXH264EncClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY)); #endif +#ifdef USE_OMX_TARGET_EXYNOS + g_object_class_install_property (gobject_class, PROP_NUM_REF_FRAME, + g_param_spec_uint ("reference-frame", "set number of reference frame", + "The number of reference frame (0x00000001=component default)", + GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT, GST_OMX_VIDEO_ENC_NUM_REF_FRAME_MAX, + GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_NUM_B_FRAME, + g_param_spec_uint ("b-frame", "set number of b frame", + "The number of reference frame (0x00000001=component default)", + GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT, GST_OMX_VIDEO_ENC_NUM_B_FRAME_MAX, + GST_OMX_VIDEO_ENC_NUM_B_FRAME_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); +#endif g_object_class_install_property (gobject_class, PROP_PERIODICITYOFIDRFRAMES, g_param_spec_uint ("periodicty-idr", "Target Bitrate", "Periodicity of IDR frames (0xffffffff=component default)", @@ -146,6 +172,14 @@ gst_omx_h264_enc_set_property (GObject * object, guint prop_id, self->inline_sps_pps_headers = g_value_get_boolean (value); break; #endif +#ifdef USE_OMX_TARGET_EXYNOS + case PROP_NUM_REF_FRAME: + self->reference_frame = g_value_get_int (value); + break; + case PROP_NUM_B_FRAME: + self->b_frame = g_value_get_int (value); + break; +#endif case PROP_PERIODICITYOFIDRFRAMES: self->periodicty_idr = g_value_get_uint (value); break; @@ -170,6 +204,14 @@ gst_omx_h264_enc_get_property (GObject * object, guint prop_id, GValue * value, g_value_set_boolean (value, self->inline_sps_pps_headers); break; #endif +#ifdef USE_OMX_TARGET_EXYNOS + case PROP_NUM_REF_FRAME: + g_value_set_uint (value, self->reference_frame); + break; + case PROP_NUM_B_FRAME: + g_value_set_uint (value, self->b_frame); + break; +#endif case PROP_PERIODICITYOFIDRFRAMES: g_value_set_uint (value, self->periodicty_idr); break; @@ -189,6 +231,9 @@ gst_omx_h264_enc_init (GstOMXH264Enc * self) self->inline_sps_pps_headers = GST_OMX_H264_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT; #endif +#ifdef USE_OMX_TARGET_EXYNOS + self->reference_frame = GST_OMX_VIDEO_ENC_NUM_REF_FRAME_DEFAULT; +#endif self->periodicty_idr = GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT; self->interval_intraframes = @@ -229,6 +274,9 @@ gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, #ifdef USE_OMX_TARGET_RPI OMX_CONFIG_PORTBOOLEANTYPE config_inline_header; #endif +#ifdef USE_OMX_TARGET_EXYNOS + OMX_VIDEO_PARAM_AVCTYPE avc_param; +#endif OMX_ERRORTYPE err; const gchar *profile_string, *level_string; @@ -262,6 +310,36 @@ gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, return FALSE; } #endif +#ifdef USE_OMX_TARGET_EXYNOS + GST_OMX_INIT_STRUCT (&avc_param); + + err = + gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexParamVideoAvc, &avc_param); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "can't get OMX_IndexParamVideoAvc %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + GST_DEBUG_OBJECT (self, "default nRefFrames:%u, nBFrames:%u", + (guint) avc_param.nRefFrames, + (guint) avc_param.nBFrames); + + avc_param.nRefFrames = self->reference_frame; + avc_param.nBFrames = self->b_frame; + err = + gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexParamVideoAvc, &avc_param); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "can't set OMX_IndexParamVideoAvc %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + +#endif if (self->periodicty_idr != GST_OMX_H264_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT diff --git a/omx/gstomxh264enc.h b/omx/gstomxh264enc.h index 03326e1..51757f5 100644 --- a/omx/gstomxh264enc.h +++ b/omx/gstomxh264enc.h @@ -49,6 +49,10 @@ struct _GstOMXH264Enc #ifdef USE_OMX_TARGET_RPI gboolean inline_sps_pps_headers; #endif +#ifdef USE_OMX_TARGET_EXYNOS + guint32 reference_frame; + guint32 b_frame; +#endif guint32 periodicty_idr; guint32 interval_intraframes; diff --git a/omx/gstomxh265enc.c b/omx/gstomxh265enc.c new file mode 100644 index 0000000..d86e3bb --- /dev/null +++ b/omx/gstomxh265enc.c @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Author: Sejun Park + * + * 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 + +#include "gstomxh265enc.h" + +#ifdef USE_OMX_TARGET_RPI +#include +#include +#endif + +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 GstFlowReturn gst_omx_h265_enc_handle_output_frame (GstOMXVideoEnc * + self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame); +static gboolean gst_omx_h265_enc_flush (GstVideoEncoder * enc); +static gboolean gst_omx_h265_enc_stop (GstVideoEncoder * enc); +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, +#ifdef USE_OMX_TARGET_RPI + PROP_INLINESPSPPSHEADERS, +#endif + PROP_PERIODICITYOFIDRFRAMES, + PROP_INTERVALOFCODINGINTRAFRAMES +}; + +#ifdef USE_OMX_TARGET_RPI +#define GST_OMX_H265_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT TRUE +#endif +#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) + + +/* class initialization */ + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_omx_h265_enc_debug_category, "omxh265enc", 0, \ + "debug category for gst-omx video encoder base class"); + +#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); + GstVideoEncoderClass *basevideoenc_class = GST_VIDEO_ENCODER_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; + +#ifdef USE_OMX_TARGET_RPI + g_object_class_install_property (gobject_class, PROP_INLINESPSPPSHEADERS, + g_param_spec_boolean ("inline-header", + "Inline SPS/PPS headers before IDR", + "Inline SPS/PPS header before IDR", + GST_OMX_H265_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); +#endif + + 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_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)); + + basevideoenc_class->flush = gst_omx_h265_enc_flush; + basevideoenc_class->stop = gst_omx_h265_enc_stop; + + 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 "; + videoenc_class->handle_output_frame = + GST_DEBUG_FUNCPTR (gst_omx_h265_enc_handle_output_frame); + + gst_element_class_set_static_metadata (element_class, + "OpenMAX H.265 Video Encoder", + "Codec/Encoder/Video", + "Encode H.265 video streams", + "Sejun Park "); + + 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) { +#ifdef USE_OMX_TARGET_RPI + case PROP_INLINESPSPPSHEADERS: + self->inline_sps_pps_headers = g_value_get_boolean (value); + break; +#endif + case PROP_PERIODICITYOFIDRFRAMES: + self->periodicty_idr = g_value_get_uint (value); + break; + case PROP_INTERVALOFCODINGINTRAFRAMES: + self->interval_intraframes = g_value_get_uint (value); + break; + 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) { +#ifdef USE_OMX_TARGET_RPI + case PROP_INLINESPSPPSHEADERS: + g_value_set_boolean (value, self->inline_sps_pps_headers); + break; +#endif + case PROP_PERIODICITYOFIDRFRAMES: + g_value_set_uint (value, self->periodicty_idr); + break; + case PROP_INTERVALOFCODINGINTRAFRAMES: + g_value_set_uint (value, self->interval_intraframes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_omx_h265_enc_init (GstOMXH265Enc * self) +{ +#ifdef USE_OMX_TARGET_RPI + self->inline_sps_pps_headers = + GST_OMX_H265_VIDEO_ENC_INLINE_SPS_PPS_HEADERS_DEFAULT; +#endif + self->periodicty_idr = + GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT; + self->interval_intraframes = + GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT; +} + +static gboolean +gst_omx_h265_enc_flush (GstVideoEncoder * enc) +{ + GstOMXH265Enc *self = GST_OMX_H265_ENC (enc); + + g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref); + self->headers = NULL; + + return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (enc); +} + +static gboolean +gst_omx_h265_enc_stop (GstVideoEncoder * enc) +{ + GstOMXH265Enc *self = GST_OMX_H265_ENC (enc); + + g_list_free_full (self->headers, (GDestroyNotify) gst_buffer_unref); + self->headers = NULL; + + return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc); +} + +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_VIDEO_PARAM_PROFILELEVELTYPE param; + OMX_VIDEO_CONFIG_AVCINTRAPERIOD config_avcintraperiod; +#ifdef USE_OMX_TARGET_RPI + OMX_CONFIG_PORTBOOLEANTYPE config_inline_header; +#endif + OMX_ERRORTYPE err; + const gchar *profile_string, *level_string; + +#ifdef USE_OMX_TARGET_RPI + GST_OMX_INIT_STRUCT (&config_inline_header); + config_inline_header.nPortIndex = + GST_OMX_VIDEO_ENC (self)->enc_out_port->index; + err = + gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "can't get OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + if (self->inline_sps_pps_headers) { + config_inline_header.bEnabled = OMX_TRUE; + } else { + config_inline_header.bEnabled = OMX_FALSE; + } + + err = + gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, &config_inline_header); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "can't set OMX_IndexParamBrcmVideoAVCInlineHeaderEnable %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } +#endif + + if (self->periodicty_idr != + GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT + || self->interval_intraframes != + GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) { + + + GST_OMX_INIT_STRUCT (&config_avcintraperiod); + config_avcintraperiod.nPortIndex = + GST_OMX_VIDEO_ENC (self)->enc_out_port->index; + err = + gst_omx_component_get_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "can't get OMX_IndexConfigVideoAVCIntraPeriod %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + GST_DEBUG_OBJECT (self, "default nPFrames:%u, nIDRPeriod:%u", + (guint) config_avcintraperiod.nPFrames, + (guint) config_avcintraperiod.nIDRPeriod); + + if (self->periodicty_idr != + GST_OMX_H265_VIDEO_ENC_PERIODICITY_OF_IDR_FRAMES_DEFAULT) { + config_avcintraperiod.nIDRPeriod = self->periodicty_idr; + } + + if (self->interval_intraframes != + GST_OMX_H265_VIDEO_ENC_INTERVAL_OF_CODING_INTRA_FRAMES_DEFAULT) { + config_avcintraperiod.nPFrames = self->interval_intraframes; + } + + err = + gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexConfigVideoAVCIntraPeriod, &config_avcintraperiod); + 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; + } + } + + gst_omx_port_get_port_definition (GST_OMX_VIDEO_ENC (self)->enc_out_port, + &port_def); + port_def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; + err = + gst_omx_port_update_port_definition (GST_OMX_VIDEO_ENC + (self)->enc_out_port, &port_def); + if (err != OMX_ErrorNone) + return FALSE; + + 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, + "Setting profile/level not supported by component"); + return TRUE; + } + + 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) { + if (g_str_equal (profile_string, "main")) { + param.eProfile = OMX_VIDEO_HEVCProfileMain; + } else if (g_str_equal (profile_string, "main-10")) { + param.eProfile = OMX_VIDEO_HEVCProfileMain10; + } else { + goto unsupported_profile; + } + } + level_string = gst_structure_get_string (s, "level"); + if (level_string) { + if (g_str_equal (level_string, "main1")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel1; + } else if (g_str_equal (level_string, "high1")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel1; + } else if (g_str_equal (level_string, "main2")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel2; + } else if (g_str_equal (level_string, "high2")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel2; + } else if (g_str_equal (level_string, "main2.1")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel21; + } else if (g_str_equal (level_string, "high2.1")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel21; + } else if (g_str_equal (level_string, "main3")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel3; + } else if (g_str_equal (level_string, "high3")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel3; + } else if (g_str_equal (level_string, "main3.1")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel31; + } else if (g_str_equal (level_string, "high3.1")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel31; + } else if (g_str_equal (level_string, "main4")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel4; + } else if (g_str_equal (level_string, "high4")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel4; + } else if (g_str_equal (level_string, "main4.1")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel41; + } else if (g_str_equal (level_string, "high4.1")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel41; + } else if (g_str_equal (level_string, "main5")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel5; + } else if (g_str_equal (level_string, "high5")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel5; + } else if (g_str_equal (level_string, "main5.1")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel51; + } else if (g_str_equal (level_string, "high5.1")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel51; + } else if (g_str_equal (level_string, "main5.2")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel52; + } else if (g_str_equal (level_string, "high5.2")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel52; + } else if (g_str_equal (level_string, "main6")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel6; + } else if (g_str_equal (level_string, "high6")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel6; + } else if (g_str_equal (level_string, "main61")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel61; + } else if (g_str_equal (level_string, "high61")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel61; + } else if (g_str_equal (level_string, "main62")) { + param.eLevel = OMX_VIDEO_HEVCMainTierLevel62; + } else if (g_str_equal (level_string, "high62")) { + param.eLevel = OMX_VIDEO_HEVCHighTierLevel62; + } else { + goto unsupported_level; + } + } + gst_caps_unref (peercaps); + } + + err = + gst_omx_component_set_parameter (GST_OMX_VIDEO_ENC (self)->enc, + OMX_IndexParamVideoProfileLevelCurrent, ¶m); + if (err == OMX_ErrorUnsupportedIndex) { + GST_WARNING_OBJECT (self, + "Setting profile/level not supported by component"); + } 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; + +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; + + 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; + default: + g_assert_not_reached (); + return NULL; + } + + switch (param.eLevel) { + case OMX_VIDEO_HEVCMainTierLevel1: + level = "main1"; + break; + case OMX_VIDEO_HEVCHighTierLevel1: + level = "high1"; + break; + case OMX_VIDEO_HEVCMainTierLevel2: + level = "main2"; + break; + case OMX_VIDEO_HEVCHighTierLevel2: + level = "high2"; + break; + case OMX_VIDEO_HEVCMainTierLevel21: + level = "main2.1"; + break; + case OMX_VIDEO_HEVCHighTierLevel21: + level = "high2.1"; + break; + case OMX_VIDEO_HEVCMainTierLevel3: + level = "main3"; + break; + case OMX_VIDEO_HEVCHighTierLevel3: + level = "high3"; + break; + case OMX_VIDEO_HEVCMainTierLevel31: + level = "main3.1"; + break; + case OMX_VIDEO_HEVCHighTierLevel31: + level = "high3.1"; + break; + case OMX_VIDEO_HEVCMainTierLevel4: + level = "main4"; + break; + case OMX_VIDEO_HEVCHighTierLevel4: + level = "high4"; + break; + case OMX_VIDEO_HEVCMainTierLevel41: + level = "main4.1"; + break; + case OMX_VIDEO_HEVCHighTierLevel41: + level = "high4.1"; + break; + case OMX_VIDEO_HEVCMainTierLevel5: + level = "main5"; + break; + case OMX_VIDEO_HEVCHighTierLevel5: + level = "high5"; + break; + case OMX_VIDEO_HEVCMainTierLevel51: + level = "main5.1"; + break; + case OMX_VIDEO_HEVCHighTierLevel51: + level = "high5.1"; + break; + case OMX_VIDEO_HEVCMainTierLevel52: + level = "main5.2"; + break; + case OMX_VIDEO_HEVCHighTierLevel52: + level = "high5.2"; + break; + case OMX_VIDEO_HEVCMainTierLevel6: + level = "main6"; + break; + case OMX_VIDEO_HEVCHighTierLevel6: + level = "high6"; + break; + case OMX_VIDEO_HEVCMainTierLevel61: + level = "main6.1"; + break; + case OMX_VIDEO_HEVCHighTierLevel61: + level = "high6.1"; + break; + case OMX_VIDEO_HEVCMainTierLevel62: + level = "main6.2"; + break; + case OMX_VIDEO_HEVCHighTierLevel62: + level = "high6.2"; + break; + default: + g_assert_not_reached (); + return NULL; + } + + gst_caps_set_simple (caps, + "profile", G_TYPE_STRING, profile, "level", G_TYPE_STRING, level, NULL); + } + + return caps; +} + +static GstFlowReturn +gst_omx_h265_enc_handle_output_frame (GstOMXVideoEnc * enc, GstOMXPort * port, + GstOMXBuffer * buf, GstVideoCodecFrame * frame) +{ + GstOMXH265Enc *self = GST_OMX_H265_ENC (enc); + + if (buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + /* The codec data is SPS/PPS with a startcode => bytestream stream format + * For bytestream stream format the SPS/PPS is only in-stream and not + * in the caps! + */ + if (buf->omx_buf->nFilledLen >= 4 && + GST_READ_UINT32_BE (buf->omx_buf->pBuffer + + buf->omx_buf->nOffset) == 0x00000001) { + GstBuffer *hdrs; + GstMapInfo map = GST_MAP_INFO_INIT; + + GST_DEBUG_OBJECT (self, "got codecconfig in byte-stream format"); + + hdrs = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); + + gst_buffer_map (hdrs, &map, GST_MAP_WRITE); + memcpy (map.data, + buf->omx_buf->pBuffer + buf->omx_buf->nOffset, + buf->omx_buf->nFilledLen); + gst_buffer_unmap (hdrs, &map); + self->headers = g_list_append (self->headers, hdrs); + + if (frame) + gst_video_codec_frame_unref (frame); + + return GST_FLOW_OK; + } + } else if (self->headers) { + gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), self->headers); + self->headers = NULL; + } + + return + GST_OMX_VIDEO_ENC_CLASS + (gst_omx_h265_enc_parent_class)->handle_output_frame (enc, port, buf, + frame); +} diff --git a/omx/gstomxh265enc.h b/omx/gstomxh265enc.h new file mode 100644 index 0000000..0c34918 --- /dev/null +++ b/omx/gstomxh265enc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * Author: Sejun Park + * + * 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 +#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; + +#ifdef USE_OMX_TARGET_RPI + gboolean inline_sps_pps_headers; +#endif + guint32 periodicty_idr; + guint32 interval_intraframes; + + GList *headers; +}; + +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/gstomxvideodec.c b/omx/gstomxvideodec.c index 1b1732f..872d306 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -213,7 +213,7 @@ gst_omx_video_dec_open (GstVideoDecoder * decoder) #ifdef TIZEN_FEATURE_OMX self->bufmgr = tbm_bufmgr_init(self->drm_fd); - if(self->bufmgr == NULL) { + if (self->bufmgr == NULL) { GST_ERROR_OBJECT (self, "TBM initialization failed."); return FALSE; } @@ -1922,8 +1922,7 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) #ifdef TIZEN_FEATURE_OMX gchar *format_tmp; int i; - EnableGemBuffersParams gemBuffers; - EnableGemBuffersParams config; + EnableGemBuffersParams gem_param; #endif GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream"); @@ -2026,18 +2025,18 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) /* Set platform specific buffer settings. to avoid plane support error.. */ #ifdef TIZEN_FEATURE_OMX - OMX_INIT_STRUCTURE(gemBuffers); - gemBuffers.enable = OMX_TRUE; - gemBuffers.nPortIndex = 1; + OMX_INIT_PARAM (gem_param); + gem_param.enable = OMX_TRUE; + gem_param.nPortIndex = 1; OMX_INDEXTYPE index = OMX_IndexComponentStartUnused; - err = OMX_GetExtensionIndex(self->dec->handle, "OMX.SEC.index.enablePlatformSpecificBuffers", &index); + err = OMX_GetExtensionIndex (self->dec->handle, "OMX.SEC.index.enablePlatformSpecificBuffers", &index); if (err != OMX_ErrorNone || index == OMX_IndexComponentStartUnused) { GST_INFO_OBJECT (self, "can not get index for OMX_GetExtensionIndex enablePlatformSpecificBuffers"); } - err = gst_omx_component_set_parameter(self->dec, index, &gemBuffers); + err = gst_omx_component_set_parameter(self->dec, index, &gem_param); #if 0 err = @@ -2049,13 +2048,13 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) gst_omx_error_to_string (err), err); } - OMX_INIT_STRUCTURE(config); - config.enable = OMX_TRUE; - config.nPortIndex = 0; + OMX_INIT_PARAM (gem_param); + gem_param.enable = OMX_TRUE; + gem_param.nPortIndex = 0; err = gst_omx_component_set_parameter (self->dec, - OMX_IndexParamEnableTimestampReorder, &config); + OMX_IndexParamEnableTimestampReorder, &gem_param); if (err != OMX_ErrorNone) { GST_ERROR_OBJECT (self, "Failed to set timestamp reorder: %s (0x%08x)", diff --git a/omx/gstomxvideodec.h b/omx/gstomxvideodec.h index 0511f31..fd08a83 100644 --- a/omx/gstomxvideodec.h +++ b/omx/gstomxvideodec.h @@ -31,23 +31,6 @@ #include "gstomx.h" -#define OMX_VERSION_MAJOR 1 -#define OMX_VERSION_MINOR 1 -#define OMX_VERSION_REVISION 2 -#define OMX_VERSION_STEP 0 -#define EXTRA_DECODER_OUTPUT_BUF 4 - -#define OMX_VERSION ((OMX_VERSION_STEP<<24) | (OMX_VERSION_REVISION<<16) | (OMX_VERSION_MINOR<<8) | OMX_VERSION_MAJOR) - -#define OMX_INIT_STRUCTURE(a) \ - memset(&(a), 0, sizeof(a)); \ - (a).nSize = sizeof(a); \ - (a).nVersion.nVersion = OMX_VERSION; \ - (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \ - (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \ - (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \ - (a).nVersion.s.nStep = OMX_VERSION_STEP - G_BEGIN_DECLS #define GST_TYPE_OMX_VIDEO_DEC \ @@ -63,6 +46,8 @@ G_BEGIN_DECLS #define GST_IS_OMX_VIDEO_DEC_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OMX_VIDEO_DEC)) +#define EXTRA_DECODER_OUTPUT_BUF 4 + typedef struct _GstOMXVideoDec GstOMXVideoDec; typedef struct _GstOMXVideoDecClass GstOMXVideoDecClass; diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c index 965ceb1..d0cf315 100644 --- a/omx/gstomxvideoenc.c +++ b/omx/gstomxvideoenc.c @@ -116,6 +116,7 @@ enum #define GST_OMX_VIDEO_ENC_QUANT_P_FRAMES_DEFAULT (0xffffffff) #define GST_OMX_VIDEO_ENC_QUANT_B_FRAMES_DEFAULT (0xffffffff) + /* class initialization */ #define DEBUG_INIT \ @@ -211,7 +212,7 @@ gst_omx_video_enc_init (GstOMXVideoEnc * self) g_mutex_init (&self->drain_lock); g_cond_init (&self->drain_cond); #ifdef TIZEN_FEATURE_OMX - self->hTBMBufMgr = NULL; + self->bufmgr = NULL; self->drm_fd = -1; #endif } @@ -246,6 +247,41 @@ gst_omx_video_enc_input_dump (MMVideoBuffer *inbuf) } #endif +#ifdef TIZEN_FEATURE_OMX +static void +set_enable_platformSpecificBuffer(GstOMXVideoEnc * self) +{ + OMX_INDEXTYPE index = OMX_IndexComponentStartUnused; + OMX_ERRORTYPE err = OMX_ErrorNone; + EnableGemBuffersParams params; + + GST_LOG_OBJECT (self, "set_enable_platformSpecificBuffer enter"); + + err = OMX_GetExtensionIndex(self->enc->handle, "OMX.SEC.index.enablePlatformSpecificBuffers", &index); + if (err != OMX_ErrorNone || index == OMX_IndexComponentStartUnused) { + GST_INFO_OBJECT (self, "can not get index for OMX_GetExtensionIndex enablePlatformSpecificBuffers"); + return; + } + + GST_INFO ("index= %x", index); + + OMX_INIT_PARAM (params); + + params.nPortIndex = self->enc_in_port->index; + params.enable = OMX_TRUE; + + err = OMX_SetParameter(self->enc->handle, index, ¶ms); + if (err == OMX_ErrorNone) { + GST_INFO_OBJECT (self, "set_enable_platformSpecificBuffer success."); + } + else { + GST_ERROR_OBJECT (self, "set OMX_IndexParamEnablePlatformSpecificBuffers failed with error %d (0x%08x)", err, err); + } + + return; +} +#endif + static gboolean gst_omx_video_enc_open (GstVideoEncoder * encoder) { @@ -295,6 +331,11 @@ gst_omx_video_enc_open (GstVideoEncoder * encoder) self->enc_in_port = gst_omx_component_add_port (self->enc, in_port_index); self->enc_out_port = gst_omx_component_add_port (self->enc, out_port_index); +#ifdef TIZEN_FEATURE_OMX + /* get extension index and set platform specific buffer enable */ + set_enable_platformSpecificBuffer (self); +#endif + if (!self->enc_in_port || !self->enc_out_port) return FALSE; @@ -366,6 +407,11 @@ gst_omx_video_enc_open (GstVideoEncoder * encoder) if (self->quant_b_frames != 0xffffffff) quant_param.nQpB = self->quant_b_frames; +#ifdef TIZEN_FEATURE_OMX + quant_param.nQpI = 20; + quant_param.nQpP = 20; + quant_param.nQpB = 20; +#endif err = gst_omx_component_set_parameter (self->enc, OMX_IndexParamVideoQuantization, &quant_param); @@ -389,13 +435,34 @@ gst_omx_video_enc_open (GstVideoEncoder * encoder) } } +/* +#ifdef TIZEN_FEATURE_OMX + { + OMX_VIDEO_PARAM_AVCTYPE param; + + GST_OMX_INIT_STRUCT (¶m); + param.nPortIndex = self->enc_out_port->index; + err = gst_omx_component_get_parameter (self->enc, OMX_IndexParamVideoAvc, ¶m); + if (err != OMX_ErrorNone) + GST_ERROR_OBJECT (self, "Failed to get OMX_IndexParamVideoAvc parameter. ret = %d", err); + + param.nPFrames = self->idr_period - 1; + err = gst_omx_component_set_parameter (self->enc, OMX_IndexParamVideoAvc, ¶m); + if (err != OMX_ErrorNone) + GST_ERROR_OBJECT (self, "Failed to set OMX_IndexParamVideoAvc. IDR period = %d ret = %d", self->idr_period, err); + } +#endif +*/ } #ifdef TIZEN_FEATURE_OMX - self->hTBMBufMgr = tbm_bufmgr_init(self->drm_fd); - if(self->hTBMBufMgr == NULL){ + self->bufmgr = tbm_bufmgr_init (self->drm_fd); + if (self->bufmgr == NULL){ GST_ERROR_OBJECT (self, "TBM initialization failed."); return FALSE; } + + self->enc_in_port->use_buffer = klass->cdata.in_port_usebuffer; + self->enc_out_port->use_buffer = klass->cdata.out_port_usebuffer; #endif return TRUE; } @@ -618,11 +685,20 @@ gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, self->input_state); state->codec_data = codec_data; gst_video_codec_state_unref (state); +#ifdef TIZEN_FEATURE_OMX + /*Modification : codec data already set_caps, so unref frame whenever negotiate ok or not*/ + if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) + flow_ret = GST_FLOW_NOT_NEGOTIATED; + else + flow_ret = GST_FLOW_OK; + gst_video_codec_frame_unref (frame); +#else if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) { gst_video_codec_frame_unref (frame); return GST_FLOW_NOT_NEGOTIATED; } flow_ret = GST_FLOW_OK; +#endif } else if (buf->omx_buf->nFilledLen > 0) { GstBuffer *outbuf; GstMapInfo map = GST_MAP_INFO_INIT; @@ -757,8 +833,8 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self) if (err != OMX_ErrorNone) goto reconfigure_error; #ifdef TIZEN_FEATURE_OMX - err = gst_omx_port_tbm_allocate_enc_buffers(port, self->hTBMBufMgr, - self->enc_in_port->port_def.format.video.eCompressionFormat); + err = gst_omx_port_tbm_allocate_enc_buffers(port, self->bufmgr, + self->enc_in_port->port_def.format.video.eCompressionFormat, port->use_buffer); #else err = gst_omx_port_allocate_buffers (port); #endif @@ -1095,15 +1171,23 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, } port_def.format.video.nFrameWidth = info->width; +#ifdef TIZEN_FEATURE_OMX + port_def.format.video.nStride = ALIGN(info->width, 16); +#else if (port_def.nBufferAlignment) port_def.format.video.nStride = (info->width + port_def.nBufferAlignment - 1) & (~(port_def.nBufferAlignment - 1)); else port_def.format.video.nStride = GST_ROUND_UP_4 (info->width); /* safe (?) default */ +#endif port_def.format.video.nFrameHeight = info->height; +#ifdef TIZEN_FEATURE_OMX + port_def.format.video.nSliceHeight = ALIGN(info->width, 16); +#else port_def.format.video.nSliceHeight = info->height; +#endif switch (port_def.format.video.eColorFormat) { case OMX_COLOR_FormatYUV420Planar: @@ -1146,6 +1230,18 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, &port_def) != OMX_ErrorNone) return FALSE; +#ifdef TIZEN_FEATURE_OMX + /*MODIFICATION : Output port configuration*/ + GST_DEBUG_OBJECT (self, "Updating outport port definition"); + gst_omx_port_get_port_definition (self->enc_out_port, &port_def); + + port_def.format.video.nFrameWidth = info->width; + port_def.format.video.nFrameHeight = info->height; + + if (gst_omx_port_update_port_definition (self->enc_out_port, &port_def) != OMX_ErrorNone) + return FALSE; +#endif + #ifdef USE_OMX_TARGET_RPI /* aspect ratio */ { @@ -1216,8 +1312,9 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone) return FALSE; #ifdef TIZEN_FEATURE_OMX - if(gst_omx_port_tbm_allocate_enc_buffers(self->enc_in_port, self->hTBMBufMgr, - self->enc_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone) + if (gst_omx_port_tbm_allocate_enc_buffers (self->enc_in_port, self->bufmgr, + self->enc_in_port->port_def.format.video.eCompressionFormat, + self->enc_in_port->use_buffer) != OMX_ErrorNone) return FALSE; #else if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) @@ -1264,8 +1361,9 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, /* Need to allocate buffers to reach Idle state */ #ifdef TIZEN_FEATURE_OMX - if(gst_omx_port_tbm_allocate_enc_buffers(self->enc_in_port, self->hTBMBufMgr, - self->enc_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone) + if (gst_omx_port_tbm_allocate_enc_buffers(self->enc_in_port, self->bufmgr, + self->enc_in_port->port_def.format.video.eCompressionFormat, + self->enc_in_port->use_buffer) != OMX_ErrorNone) return FALSE; #else if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone) @@ -1273,8 +1371,9 @@ gst_omx_video_enc_set_format (GstVideoEncoder * encoder, #endif #ifdef TIZEN_FEATURE_OMX - if(gst_omx_port_tbm_allocate_enc_buffers(self->enc_out_port, self->hTBMBufMgr, - self->enc_out_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone) + if (gst_omx_port_tbm_allocate_enc_buffers(self->enc_out_port, self->bufmgr, + self->enc_out_port->port_def.format.video.eCompressionFormat, + self->enc_out_port->use_buffer) != OMX_ErrorNone) #else if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone) #endif @@ -1644,8 +1743,8 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, goto reconfigure_error; } #ifdef TIZEN_FEATURE_OMX - err = gst_omx_port_tbm_allocate_enc_buffers(port, self->hTBMBufMgr, - self->enc_in_port->port_def.format.video.eCompressionFormat); + err = gst_omx_port_tbm_allocate_enc_buffers (port, self->bufmgr, + self->enc_in_port->port_def.format.video.eCompressionFormat, port->use_buffer); #else err = gst_omx_port_allocate_buffers (port); #endif diff --git a/omx/gstomxvideoenc.h b/omx/gstomxvideoenc.h index 497ca54..06748c0 100644 --- a/omx/gstomxvideoenc.h +++ b/omx/gstomxvideoenc.h @@ -78,7 +78,7 @@ struct _GstOMXVideoEnc GstFlowReturn downstream_flow_ret; #ifdef TIZEN_FEATURE_OMX gint drm_fd; - tbm_bufmgr hTBMBufMgr; + tbm_bufmgr bufmgr; #endif }; -- 2.7.4