After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 711271 - soup: Add a SoupServer sink
soup: Add a SoupServer sink
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gst-plugins-good
git master
Other All
: Normal enhancement
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2013-11-01 18:53 UTC by Brendan Long
Modified: 2018-11-03 14:50 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Patch to add gstsouphttpserversrc (13.57 KB, patch)
2013-11-01 18:53 UTC, Brendan Long
none Details | Review
Patch to add gstsouphttpserversrc (14.14 KB, patch)
2013-11-01 22:43 UTC, Brendan Long
needs-work Details | Review

Description Brendan Long 2013-11-01 18:53:41 UTC
Created attachment 258778 [details] [review]
Patch to add gstsouphttpserversrc

I'm trying to test some things in WebKit with live sources, and there doesn't seem to be any simple way to create a stream, so I made this.

It's currently *very* basic. I can think of plenty of new properties that would be useful (passing a SoupServer, GMainLoop, GMainContext, mime type, etc.), and useful features (detecting mime types), but I figured the basic version was a good first step, and then new features can be built on top of that.

I wasn't able to get this working with Ogg or WebM, but MPEG-TS works:

    gst-launch-1.0 videotestsrc ! x264enc ! mpegtsmux ! souphttpserversink port=8080

    gst-launch-1.0 playbin uri=http://localhost:8080
Comment 1 Brendan Long 2013-11-01 19:17:46 UTC
Hm I found an issue where if I try to shutdown the server while a client is connected, it fails to shutdown, and then even after shutting down the client, I have to do a kill -9 to stop the server. I'll try to fix that and then update the patch. I suspect I need to do something in the _stop function.
Comment 2 Brendan Long 2013-11-01 22:43:17 UTC
Created attachment 258790 [details] [review]
Patch to add gstsouphttpserversrc

The lock in `gst_soup_http_server_message_finished` was causing a deadlock (since _stop was holding the same lock). I handled it by just removing the signal handler in _stop, since we're about to clear the whole set anyway. I'm guessing a cleaner way to handle this is with callbacks and not doing anything on the main thread, but everything seems to work now.
Comment 3 Brendan Long 2013-11-01 22:57:00 UTC
I occasionally get errors about:

