diff --git a/src/cc/cc-media-factory.c b/src/cc/cc-media-factory.c index 6f707cdcdb451654685945575d57709b44180ab6..c2235c8f1c0138a0ec3d37a5ebbd3954f8e012bb 100644 --- a/src/cc/cc-media-factory.c +++ b/src/cc/cc-media-factory.c @@ -49,7 +49,7 @@ cc_media_factory_create_video_element (CcMediaFactory *self) g_autoptr(GstElement) source = NULL; GstElement *scale; - GstElement *sizefilter; + GstElement *sinkfilter; GstElement *convert; GstElement *queue_pre_encoder; GstElement *encoder; @@ -83,9 +83,9 @@ cc_media_factory_create_video_element (CcMediaFactory *self) "width", G_TYPE_INT, 1920, "height", G_TYPE_INT, 1080, NULL); - sizefilter = gst_element_factory_make ("capsfilter", "cc-sizefilter"); - success &= gst_bin_add (bin, sizefilter); - g_object_set (sizefilter, + sinkfilter = gst_element_factory_make ("capsfilter", "cc-sinkfilter"); + success &= gst_bin_add (bin, sinkfilter); + g_object_set (sinkfilter, "caps", caps, NULL); g_clear_pointer (&caps, gst_caps_unref); @@ -184,7 +184,7 @@ cc_media_factory_create_video_element (CcMediaFactory *self) success &= gst_element_link_many (source, scale, - sizefilter, + sinkfilter, convert, queue_pre_encoder, encoder, diff --git a/src/nd-sink.h b/src/nd-sink.h index d42ddad12bd0772addbb3421980b2a181d2867ce..96458338ccba1e5c38f5432f49b2fce3b37193f0 100644 --- a/src/nd-sink.h +++ b/src/nd-sink.h @@ -42,6 +42,12 @@ typedef enum { ND_SINK_STATE_ERROR = 0x10000, } NdSinkState; +typedef enum { + ND_SCREEN_CAST_SOURCE_TYPE_MONITOR = 1, + ND_SCREEN_CAST_SOURCE_TYPE_WINDOW = 2, + ND_SCREEN_CAST_SOURCE_TYPE_VIRTUAL = 4, +} NdScreenCastSourceType; + struct _NdSinkIface { /*< private >*/ diff --git a/src/nd-window.c b/src/nd-window.c index 5ebff2f6e225051bd4537302161e1fefa9350bc4..046c55cde2d1c211b8fe1b6ae00ed8125bd56499 100644 --- a/src/nd-window.c +++ b/src/nd-window.c @@ -36,23 +36,24 @@ struct _NdWindow { - AdwApplicationWindow parent_instance; + AdwApplicationWindow parent_instance; - GaClient *avahi_client; - NdMetaProvider *meta_provider; - NdNMDeviceRegistry *nm_device_registry; + GaClient *avahi_client; + NdMetaProvider *meta_provider; + NdNMDeviceRegistry *nm_device_registry; - XdpPortal *portal; - XdpSession *session; - gboolean use_x11; + XdpPortal *portal; + XdpSession *session; + NdScreenCastSourceType screencast_type; + gboolean use_x11; - NdPulseaudio *pulse; + NdPulseaudio *pulse; - GCancellable *cancellable; + GCancellable *cancellable; - NdSink *stream_sink; + NdSink *stream_sink; - GPtrArray *sink_property_bindings; + GPtrArray *sink_property_bindings; /* Template widgets */ GtkStack *has_providers_stack; @@ -87,31 +88,40 @@ G_DEFINE_TYPE (NdWindow, gnome_nd_window, ADW_TYPE_APPLICATION_WINDOW) static GstElement * nd_window_screencast_get_source (NdWindow * self) { - g_autoptr(GstElement) src = NULL; + g_autoptr(GVariant) stream_properties = NULL; + g_autoptr(GError) error = NULL; + GstElement *src = NULL; GVariant *streams = NULL; - const gchar *stream_type; - gsize stream_count; + GVariantIter iter; guint32 node_id; - - src = gst_element_factory_make ("pipewiresrc", "portal-pipewire-source"); - if (src == NULL) - g_error ("GStreamer element \"pipewiresrc\" could not be created!"); + guint32 screencast_type; streams = xdp_session_get_streams (self->session); if (streams == NULL) g_error ("XDP session streams not found!"); - stream_type = g_variant_get_type_string (streams); - if (0 != strcmp (stream_type, "a(ua{sv})")) - g_error ("Unexpected XDP session type '%s'", stream_type); + g_variant_iter_init (&iter, streams); + g_variant_iter_loop (&iter, "(u@a{sv})", &node_id, &stream_properties); + g_variant_lookup (stream_properties, "source_type", "u", &screencast_type); - stream_count = g_variant_n_children (streams); - if (stream_count == 0) - g_error ("Did not find any usable streams!"); + g_debug ("Got a stream with node ID: %d", node_id); + g_debug ("Got a stream of type: %d", screencast_type); - g_variant_get_child (streams, 0, "(ua{sv})", &node_id, NULL); + switch (screencast_type) + { + case ND_SCREEN_CAST_SOURCE_TYPE_MONITOR: + case ND_SCREEN_CAST_SOURCE_TYPE_WINDOW: + case ND_SCREEN_CAST_SOURCE_TYPE_VIRTUAL: + self->screencast_type = screencast_type; + break; - g_debug ("Got a stream with node ID: %d", node_id); + default: + g_assert_not_reached (); + } + + src = gst_element_factory_make ("pipewiresrc", "portal-pipewire-source"); + if (src == NULL) + g_error ("GStreamer element \"pipewiresrc\" could not be created!"); g_object_set (src, "fd", xdp_session_open_pipewire_remote (self->session), @@ -127,8 +137,9 @@ nd_window_screencast_get_source (NdWindow * self) static GstElement * sink_create_source_cb (NdWindow * self, NdSink * sink) { + g_autoptr(GstCaps) caps = NULL; GstBin *bin; - GstElement *src, *dst, *res; + GstElement *src, *filter, *dst, *res; bin = GST_BIN (gst_bin_new ("screencast source bin")); g_debug ("use x11: %d", self->use_x11); @@ -152,7 +163,25 @@ sink_create_source_cb (NdWindow * self, NdSink * sink) NULL); gst_bin_add (bin, dst); - gst_element_link_many (src, dst, NULL); + if (self->screencast_type == ND_SCREEN_CAST_SOURCE_TYPE_VIRTUAL) + { + /* Initial caps for virtual display */ + caps = gst_caps_new_simple ("video/x-raw", + "max-framerate", GST_TYPE_FRACTION, 30, 1, + "width", G_TYPE_INT, 1920, + "height", G_TYPE_INT, 1080, + NULL); + filter = gst_element_factory_make ("capsfilter", "srcfilter"); + gst_bin_add (bin, filter); + g_object_set (filter, + "caps", caps, + NULL); + g_clear_pointer (&caps, gst_caps_unref); + + gst_element_link_many (src, filter, dst, NULL); + } + else + gst_element_link_many (src, dst, NULL); res = gst_element_factory_make ("intervideosrc", "screencastsrc"); g_object_set (res, diff --git a/src/wfd/wfd-media-factory.c b/src/wfd/wfd-media-factory.c index c12461e96c1d0820866b4c0d3354bb0c736f5f8f..6f773d91ad1fc30bbe5fbb4efae5281cc9093461 100644 --- a/src/wfd/wfd-media-factory.c +++ b/src/wfd/wfd-media-factory.c @@ -127,7 +127,7 @@ wfd_media_factory_create_video_element (WfdMediaFactory *self, GstBin *bin) QOSData *qos_data; GstElement *scale; - GstElement *sizefilter; + GstElement *sinkfilter; GstElement *convert; GstElement *queue_pre_encoder; GstElement *encoder; @@ -155,9 +155,9 @@ wfd_media_factory_create_video_element (WfdMediaFactory *self, GstBin *bin) "width", G_TYPE_INT, 1920, "height", G_TYPE_INT, 1080, NULL); - sizefilter = gst_element_factory_make ("capsfilter", "wfd-sizefilter"); - success &= gst_bin_add (bin, sizefilter); - g_object_set (sizefilter, + sinkfilter = gst_element_factory_make ("capsfilter", "wfd-sinkfilter"); + success &= gst_bin_add (bin, sinkfilter); + g_object_set (sinkfilter, "caps", caps, NULL); g_clear_pointer (&caps, gst_caps_unref); @@ -312,7 +312,7 @@ wfd_media_factory_create_video_element (WfdMediaFactory *self, GstBin *bin) success &= gst_element_link_many (source, scale, - sizefilter, + sinkfilter, convert, queue_pre_encoder, encoder, @@ -434,7 +434,7 @@ wfd_media_factory_create_element (GstRTSPMediaFactory *factory, const GstRTSPUrl GstElement *payloader; gboolean success = TRUE; - bin = GST_BIN (gst_bin_new ("wfd-encoder-bin")); + bin = GST_BIN (gst_bin_new ("nd-wfd-pipeline")); queue_mpegmux_video = wfd_media_factory_create_video_element (self, bin); @@ -484,7 +484,7 @@ wfd_media_factory_create_element (GstRTSPMediaFactory *factory, const GstRTSPUrl GST_DEBUG_BIN_TO_DOT_FILE (bin, GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE, - "wfd-encoder-bin"); + "nd-wfd-pipeline"); if (!success) { g_error ("WfdMediaFactory: Error creating encoding pipeline. If gstreamer is compiled with debugging and GST_DEBUG_DUMP_DOT_DIR is set, then the pipeline will have been dumped."); @@ -512,9 +512,9 @@ wfd_media_factory_create_pipeline (GstRTSPMediaFactory *factory, GstRTSPMedia *m WfdMediaQuirks wfd_configure_media_element (GstBin *bin, WfdParams *params) { - g_autoptr(GstCaps) caps_sizefilter = NULL; - g_autoptr(GstElement) sizefilter = NULL; - g_autoptr(GstCaps) caps_codecfilter = NULL; + g_autoptr(GstCaps) caps = NULL; + g_autoptr(GstElement) srcfilter = NULL; + g_autoptr(GstElement) sinkfilter = NULL; g_autoptr(GstElement) codecfilter = NULL; g_autoptr(GstElement) encoder = NULL; g_autoptr(GstElement) audio_pipeline = NULL; @@ -547,16 +547,32 @@ wfd_configure_media_element (GstBin *bin, WfdParams *params) if (params->idr_request_capability && !(quirks & WFD_QUIRK_NO_IDR)) gop_size = 10 * resolution->refresh_rate; - caps_sizefilter = gst_caps_new_simple ("video/x-raw", - "framerate", GST_TYPE_FRACTION, resolution->refresh_rate, 1, - "width", G_TYPE_INT, resolution->width, - "height", G_TYPE_INT, resolution->height, - NULL); + srcfilter = gst_bin_get_by_name (bin, "srcfilter"); + if (srcfilter != NULL) + { + caps = gst_caps_new_simple ("video/x-raw", + "max-framerate", GST_TYPE_FRACTION, resolution->refresh_rate, 1, + "width", G_TYPE_INT, resolution->width, + "height", G_TYPE_INT, resolution->height, + NULL); + + g_object_set (srcfilter, + "caps", caps, + NULL); + g_clear_pointer (&caps, gst_caps_unref); + } + + caps = gst_caps_new_simple ("video/x-raw", + "framerate", GST_TYPE_FRACTION, resolution->refresh_rate, 1, + "width", G_TYPE_INT, resolution->width, + "height", G_TYPE_INT, resolution->height, + NULL); - sizefilter = gst_bin_get_by_name (bin, "wfd-sizefilter"); - g_object_set (sizefilter, - "caps", caps_sizefilter, + sinkfilter = gst_bin_get_by_name (bin, "wfd-sinkfilter"); + g_object_set (sinkfilter, + "caps", caps, NULL); + g_clear_pointer (&caps, gst_caps_unref); switch (encoder_impl) { @@ -636,20 +652,20 @@ wfd_configure_media_element (GstBin *bin, WfdParams *params) } if (profile == WFD_H264_PROFILE_HIGH) - caps_codecfilter = gst_caps_from_string ("video/x-h264,stream-format=byte-stream,profile=high"); + caps = gst_caps_from_string ("video/x-h264,stream-format=byte-stream,profile=high"); else { /* Permit both constrained-baseline and baseline. Would constrained-baseline be sufficient? */ - caps_codecfilter = gst_caps_from_string ("video/x-h264,stream-format=byte-stream,profile=constrained-baseline"); - gst_caps_append (caps_codecfilter, + caps = gst_caps_from_string ("video/x-h264,stream-format=byte-stream,profile=constrained-baseline"); + gst_caps_append (caps, gst_caps_from_string ("video/x-h264,stream-format=byte-stream,profile=baseline")); } codecfilter = gst_bin_get_by_name (bin, "wfd-codecfilter"); g_object_set (codecfilter, - "caps", caps_codecfilter, + "caps", caps, NULL); - + g_clear_pointer (&caps, gst_caps_unref); g_debug ("An audiocodec has been selected: %s", params->selected_audio_codec ? "yes" : "no"); audio_pipeline = gst_bin_get_by_name (bin, "wfd-audio"); @@ -678,7 +694,7 @@ wfd_configure_media_element (GstBin *bin, WfdParams *params) GST_DEBUG_BIN_TO_DOT_FILE (bin, GST_DEBUG_GRAPH_SHOW_ALL, - "wfd-encoder-bin-configured"); + "nd-wfd-pipeline-configured"); return quirks; }