Commit 5f33fa39 authored by Jakub Adam's avatar Jakub Adam
Browse files

Initial commit - HLS streaming of locally generated media

parents
project('multistream-server', 'c')
run_command('meson', 'subprojects', 'download', 'gst-build')
run_command('meson', 'wrap', 'promote', 'subprojects/gst-build/subprojects/gstreamer.wrap')
run_command('meson', 'wrap', 'promote', 'subprojects/gst-build/subprojects/gst-plugins-base.wrap')
run_command('meson', 'wrap', 'promote', 'subprojects/gst-build/subprojects/gst-plugins-good.wrap')
run_command('meson', 'wrap', 'promote', 'subprojects/gst-build/subprojects/gst-plugins-bad.wrap')
run_command('meson', 'wrap', 'promote', 'subprojects/gst-build/subprojects/gst-plugins-ugly.wrap')
subproject('gst-build')
soup_dep = dependency('libsoup-2.4')
gst_base_dep = subproject('gstreamer').get_variable('gst_base_dep')
subdir('src')
uninstalled = find_program('subprojects/gst-build/gst-uninstalled.py')
run_target('uninstalled', command : [uninstalled,
'--builddir=@0@'.format(meson.build_root()),
'--srcdir=@0@'.format(meson.source_root())])
#include "mss-http-server.h"
#include <glib-unix.h>
#include <gst/gst.h>
static gboolean
sigint_handler (gpointer user_data)
{
g_main_loop_quit (user_data);
return G_SOURCE_REMOVE;
}
int main (int argc, char *argv[])
{
GMainLoop *loop;
MssHttpServer *http_server;
gchar *pipeline_str;
GstElement *pipeline;
GError *error = NULL;
http_server = mss_http_server_new ();
pipeline_str = g_strdup_printf ("videotestsrc is-live=true ! x264enc ! "
"mpegtsmux ! hlssink location=%s/segment%%05d.ts "
"playlist-location=%s/playlist.m3u8",
mss_http_server_get_hls_dir (http_server),
mss_http_server_get_hls_dir (http_server));
gst_init (&argc, &argv);
pipeline = gst_parse_launch (pipeline_str, &error);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_assert_no_error (error);
g_free (pipeline_str);
loop = g_main_loop_new (NULL, FALSE);
g_unix_signal_add (SIGINT, sigint_handler, loop);
g_print ("Open http://localhost:8080 in a browser to watch HLS stream\n");
g_main_loop_run (loop);
g_main_loop_unref (loop);
gst_clear_object (&pipeline);
g_clear_object (&http_server);
}
subdir('resources')
sources = [
'mss-http-server.c',
'main.c',
gresources
]
executable('multistream-server', sources,
dependencies: [soup_dep, gst_base_dep],
install: true)
/*
* This file is a part of MultiStreamServer
*
* (C) 2019, Collabora Ltd
*/
#include "mss-http-server.h"
#include "gresource-multistream-server.h"
#include <glib/gstdio.h>
#include <libsoup/soup-message.h>
#include <libsoup/soup-server.h>
struct _MssHttpServer
{
GObject parent;
SoupServer *soup_server;
gchar *hls_dir;
};
G_DEFINE_TYPE (MssHttpServer, mss_http_server, G_TYPE_OBJECT)
MssHttpServer *
mss_http_server_new ()
{
return MSS_HTTP_SERVER (g_object_new (MSS_TYPE_HTTP_SERVER, NULL));
}
static void
http_cb (SoupServer *server, SoupMessage *msg, const char *path,
GHashTable *query, SoupClientContext *client, gpointer user_data)
{
GResource *res = multistream_server_get_resource();
GBytes *bytes;
if (g_str_equal (path, "/")) {
path = "/index.html";
}
bytes = g_resource_lookup_data(res, path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
if (bytes) {
SoupBuffer *buffer;
gconstpointer data;
gsize size;
data = g_bytes_get_data (bytes, &size);
buffer = soup_buffer_new_with_owner(data, size, bytes,
(GDestroyNotify) g_bytes_unref);
soup_message_body_append_buffer (msg->response_body, buffer);
soup_buffer_free (buffer);
soup_message_set_status (msg, SOUP_STATUS_OK);
} else {
soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
}
}
static void
hls_cb (SoupServer *server, SoupMessage *msg, const char *path,
GHashTable *query, SoupClientContext *client, gpointer user_data)
{
gchar *file_name;
gchar *file_path;
gchar *buf;
gsize buf_len;
GError *error = NULL;
MssHttpServer *self = MSS_HTTP_SERVER(user_data);
file_name = g_path_get_basename (path);
file_path = g_build_filename (self->hls_dir, file_name, NULL);
if (g_file_get_contents (file_path, &buf, &buf_len, &error)) {
SoupBuffer *buffer;
buffer = soup_buffer_new_take ((guchar *) buf, buf_len);
soup_message_body_append_buffer (msg->response_body, buffer);
soup_buffer_free (buffer);
if (g_str_has_suffix(path, ".m3u8")) {
soup_message_headers_append(msg->response_headers,
"Content-Type", "application/vnd.apple.mpegurl");
}
soup_message_set_status (msg, SOUP_STATUS_OK);
} else {
g_warning (error->message);
g_clear_error (&error);
soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
}
}
static void
mss_http_server_init (MssHttpServer *server)
{
GError *error = NULL;
server->soup_server = soup_server_new (NULL, NULL);
server->hls_dir = g_dir_make_tmp ("mss-hls-XXXXXX", &error);
g_assert_no_error (error);
soup_server_add_handler (server->soup_server, NULL, http_cb, server, NULL);
soup_server_add_handler (server->soup_server, "/hls/", hls_cb, server, NULL);
soup_server_listen_all (server->soup_server, 8080, 0, &error);
g_assert_no_error (error);
}
const gchar *
mss_http_server_get_hls_dir (MssHttpServer *server)
{
return server->hls_dir;
}
static void
mss_http_server_dispose (GObject *object)
{
MssHttpServer *self = MSS_HTTP_SERVER (object);
GDir *dir;
soup_server_disconnect (self->soup_server);
g_clear_object (&self->soup_server);
dir = g_dir_open (self->hls_dir, 0, NULL);
if (dir) {
const gchar *filename;
while ((filename = g_dir_read_name (dir))) {
gchar *path = g_build_filename (self->hls_dir, filename, NULL);
g_unlink (path);
g_free (path);
}
g_dir_close (dir);
g_rmdir (self->hls_dir);
}
g_clear_pointer (&self->hls_dir, g_free);
}
static void
mss_http_server_class_init (MssHttpServerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = mss_http_server_dispose;
}
/*
* This file is a part of MultiStreamServer
*
* (C) 2019, Collabora Ltd
*/
#ifndef __MSS_HTTP_SERVER_H__
#define __MSS_HTTP_SERVER_H__
#include <glib-object.h>
#define MSS_TYPE_HTTP_SERVER mss_http_server_get_type()
G_DECLARE_FINAL_TYPE (MssHttpServer, mss_http_server, MSS, HTTP_SERVER, GObject)
MssHttpServer *
mss_http_server_new ();
const gchar *
mss_http_server_get_hls_dir (MssHttpServer *server);
#endif /* __MSS_HTTP_SERVER_H__ */
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/hls.js"></script>
<center>
<video id="video" controls></video>
</center>
<script>
if(Hls.isSupported()) {
var video = document.getElementById('video');
var hls = new Hls();
hls.loadSource('hls/playlist.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
}
</script>
</body>
</html>
gnome = import('gnome')
gresources = gnome.compile_resources(
'gresource-multistream-server',
'multistream-server.gresources.xml'
)
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file>index.html</file>
</gresource>
</gresources>
[wrap-git]
directory=gst-build
url=https://gitlab.freedesktop.org/gstreamer/gst-build.git
revision=master
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment