videoenc: implement ROI on zynqultrascaleplus
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Tue, 6 Feb 2018 13:25:57 +0000 (14:25 +0100)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 21 Feb 2018 17:31:39 +0000 (12:31 -0500)
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
omx/gstomxvideoenc.h

index efcc40d..c9a39c0 100644 (file)
@@ -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 */
index 3a5f2cf..a732254 100644 (file)
@@ -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