(gst-launch-1.0:16303): GLib-GIO-CRITICAL **: g_output_stream_write: assertion `buffer != NULL' failed

But the backtrace isn't very helpful (I removed x264 threadpool threads for clarity):

Thread 2 (Thread 0x7ffff7c49700 (LWP 16547))

  • #0 video_chroma_down_h2_guint8
    at video-chroma.c line 320
  • #1 video_chroma_down_v2_guint8
    at video-chroma.c line 322
  • #2 gst_video_chroma_resample
    at video-chroma.c line 817
  • #3 convert_hline_generic
    at videotestsrc.c line 1195
  • #4 videotestsrc_convert_tmpline
    at videotestsrc.c line 275
  • #5 gst_video_test_src_smpte
    at videotestsrc.c line 352
  • #6 gst_video_test_src_fill
    at gstvideotestsrc.c line 877
  • #7 gst_push_src_fill
    at gstpushsrc.c line 169
  • #8 gst_base_src_default_create
    at gstbasesrc.c line 1439
  • #9 gst_push_src_create
    at gstpushsrc.c line 134
  • #10 gst_base_src_get_range
    at gstbasesrc.c line 2392
  • #11 gst_base_src_loop
    at gstbasesrc.c line 2665
  • #12 gst_task_func
    at gsttask.c line 316
  • #13 default_func
    at gsttaskpool.c line 70
  • #14 g_thread_pool_thread_proxy
    at gthreadpool.c line 309
  • #15 g_thread_proxy
    at gthread.c line 798
  • #16 start_thread
    at pthread_create.c line 308
  • #17 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 113

Thread 1 (Thread 0x7ffff7ea6740 (LWP 16524))

  • #0 g_logv
    at gmessages.c line 981
  • #1 g_log
    at gmessages.c line 1010
  • #2 g_return_if_fail_warning
    at gmessages.c line 1019
  • #3 g_output_stream_write
    at goutputstream.c line 195
  • #4 soup_body_output_stream_write_chunked
    at soup-body-output-stream.c line 175
  • #5 soup_body_output_stream_close_fn
    at soup-body-output-stream.c line 235
  • #6 _g_output_stream_close_internal
    at goutputstream.c line 555
  • #7 g_output_stream_close
    at goutputstream.c line 626
  • #8 g_output_stream_dispose
    at goutputstream.c line 116
  • #9 g_filter_output_stream_dispose
    at gfilteroutputstream.c line 180
  • #10 g_object_unref
    at gobject.c line 2987
  • #11 soup_message_io_cleanup
    at soup-message-io.c line 112
  • #12 soup_message_io_finished
    at soup-message-io.c line 163
  • #13 io_run
    at soup-message-io.c line 939
  • #14 g_main_dispatch
    at gmain.c line 3054
  • #15 g_main_context_dispatch
    at gmain.c line 3630
  • #16 g_main_context_iterate
    at gmain.c line 3701
  • #17 g_main_loop_run
    at gmain.c line 3895
  • #18 gst_bus_poll
    at gstbus.c line 1082
  • #19 event_loop
    at gst-launch.c line 507
  • #20 main
    at gst-launch.c line 1081

Comment 4 Olivier Crête 2013-12-06 02:15:38 UTC
Review of attachment 258790 [details] [review]:

Thanks for you contribution, there are a couple things that need improving before we can merge it. The biggest is the use of the default GMainContext.

::: ext/soup/gstsouphttpserversink.c
@@ +66,3 @@
+{
+  PROP_0,
+  PROP_PATH,

The matching g_object_class_install_property() is missing

@@ +122,3 @@
+gst_soup_http_server_sink_init (GstSoupHttpServerSink * souphttpsink)
+{
+  g_mutex_init (&souphttpsink->mutex);

Why not use the GST_OBJECT_LOCK() ?

@@ +199,3 @@
+  soup_server_add_handler (souphttpsink->server, souphttpsink->path,
+      gst_soup_http_server_new_message, souphttpsink, NULL);
+  soup_server_run_async (souphttpsink->server);

This will make libsoup use the default GMainContext/GMainLoop, sadly GStreamer must work without one running. So you need to create a GMainContext and then in a thread run your own GMainLoop there. Look at how souphttpclientsink does it.

@@ +246,3 @@
+  gpointer key, value;
+
+  if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {

You may want to iterate over each GstMemory inside the buffer to avoid doing copies if there are multiple non-contiguous memories.

@@ +261,3 @@
+    SoupMessage *msg = SOUP_MESSAGE (key);
+    soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, info.data,
+        info.size);

It would be nice to use soup_buffer_new_with_owner() to avoid making a copy.

@@ +280,3 @@
+
+  soup_message_headers_set_content_type (msg->response_headers, "text/plain",
+      NULL);

Why text/plain? Is it possible to just not put the header? Worst cast, application/octet-stream unless the caps are really plaintext.
Comment 5 Tim-Philipp Müller 2013-12-06 11:33:29 UTC
I'm not sure if this should be merged in this form.

I think maybe it should be based on top of multifdsink or multisocketsink, so that multiple clients can connect, and get sent stream headers and all those things.

Then the question is how to accommodate multiple paths/streams on the same server. This doesn't have to be implemented right away, but we should have a plan how to do it later, because it affects the design.

One could have one (or more) common server objects shared amongst all the sink instances. The path could then be a property on the sink, and the sink would hook into an existing server or create one if one doesn't exist yet. In this scenario one could build on top of multisocketsink.

Alternatively, one could make a bin with multiple request pads, and each request pad stands for a path served by the server.
Comment 6 Brendan Long 2013-12-08 11:27:48 UTC
(In reply to comment #5)
> One could have one (or more) common server objects shared amongst all the sink
> instances. The path could then be a property on the sink, and the sink would
> hook into an existing server or create one if one doesn't exist yet. In this
> scenario one could build on top of multisocketsink.

That makes sense to me. I was thinking of having a "server" property where you could pass in an existing server. Combined with the "path" property, that should give us what we want. If we did that, we'd probably want to either remove the "path" property, or make it not work if the "server" is also set.

> Alternatively, one could make a bin with multiple request pads, and each
> request pad stands for a path served by the server.

The downside to this is that other elements may expect sinks to have a single static sink pad.
Comment 7 Brendan Long 2013-12-08 11:32:29 UTC
I'll take a look through tcpserversink to see how it uses multisocketsink.
Comment 8 Tim-Philipp Müller 2013-12-08 13:51:24 UTC
For each client connection you would basically do the http handshake, and once that's done you just hand off the socket to multisocketsink, which will send the stream headers (headers, possibly some data from the last keyframe) and then send whatever comes in. That's the idea anyway.

What this setup doesn't allow for is seeking from the client, but I think that's a less interesting use case generally, since it would only work if there's was just a single client (since you can't recreate the pipeline for a second one; there's a reason the rtsp-server is proper API).
Comment 9 Sebastian Dröge (slomo) 2013-12-08 16:13:15 UTC
Brendan, see my example here http://coaxion.net/blog/2013/10/streaming-gstreamer-pipelines-via-http/

That basically does what you want to do without libsoup and as a simple application instead of an element ;)
Comment 10 Brendan Long 2013-12-08 16:37:52 UTC
(In reply to comment #9)
> Brendan, see my example here
> http://coaxion.net/blog/2013/10/streaming-gstreamer-pipelines-via-http/
> 
> That basically does what you want to do without libsoup and as a simple
> application instead of an element ;)

Thanks, that'll be useful.
Comment 11 Sebastian Dröge (slomo) 2014-01-14 19:25:26 UTC
Any progress here or further interest?
Comment 12 Brendan Long 2014-01-14 20:22:57 UTC
Sorry, I've had a lot of other things going on. I'm not sure if this is worth finishing, since you already have an application that does the same thing. Do you think it's worth having an element for this?
Comment 13 Sebastian Dröge (slomo) 2014-01-14 20:24:35 UTC
Yes, I think so. Same goes for an rtspsink on top of gst-rtsp-server. It's more convenient to use for simple use cases and people requested it quite often.
Comment 14 Brendan Long 2014-01-14 21:57:56 UTC
Ok, I'll make a note to spend some time cleaning this up (by which I mean completely rewriting it to use multisocketsink). I'll try to work on it next week or next weekend..
Comment 15 Sebastian Dröge (slomo) 2015-11-07 14:18:16 UTC
Brendan, any news on this?
Comment 16 Brendan Long 2015-11-09 18:27:16 UTC
I've been incredibly busy so I don't know when I'll have time for this :(
Comment 17 GStreamer system administrator 2018-11-03 14:50:21 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/97.