GNOME Bugzilla – Bug 711271
soup: Add a SoupServer sink
Last modified: 2018-11-03 14:50:21 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
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.
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.
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):
+ Trace 232700
Thread 2 (Thread 0x7ffff7c49700 (LWP 16547))
Thread 1 (Thread 0x7ffff7ea6740 (LWP 16524))
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.
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.
(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.
I'll take a look through tcpserversink to see how it uses multisocketsink.
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).
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 ;)
(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.
Any progress here or further interest?
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?
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.
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..
Brendan, any news on this?
I've been incredibly busy so I don't know when I'll have time for this :(
-- 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.