By default GStreamer 1.0 is used if available, otherwise GStreamer 0.10 is used and Spice is compiled without GStreamer support only as a last resort. It's possible to explicitly require a specific Gstreamer version with configure --enable-gstreamer=1.0 and --enable-gstreamer=0.10; or for any version with --enable-gstreamer=yes; or to disable GStreamer support with --disable-gstreamer. Signed-off-by: Francois Gouget <fgouget@xxxxxxxxxxxxxxx> --- Changes since take 4: - Fixed setting the deadline vp8enc property (it's in microseconds, not nanoseconds). - Store the GStreamer 1.0 buffer format string in the SpiceFormatForGStreamer structure. configure.ac | 35 ++++++++++++++---- server/Makefile.am | 12 +++++-- server/gstreamer_encoder.c | 88 ++++++++++++++++++++++++++++++++++++++++------ server/red_dispatcher.c | 2 +- 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index d775bc1..39297ff 100644 --- a/configure.ac +++ b/configure.ac @@ -81,14 +81,32 @@ SPICE_CHECK_SMARTCARD([SMARTCARD]) AM_CONDITIONAL(SUPPORT_SMARTCARD, test "x$have_smartcard" = "xyes") AC_ARG_ENABLE(gstreamer, - AS_HELP_STRING([--enable-gstreamer=@<:@auto/yes/no@:>@], - [Enable GStreamer 0.10 support]), + AS_HELP_STRING([--enable-gstreamer=@<:@auto/0.10/1.0/yes/no@:>@], + [Enable GStreamer support]), [], [enable_gstreamer="auto"]) -if test "x$enable_gstreamer" != "xno"; then +if test "x$enable_gstreamer" != "xno" && test "x$enable_gstreamer" != "x0.10"; then + PKG_CHECK_MODULES(GSTREAMER_1_0, [gstreamer-1.0, gstreamer-app-1.0], + [enable_gstreamer="1.0" + have_gstreamer_1_0="yes"], + [have_gstreamer_1_0="no"]) + if test "x$have_gstreamer_1_0" = "xyes"; then + AC_SUBST(GSTREAMER_1_0_CFLAGS) + AC_SUBST(GSTREAMER_1_0_LIBS) + AS_VAR_APPEND([SPICE_REQUIRES], [" gstreamer-1.0 gstreamer-app-1.0"]) + AC_DEFINE([HAVE_GSTREAMER_1_0], [1], [Define if supporting GStreamer 1.0]) + elif test "x$enable_gstreamer" = "x1.0"; 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.]) + fi +else + have_gstreamer_1_0="no" +fi +AM_CONDITIONAL(SUPPORT_GSTREAMER_1_0, test "x$have_gstreamer_1_0" = "xyes") + +if test "x$enable_gstreamer" != "xno" && test "x$enable_gstreamer" != "x1.0"; then PKG_CHECK_MODULES(GSTREAMER_0_10, [gstreamer-0.10, gstreamer-app-0.10], - [enable_gstreamer="yes" + [enable_gstreamer="0.10" have_gstreamer_0_10="yes"], [have_gstreamer_0_10="no"]) if test "x$have_gstreamer_0_10" = "xyes"; then @@ -96,7 +114,7 @@ if test "x$enable_gstreamer" != "xno"; then AC_SUBST(GSTREAMER_0_10_LIBS) AS_VAR_APPEND([SPICE_REQUIRES], [" gstreamer-0.10 gstreamer-app-0.10"]) AC_DEFINE([HAVE_GSTREAMER_0_10], [1], [Define if supporting GStreamer 0.10]) - elif test "x$enable_gstreamer" = "xyes"; then + elif test "x$enable_gstreamer" = "x0.10"; then AC_MSG_ERROR([GStreamer 0.10 support requested but not found. You may set GSTREAMER_0_10_CFLAGS and GSTREAMER_0_10_LIBS to avoid the need to call pkg-config.]) fi else @@ -104,6 +122,11 @@ else fi AM_CONDITIONAL(SUPPORT_GSTREAMER_0_10, test "x$have_gstreamer_0_10" = "xyes") +if test "x$enable_gstreamer" = "xyes"; then + AC_MSG_ERROR("GStreamer support requested but not found") +fi +AS_IF([test "x$enable_gstreamer" = "xauto"], [enable_gstreamer="no"]) + AC_ARG_ENABLE([automated_tests], AS_HELP_STRING([--enable-automated-tests], [Enable automated tests using spicy-screenshot (part of spice--gtk)]),, [enable_automated_tests="no"]) @@ -343,7 +366,7 @@ echo " Smartcard: ${have_smartcard} - GStreamer 0.10: ${have_gstreamer_0_10} + GStreamer: ${enable_gstreamer} SASL support: ${enable_sasl} diff --git a/server/Makefile.am b/server/Makefile.am index 9dad6f6..091e94d 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -12,6 +12,7 @@ AM_CPPFLAGS = \ $(SLIRP_CFLAGS) \ $(SMARTCARD_CFLAGS) \ $(GSTREAMER_0_10_CFLAGS) \ + $(GSTREAMER_1_0_CFLAGS) \ $(SPICE_PROTOCOL_CFLAGS) \ $(SSL_CFLAGS) \ $(VISIBILITY_HIDDEN_CFLAGS) \ @@ -43,7 +44,8 @@ libspice_server_la_LIBADD = \ $(PIXMAN_LIBS) \ $(SASL_LIBS) \ $(SLIRP_LIBS) \ - $(GSTREAMER_0_10_LIBS) \ + $(GSTREAMER_0_10_LIBS) \ + $(GSTREAMER_1_0_LIBS) \ $(SSL_LIBS) \ $(Z_LIBS) \ $(SPICE_NONPKGCONFIG_LIBS) \ @@ -146,7 +148,13 @@ endif if SUPPORT_GSTREAMER_0_10 libspice_server_la_SOURCES += \ - gstreamer_encoder.c \ + gstreamer_encoder.c \ + $(NULL) +endif + +if SUPPORT_GSTREAMER_1_0 +libspice_server_la_SOURCES += \ + gstreamer_encoder.c \ $(NULL) endif diff --git a/server/gstreamer_encoder.c b/server/gstreamer_encoder.c index 425be55..f20d0f8 100644 --- a/server/gstreamer_encoder.c +++ b/server/gstreamer_encoder.c @@ -38,6 +38,7 @@ typedef struct GstEncoder GstEncoder; typedef struct { SpiceBitmapFmt spice_format; + const char *format; uint32_t bpp; uint32_t depth; uint32_t endianness; @@ -49,6 +50,9 @@ typedef struct { struct GstVideoBuffer { VideoBuffer base; GstBuffer *gst_buffer; +#ifndef HAVE_GSTREAMER_0_10 + GstMapInfo map_info; +#endif gboolean persistent; }; @@ -108,6 +112,9 @@ static inline GstVideoBuffer* gst_video_buffer_ref(GstVideoBuffer *buffer) static void gst_video_buffer_unref(GstVideoBuffer *buffer) { if (--buffer->base.ref_count == 0) { +#ifndef HAVE_GSTREAMER_0_10 + gst_buffer_unmap(buffer->gst_buffer, &buffer->map_info); +#endif gst_buffer_unref(buffer->gst_buffer); if (!buffer->persistent) { free(buffer); @@ -191,13 +198,15 @@ static void adjust_bit_rate(GstEncoder *encoder) /* A helper for gst_encoder_encode_frame(). */ static SpiceFormatForGStreamer *map_format(SpiceBitmapFmt format) { - /* See GStreamer's section-types-definitions.html document */ + /* See GStreamer's part-mediatype-video-raw.txt and + * section-types-definitions.html documents. + */ static SpiceFormatForGStreamer format_map[] = { - {SPICE_BITMAP_FMT_RGBA, 32, 24, 4321, 0xff000000, 0xff0000, 0xff00}, + {SPICE_BITMAP_FMT_RGBA, "BGRA", 32, 24, 4321, 0xff000000, 0xff0000, 0xff00}, /* TODO: Test the other formats */ - {SPICE_BITMAP_FMT_32BIT, 32, 24, 4321, 0xff000000, 0xff0000, 0xff00}, - {SPICE_BITMAP_FMT_24BIT, 24, 24, 4321, 0xff0000, 0xff00, 0xff}, - {SPICE_BITMAP_FMT_16BIT, 16, 15, 4321, 0x001f, 0x03E0, 0x7C00}, + {SPICE_BITMAP_FMT_32BIT, "BGRx", 32, 24, 4321, 0xff000000, 0xff0000, 0xff00}, + {SPICE_BITMAP_FMT_24BIT, "BGR", 24, 24, 4321, 0xff0000, 0xff00, 0xff}, + {SPICE_BITMAP_FMT_16BIT, "BGR15", 16, 15, 4321, 0x001f, 0x03E0, 0x7C00}, }; int i; @@ -242,7 +251,11 @@ static gboolean construct_pipeline(GstEncoder *encoder, const SpiceBitmap *bitma switch (encoder->base.codec_type) { case SPICE_VIDEO_CODEC_TYPE_MJPEG: +#ifdef HAVE_GSTREAMER_0_10 gstenc_name = "ffenc_mjpeg"; +#else + gstenc_name = "avenc_mjpeg"; +#endif break; case SPICE_VIDEO_CODEC_TYPE_VP8: gstenc_name = "vp8enc"; @@ -251,9 +264,14 @@ static gboolean construct_pipeline(GstEncoder *encoder, const SpiceBitmap *bitma spice_warning("unsupported codec type %d", encoder->base.codec_type); return FALSE; } +#ifdef HAVE_GSTREAMER_0_10 + const gchar *converter = "ffmpegcolorspace"; +#else + const gchar *converter = "videoconvert"; +#endif GError *err = NULL; - gchar *desc = g_strdup_printf("appsrc name=src format=2 do-timestamp=true ! ffmpegcolorspace ! %s name=encoder ! appsink name=sink", gstenc_name); + gchar *desc = g_strdup_printf("appsrc name=src format=2 do-timestamp=true ! %s ! %s name=encoder ! appsink name=sink", converter, gstenc_name); spice_debug("GStreamer pipeline: %s", desc); encoder->pipeline = gst_parse_launch_full(desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &err); g_free(desc); @@ -272,8 +290,13 @@ static gboolean construct_pipeline(GstEncoder *encoder, const SpiceBitmap *bitma /* Configure the encoders for a zero-frame latency, and real-time speed */ adjust_bit_rate(encoder); - g_object_set(G_OBJECT(encoder->gstenc), "bitrate", encoder->bit_rate, NULL); - if (encoder->base.codec_type == SPICE_VIDEO_CODEC_TYPE_VP8) { + switch (encoder->base.codec_type) { + case SPICE_VIDEO_CODEC_TYPE_MJPEG: + g_object_set(G_OBJECT(encoder->gstenc), + "bitrate", encoder->bit_rate, + NULL); + break; + case SPICE_VIDEO_CODEC_TYPE_VP8: { /* See http://www.webmproject.org/docs/encoder-parameters/ */ #ifdef HAVE_G_GET_NUMPROCESSORS int core_count = g_get_num_processors(); @@ -282,13 +305,28 @@ static gboolean construct_pipeline(GstEncoder *encoder, const SpiceBitmap *bitma #endif g_object_set(G_OBJECT(encoder->gstenc), "resize-allowed", TRUE, /* for very low bit rates */ +#ifdef HAVE_GSTREAMER_0_10 "mode", 1, /* CBR */ + "bitrate", encoder->bit_rate, "max-latency", 0, /* zero-frame latency */ "error-resilient", TRUE, /* for client frame drops */ "speed", 7, /* ultrafast */ +#else + "end-usage", 1, /* CBR */ + "target-bitrate", encoder->bit_rate, + "lag-in-frames", 0, /* zero-frame latency */ + "error-resilient", 1, /* for client frame drops */ + "deadline", 1000000 / get_source_fps(encoder) / 2, /* usec */ +#endif "threads", core_count - 1, NULL); - } + break; + } + default: + spice_warning("unknown encoder type %d", encoder->base.codec_type); + reset_pipeline(encoder); + return FALSE; + } /* Set the source caps */ set_appsrc_caps(encoder); @@ -368,7 +406,14 @@ static int push_raw_frame(GstEncoder *encoder, const SpiceBitmap *bitmap, const uint32_t stream_stride = (src->right - src->left) * encoder->format->bpp / 8; uint32_t len = stream_stride * height; GstBuffer *buffer = gst_buffer_new_and_alloc(len); - uint8_t *dst = GST_BUFFER_DATA(buffer); +#ifdef HAVE_GSTREAMER_0_10 + uint8_t *b = GST_BUFFER_DATA(buffer); +#else + GstMapInfo map; + gst_buffer_map(buffer, &map, GST_MAP_WRITE); + uint8_t *b = map.data; +#endif + uint8_t *dst = b; /* Note that we should not reorder the lines, even if top_down is false. * It just changes the number of lines to skip at the start of the bitmap. @@ -412,8 +457,11 @@ static int push_raw_frame(GstEncoder *encoder, const SpiceBitmap *bitmap, } spice_assert(len == 0); } - +#ifdef HAVE_GSTREAMER_0_10 gst_buffer_set_caps(buffer, encoder->src_caps); +#else + gst_buffer_unmap(buffer, &map); +#endif GST_BUFFER_OFFSET(buffer) = encoder->frame++; GstFlowReturn ret = gst_app_src_push_buffer(encoder->appsrc, buffer); @@ -436,6 +484,7 @@ static int pull_compressed_buffer(GstEncoder *encoder, GstVideoBuffer **buffer) } else { video_buffer = create_gst_video_buffer(FALSE); } +#ifdef HAVE_GSTREAMER_0_10 video_buffer->gst_buffer = gst_app_sink_pull_buffer(encoder->appsink); if (video_buffer->gst_buffer) { video_buffer->base.data = GST_BUFFER_DATA(video_buffer->gst_buffer); @@ -444,6 +493,23 @@ static int pull_compressed_buffer(GstEncoder *encoder, GstVideoBuffer **buffer) return VIDEO_ENCODER_FRAME_ENCODE_DONE; } video_buffer->base.unref(video_buffer); +#else + GstSample *sample = gst_app_sink_pull_sample(encoder->appsink); + if (sample) { + video_buffer->gst_buffer = gst_sample_get_buffer(sample); + if (video_buffer->gst_buffer) { + gst_buffer_ref(video_buffer->gst_buffer); + video_buffer->base.size = gst_buffer_get_size(video_buffer->gst_buffer); + gst_buffer_map(video_buffer->gst_buffer, &video_buffer->map_info, + GST_MAP_READ); + video_buffer->base.data = video_buffer->map_info.data; + *buffer = video_buffer; + gst_sample_unref(sample); + return VIDEO_ENCODER_FRAME_ENCODE_DONE; + } + gst_sample_unref(sample); + } +#endif return VIDEO_ENCODER_FRAME_UNSUPPORTED; } diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c index acceb53..105bdd3 100644 --- a/server/red_dispatcher.c +++ b/server/red_dispatcher.c @@ -258,7 +258,7 @@ static const EnumNames video_encoder_names[] = { static create_video_encoder_proc video_encoder_procs[] = { &create_mjpeg_encoder, -#ifdef HAVE_GSTREAMER_0_10 +#if defined(HAVE_GSTREAMER_0_10) || defined(HAVE_GSTREAMER_1_0) &create_gstreamer_encoder, #else NULL, -- 2.5.0 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel