Signed-off-by: Francois Gouget <fgouget@xxxxxxxxxxxxxxx> --- configure.ac | 1 + server/gstreamer-encoder.c | 74 ++++++++++++++++++++++++++++++++++++++++------ server/reds.c | 4 ++- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 9904bc8..9bd8ccb 100644 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,7 @@ if test "x$enable_gstreamer" != "xno"; then [enable_gstreamer="yes" SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-base 1.0], [appsrc videoconvert appsink]) SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gstreamer-libav 1.0], [avenc_mjpeg]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-good 1.0], [vp8enc]) ], [if test "x$enable_gstreamer" = "xyes"; then AC_MSG_ERROR([GStreamer 1.0 support requested but not found. You may set GSTREAMER_1_0_CFLAGS and GSTREAMER_1_0_LIBS to avoid the need to call pkg-config.]) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index d6eb1eb..5e6e52c 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -191,11 +191,42 @@ static void set_appsrc_caps(SpiceGstEncoder *encoder) /* A helper for spice_gst_encoder_encode_frame() */ static gboolean create_pipeline(SpiceGstEncoder *encoder) { + gchar *gstenc; + switch (encoder->base.codec_type) + { + case SPICE_VIDEO_CODEC_TYPE_MJPEG: + /* Set max-threads to ensure zero-frame latency */ + gstenc = g_strdup("avenc_mjpeg max-threads=1"); + break; + case SPICE_VIDEO_CODEC_TYPE_VP8: { + /* See http://www.webmproject.org/docs/encoder-parameters/ + * - Set end-usage to get a constant bitrate to help with streaming. + * - resize-allowed allows trading resolution for low bitrates while + * min-quantizer ensures the bitrate does not get needlessly high. + * - error-resilient minimises artifacts in case the client drops a + * frame. + * - Set lag-in-frames, deadline and cpu-used to match + * "Profile Realtime". lag-in-frames ensures zero-frame latency, + * deadline turns on realtime behavior, and cpu-used targets a 75% + * CPU usage. + * - deadline is supposed to be set in microseconds but in practice + * it behaves like a boolean. + */ + gstenc = g_strdup_printf("vp8enc end-usage=cbr min-quantizer=10 resize-allowed=true error-resilient=true lag-in-frames=0 deadline=1 cpu-used=4"); + break; + } + default: + /* gstreamer_encoder_new() should have rejected this codec type */ + spice_warning("unsupported codec type %d", encoder->base.codec_type); + return FALSE; + } + GError *err = NULL; - /* Set max-threads to ensure zero-frame latency */ - const gchar *desc = "appsrc is-live=true format=time do-timestamp=true name=src ! videoconvert ! avenc_mjpeg max-threads=1 name=encoder ! appsink name=sink"; + gchar *desc = g_strdup_printf("appsrc is-live=true format=time do-timestamp=true name=src ! videoconvert ! %s name=encoder ! appsink name=sink", gstenc); spice_debug("GStreamer pipeline: %s", desc); encoder->pipeline = gst_parse_launch_full(desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &err); + g_free(gstenc); + g_free(desc); if (!encoder->pipeline || err) { spice_warning("GStreamer error: %s", err->message); g_clear_error(&err); @@ -221,12 +252,27 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, /* Configure the encoder bitrate */ adjust_bit_rate(encoder); - g_object_set(G_OBJECT(encoder->gstenc), - "bitrate", (gint)encoder->bit_rate, NULL); - - /* See https://bugzilla.gnome.org/show_bug.cgi?id=753257 */ - spice_debug("removing the pipeline clock"); - gst_pipeline_use_clock(GST_PIPELINE(encoder->pipeline), NULL); + switch (encoder->base.codec_type) + { + case SPICE_VIDEO_CODEC_TYPE_MJPEG: + g_object_set(G_OBJECT(encoder->gstenc), + "bitrate", (gint)encoder->bit_rate, + NULL); + /* See https://bugzilla.gnome.org/show_bug.cgi?id=753257 */ + spice_debug("removing the pipeline clock"); + gst_pipeline_use_clock(GST_PIPELINE(encoder->pipeline), NULL); + break; + case SPICE_VIDEO_CODEC_TYPE_VP8: + g_object_set(G_OBJECT(encoder->gstenc), + "target-bitrate", (gint)encoder->bit_rate, + NULL); + break; + default: + /* gstreamer_encoder_new() should have rejected this codec type */ + spice_warning("unsupported codec type %d", encoder->base.codec_type); + free_pipeline(encoder); + return FALSE; + } /* Set the source caps */ set_appsrc_caps(encoder); @@ -247,6 +293,15 @@ static void reconfigure_pipeline(SpiceGstEncoder *encoder) if (!is_pipeline_configured(encoder)) { return; } + if (encoder->base.codec_type == SPICE_VIDEO_CODEC_TYPE_VP8) { + /* vp8enc fails to account for caps changes that modify the frame + * size and complains about the buffer size. + * So recreate the pipeline from scratch. + */ + free_pipeline(encoder); + return; + } + if (gst_element_set_state(encoder->pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { spice_debug("GStreamer error: could not pause the pipeline, rebuilding it instead"); free_pipeline(encoder); @@ -511,7 +566,8 @@ VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type, uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs) { - spice_return_val_if_fail(codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG, NULL); + spice_return_val_if_fail(codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG || + codec_type == SPICE_VIDEO_CODEC_TYPE_VP8, NULL); GError *err = NULL; if (!gst_init_check(NULL, NULL, &err)) { diff --git a/server/reds.c b/server/reds.c index a270fa6..cffed46 100644 --- a/server/reds.c +++ b/server/reds.c @@ -3482,7 +3482,7 @@ err: } static const char default_renderer[] = "sw"; -static const char default_video_codecs[] = "spice:mjpeg;gstreamer:mjpeg"; +static const char default_video_codecs[] = "spice:mjpeg;gstreamer:mjpeg;gstreamer:vp8"; /* new interface */ SPICE_GNUC_VISIBLE SpiceServer *spice_server_new(void) @@ -3567,11 +3567,13 @@ static new_video_encoder_t video_encoder_procs[] = { static const EnumNames video_codec_names[] = { {SPICE_VIDEO_CODEC_TYPE_MJPEG, "mjpeg"}, + {SPICE_VIDEO_CODEC_TYPE_VP8, "vp8"}, {0, NULL}, }; static int video_codec_caps[] = { SPICE_DISPLAY_CAP_CODEC_MJPEG, + SPICE_DISPLAY_CAP_CODEC_VP8, }; -- 2.8.0.rc3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel