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@xxxxxxxxxxxxxxx> --- 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel