[Spice-devel,v7,16/23] server: Respect the GStreamer encoder's valid bit rate range

Submitted by Francois Gouget on Dec. 16, 2015, 3:19 p.m.

Details

Message ID alpine.DEB.2.20.1512161126460.16981@amboise
State New
Headers show
Series "Add GStreamer support for video streaming" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Francois Gouget Dec. 16, 2015, 3:19 p.m.
Otherwise it may get wrapped to a much lower value than intended.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
---
 server/gstreamer-encoder.c | 65 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c
index 3c1e86e..bcf28e7 100644
--- a/server/gstreamer-encoder.c
+++ b/server/gstreamer-encoder.c
@@ -20,6 +20,8 @@ 
 #include <config.h>
 #endif
 
+#include <inttypes.h>
+
 #include <gst/gst.h>
 #include <gst/app/gstappsrc.h>
 #include <gst/app/gstappsink.h>
@@ -777,6 +779,65 @@  static gboolean create_pipeline(SpiceGstEncoder *encoder)
     return TRUE;
 }
 
+/* A helper for configure_pipeline() */
+static void set_gstenc_bitrate(SpiceGstEncoder *encoder)
+{
+    GObjectClass *class = G_OBJECT_GET_CLASS(encoder->gstenc);
+    GParamSpec *param = g_object_class_find_property(class, "bitrate");
+    if (param == NULL) {
+        param = g_object_class_find_property(class, "target-bitrate");
+    }
+    if (param) {
+        uint64_t gst_bit_rate = encoder->video_bit_rate;
+        if (strstr(g_param_spec_get_blurb(param), "kbit")) {
+            gst_bit_rate = gst_bit_rate / 1024;
+        }
+        switch (param->value_type) {
+        case G_TYPE_ULONG: {
+            GParamSpecULong *range = G_PARAM_SPEC_ULONG(param);
+            gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate));
+            break;
+        }
+        case G_TYPE_LONG: {
+            GParamSpecLong *range = G_PARAM_SPEC_LONG(param);
+            gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate));
+            break;
+        }
+        case G_TYPE_UINT: {
+            GParamSpecUInt *range = G_PARAM_SPEC_UINT(param);
+            gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate));
+            break;
+        }
+        case G_TYPE_INT: {
+            GParamSpecInt *range = G_PARAM_SPEC_INT(param);
+            gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate));
+            break;
+        }
+        case G_TYPE_UINT64: {
+            GParamSpecUInt64 *range = G_PARAM_SPEC_UINT64(param);
+            gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate));
+            break;
+        }
+        case G_TYPE_INT64: {
+            GParamSpecInt64 *range = G_PARAM_SPEC_INT64(param);
+            gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate));
+            break;
+        }
+        default:
+            spice_debug("the %s property has an unsupported type %zu",
+                        g_param_spec_get_name(param), param->value_type);
+        }
+        spice_debug("setting the GStreamer %s to %"PRIu64,
+                    g_param_spec_get_name(param), gst_bit_rate);
+        g_object_set(G_OBJECT(encoder->gstenc),
+                     g_param_spec_get_name(param), gst_bit_rate,
+                     NULL);
+    } else {
+        spice_printerr("Could not find the bit rate property for %s",
+                       get_gst_codec_name(encoder));
+    }
+}
+
 /* A helper for spice_gst_encoder_encode_frame() */
 static gboolean configure_pipeline(SpiceGstEncoder *encoder,
                                    const SpiceBitmap *bitmap)
@@ -786,10 +847,10 @@  static gboolean configure_pipeline(SpiceGstEncoder *encoder,
     }
 
     /* Configure the encoder bitrate, frame latency, etc. */
+    set_gstenc_bitrate(encoder);
     switch (encoder->base.codec_type) {
     case SPICE_VIDEO_CODEC_TYPE_MJPEG:
         g_object_set(G_OBJECT(encoder->gstenc),
-                     "bitrate", encoder->video_bit_rate,
                      "max-threads", 1, /* zero-frame latency */
                      NULL);
 
@@ -807,7 +868,6 @@  static gboolean configure_pipeline(SpiceGstEncoder *encoder,
         g_object_set(G_OBJECT(encoder->gstenc),
                      "resize-allowed", TRUE, /* for very low bit rates */
                      "min-quantizer", 10, /* seems virtually lossless */
-                     "target-bitrate", encoder->video_bit_rate,
                      "end-usage", 1, /* CBR */
                      "lag-in-frames", 0, /* zero-frame latency */
                      "error-resilient", 1, /* for client frame drops */
@@ -818,7 +878,6 @@  static gboolean configure_pipeline(SpiceGstEncoder *encoder,
         }
     case SPICE_VIDEO_CODEC_TYPE_H264:
         g_object_set(G_OBJECT(encoder->gstenc),
-                     "bitrate", encoder->video_bit_rate / 1024,
                      "qp-min", 15, /* virtually lossless */
                      "byte-stream", TRUE,
                      "aud", FALSE,