From 692156816122f6d87ee97e505f7469d3152a0cb9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 6 Feb 2018 14:25:57 +0100 Subject: videoenc: implement ROI on zynqultrascaleplus Check input buffers for ROI meta and pass them to the encoder by using zynqultrascaleplus's custom OMX extension. Also add a new "default-roi-quality" in order to tell the encoder what quality level should be applied to ROI by default. https://bugzilla.gnome.org/show_bug.cgi?id=793696 --- omx/gstomxvideoenc.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ omx/gstomxvideoenc.h | 5 +++ 2 files changed, 111 insertions(+) diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c index efcc40d..c9a39c0 100644 --- a/omx/gstomxvideoenc.c +++ b/omx/gstomxvideoenc.c @@ -176,6 +176,25 @@ gst_omx_video_enc_aspect_ratio_get_type (void) return qtype; } +#define GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY (gst_omx_video_enc_roi_quality_type ()) +static GType +gst_omx_video_enc_roi_quality_type (void) +{ + static GType qtype = 0; + + if (qtype == 0) { + static const GEnumValue values[] = { + {OMX_ALG_ROI_QUALITY_HIGH, "Delta QP of -5", "high"}, + {OMX_ALG_ROI_QUALITY_MEDIUM, "Delta QP of 0", "medium"}, + {OMX_ALG_ROI_QUALITY_LOW, "Delta QP of +5", "low"}, + {OMX_ALG_ROI_QUALITY_DONT_CARE, "Maximum delta QP value", "dont-care"}, + {0, NULL, NULL} + }; + + qtype = g_enum_register_static ("GstOMXVideoEncRoiQuality", values); + } + return qtype; +} #endif /* prototypes */ @@ -233,6 +252,7 @@ enum PROP_NUM_SLICES, PROP_SLICE_SIZE, PROP_DEPENDENT_SLICE, + PROP_DEFAULT_ROI_QUALITY, }; /* FIXME: Better defaults */ @@ -256,6 +276,7 @@ enum #define GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT (0xffffffff) #define GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT (0) #define GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT (FALSE) +#define GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY OMX_ALG_ROI_QUALITY_HIGH /* class initialization */ #define do_init \ @@ -432,6 +453,13 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) "dependent slice segments or regular slices", GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DEFAULT_ROI_QUALITY, + g_param_spec_enum ("default-roi-quality", "Default ROI Qualtiy", + "The default quality level to apply to each Region of Interest", + GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY, + GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); #endif element_class->change_state = @@ -484,10 +512,16 @@ gst_omx_video_enc_init (GstOMXVideoEnc * self) self->num_slices = GST_OMX_VIDEO_ENC_NUM_SLICES_DEFAULT; self->slice_size = GST_OMX_VIDEO_ENC_SLICE_SIZE_DEFAULT; self->dependent_slice = GST_OMX_VIDEO_ENC_DEPENDENT_SLICE_DEFAULT; + self->default_roi_quality = GST_OMX_VIDEO_ENC_DEFAULT_ROI_QUALITY; #endif g_mutex_init (&self->drain_lock); g_cond_init (&self->drain_cond); + +#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS + self->alg_roi_quality_enum_class = + g_type_class_ref (GST_TYPE_OMX_VIDEO_ENC_ROI_QUALITY); +#endif } #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS @@ -908,6 +942,10 @@ gst_omx_video_enc_finalize (GObject * object) g_mutex_clear (&self->drain_lock); g_cond_clear (&self->drain_cond); +#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS + g_clear_pointer (&self->alg_roi_quality_enum_class, g_type_class_unref); +#endif + G_OBJECT_CLASS (gst_omx_video_enc_parent_class)->finalize (object); } @@ -996,6 +1034,9 @@ gst_omx_video_enc_set_property (GObject * object, guint prop_id, case PROP_DEPENDENT_SLICE: self->dependent_slice = g_value_get_boolean (value); break; + case PROP_DEFAULT_ROI_QUALITY: + self->default_roi_quality = g_value_get_enum (value); + break; #endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1073,6 +1114,9 @@ gst_omx_video_enc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_DEPENDENT_SLICE: g_value_set_boolean (value, self->dependent_slice); break; + case PROP_DEFAULT_ROI_QUALITY: + g_value_set_enum (value, self->default_roi_quality); + break; #endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2416,6 +2460,65 @@ done: return ret; } +#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS +static void +handle_roi_metadata (GstOMXVideoEnc * self, GstBuffer * input) +{ + GstMeta *meta; + gpointer state = NULL; + + while ((meta = + gst_buffer_iterate_meta_filtered (input, &state, + GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE))) { + GstVideoRegionOfInterestMeta *roi = (GstVideoRegionOfInterestMeta *) meta; + OMX_ALG_VIDEO_CONFIG_REGION_OF_INTEREST roi_param; + GstStructure *s; + + GST_LOG_OBJECT (self, "Input buffer ROI: type=%s id=%d (%d, %d) %dx%d", + g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w, + roi->h); + + GST_OMX_INIT_STRUCT (&roi_param); + roi_param.nPortIndex = self->enc_in_port->index; + roi_param.nLeft = roi->x; + roi_param.nTop = roi->y; + roi_param.nWidth = roi->w; + roi_param.nHeight = roi->h; + + s = gst_video_region_of_interest_meta_get_param (roi, "roi/omx-alg"); + if (s) { + const gchar *quality; + GEnumValue *evalue; + + quality = gst_structure_get_string (s, "quality"); + + evalue = + g_enum_get_value_by_nick (self->alg_roi_quality_enum_class, quality); + if (!evalue) { + roi_param.eQuality = self->default_roi_quality; + + GST_WARNING_OBJECT (self, + "Unknown ROI encoding quality '%s', use default (%d)", + quality, self->default_roi_quality); + } else { + roi_param.eQuality = evalue->value; + + GST_LOG_OBJECT (self, "Use encoding quality '%s' from upstream", + quality); + } + } else { + roi_param.eQuality = self->default_roi_quality; + + GST_LOG_OBJECT (self, "No quality specified upstream, use default (%d)", + self->default_roi_quality); + } + + gst_omx_component_set_config (self->enc, + (OMX_INDEXTYPE) OMX_ALG_IndexConfigVideoRegionOfInterest, &roi_param); + } +} +#endif + static GstFlowReturn gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) @@ -2572,6 +2675,9 @@ gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)", gst_omx_error_to_string (err), err); } +#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS + handle_roi_metadata (self, frame->input_buffer); +#endif /* Copy the buffer content in chunks of size as requested * by the port */ diff --git a/omx/gstomxvideoenc.h b/omx/gstomxvideoenc.h index 3a5f2cf..a732254 100644 --- a/omx/gstomxvideoenc.h +++ b/omx/gstomxvideoenc.h @@ -91,6 +91,7 @@ struct _GstOMXVideoEnc guint32 num_slices; guint32 slice_size; gboolean dependent_slice; + gint default_roi_quality; #endif GstFlowReturn downstream_flow_ret; @@ -98,6 +99,10 @@ struct _GstOMXVideoEnc GstOMXBufferAllocation input_allocation; /* TRUE if encoder is passing dmabuf's fd directly to the OMX component */ gboolean input_dmabuf; + +#ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS + GEnumClass *alg_roi_quality_enum_class; +#endif }; struct _GstOMXVideoEncClass -- cgit v1.2.1