[Spice-devel] [PATCH v5 13/20] server: Give up after a while if GStreamer cannot handle the video.
Francois Gouget
fgouget at codeweavers.com
Thu Aug 27 12:01:26 PDT 2015
This typically happens when sending very small frames (less than 16 pixels in one dimension) to the x264enc encoder.
This avoids repeatedly wasting time rebuilding the pipeline.
Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
---
server/gstreamer_encoder.c | 49 ++++++++++++++++++++++++++++++++++++----------
1 file changed, 39 insertions(+), 10 deletions(-)
diff --git a/server/gstreamer_encoder.c b/server/gstreamer_encoder.c
index 7f6800f..fc8dc27 100644
--- a/server/gstreamer_encoder.c
+++ b/server/gstreamer_encoder.c
@@ -91,6 +91,9 @@ struct GstEncoder {
SpiceFormatForGStreamer *format;
SpiceBitmapFmt spice_format;
+ /* Number of consecutive frame encoding errors. */
+ uint32_t errors;
+
/* ---------- GStreamer pipeline ---------- */
/* Pointers to the GStreamer pipeline elements. If pipeline is NULL the
@@ -760,27 +763,31 @@ static void set_appsrc_caps(GstEncoder *encoder)
g_object_set(G_OBJECT(encoder->appsrc), "caps", encoder->src_caps, NULL);
}
-/* A helper for gst_encoder_encode_frame(). */
-static gboolean construct_pipeline(GstEncoder *encoder, const SpiceBitmap *bitmap)
+static const gchar* get_gst_codec_name(GstEncoder *encoder)
{
- const gchar* gstenc_name;
switch (encoder->base.codec_type)
{
case SPICE_VIDEO_CODEC_TYPE_MJPEG:
#ifdef HAVE_GSTREAMER_0_10
- gstenc_name = "ffenc_mjpeg";
+ return "ffenc_mjpeg";
#else
- gstenc_name = "avenc_mjpeg";
+ return "avenc_mjpeg";
#endif
- break;
case SPICE_VIDEO_CODEC_TYPE_VP8:
- gstenc_name = "vp8enc";
- break;
+ return "vp8enc";
case SPICE_VIDEO_CODEC_TYPE_H264:
- gstenc_name = "x264enc";
- break;
+ return "x264enc";
default:
spice_warning("unsupported codec type %d", encoder->base.codec_type);
+ return NULL;
+ }
+}
+
+/* A helper for gst_encoder_encode_frame(). */
+static gboolean construct_pipeline(GstEncoder *encoder, const SpiceBitmap *bitmap)
+{
+ const gchar* gstenc_name = get_gst_codec_name(encoder);
+ if (!gstenc_name) {
return FALSE;
}
#ifdef HAVE_GSTREAMER_0_10
@@ -1177,6 +1184,7 @@ static int gst_encoder_encode_frame(GstEncoder *encoder,
encoder->format = map_format(bitmap->format);
if (!encoder->format) {
spice_debug("unable to map format type %d", bitmap->format);
+ encoder->errors = 4;
return VIDEO_ENCODER_FRAME_UNSUPPORTED;
}
encoder->spice_format = bitmap->format;
@@ -1192,6 +1200,19 @@ static int gst_encoder_encode_frame(GstEncoder *encoder,
} else if (encoder->pipeline) {
reconfigure_pipeline(encoder);
}
+ encoder->errors = 0;
+ } else if (encoder->errors >= 3) {
+ /* The pipeline keeps failing to handle the frames we send it, which is
+ * usually because they are too small (mouse pointer-sized).
+ * So give up until something changes.
+ */
+ if (encoder->errors == 3) {
+ spice_debug("%s cannot compress %dx%d:%dbpp frames",
+ get_gst_codec_name(encoder), encoder->width,
+ encoder->height, encoder->format->bpp);
+ encoder->errors++;
+ }
+ return VIDEO_ENCODER_FRAME_UNSUPPORTED;
}
if (rate_control_is_active(encoder) &&
@@ -1202,6 +1223,7 @@ static int gst_encoder_encode_frame(GstEncoder *encoder,
}
if (!encoder->pipeline && !construct_pipeline(encoder, bitmap)) {
+ encoder->errors++;
return VIDEO_ENCODER_FRAME_UNSUPPORTED;
}
@@ -1209,6 +1231,13 @@ static int gst_encoder_encode_frame(GstEncoder *encoder,
if (rc == VIDEO_ENCODER_FRAME_ENCODE_DONE) {
rc = pull_compressed_buffer(encoder, buffer);
#ifdef DO_ZERO_COPY
+ if (rc != VIDEO_ENCODER_FRAME_ENCODE_DONE) {
+ /* The input buffer will be stuck in the pipeline, preventing later
+ * ones from being processed. So reset the pipeline.
+ */
+ reset_pipeline(encoder);
+ encoder->errors++;
+ }
/* GStreamer should have released the source frame buffer by now */
spice_assert(!encoder->needs_bitmap);
#endif
--
2.5.0
More information about the Spice-devel
mailing list