diff options
author | Christian Pointner <equinox@spreadspace.org> | 2014-09-03 23:09:49 +0200 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2014-09-03 23:09:49 +0200 |
commit | a7c3a5c479812f1f69acac276402fdffc60371aa (patch) | |
tree | 39bb07552103848862935d8e5c5df20f7135c3f0 /src/sydra.c |
added initial code - based on rharchive
Diffstat (limited to 'src/sydra.c')
-rw-r--r-- | src/sydra.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/sydra.c b/src/sydra.c new file mode 100644 index 0000000..bded404 --- /dev/null +++ b/src/sydra.c @@ -0,0 +1,255 @@ +/* + * sydra + * + * sydra is a toolbox which allows you to set up multiple bidirectional + * Video/Audio streams from external locations. + * sydra has been written to be used for the Elevate Festival in Graz + * Austria in order to involve external locations to present themselves + * at the festival. + * Sydra is based on GStreamer and is written in C. + * + * + * Copyright (C) 2014 Christian Pointner <equinox@helsinki.at> + * + * This file is part of sydra. + * + * sydra is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * sydra is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with sydra. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/select.h> + +#include <gst/gst.h> + +#include "datatypes.h" +#include "options.h" +#include "string_list.h" +#include "log.h" +#include "sig_handler.h" +#include "daemon.h" +#include "writer.h" + +static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) +{ + GMainLoop *loop = (GMainLoop *)data; + + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_EOS: { + log_printf(NOTICE, "End of stream"); + g_main_loop_quit(loop); + break; + } + case GST_MESSAGE_INFO: { + GError *info; + gst_message_parse_info(msg, &info, NULL); + log_printf(INFO, "%s", info->message); + g_error_free(info); + break; + } + case GST_MESSAGE_WARNING: { + GError *warning; + gst_message_parse_warning(msg, &warning, NULL); + log_printf(WARNING, "%s", warning->message); + g_error_free(warning); + break; + } + case GST_MESSAGE_ERROR: { + GError *error; + gst_message_parse_error(msg, &error, NULL); + log_printf(ERROR, "%s", error->message); + g_error_free(error); + g_main_loop_quit(loop); + break; + } + default: + break; + } + return TRUE; +} + +int main_loop(options_t* opt) +{ + log_printf(INFO, "entering main loop"); + + GMainLoop *loop; + GstElement *pipeline, *source; + GstBus *bus; + writer_t writer; + + loop = g_main_loop_new(NULL, FALSE); + pipeline = gst_pipeline_new("sydra"); + if(!pipeline || !loop) { + log_printf(ERROR, "the pipeline/loop object could not be created. Exiting."); + return -1; + } + + int ret = writer_init(&writer, loop, opt->name_format_, opt->mode_, opt->nocache_, opt->output_dir_, opt->interval_, opt->offset_, opt->post_process_); + if(ret) { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(loop)); + return ret; + } + + GError *error = NULL; + source = gst_parse_bin_from_description(opt->src_bin_desc_, TRUE, &error); + if(!source || error) { + log_printf(ERROR, "Source Bin Description Parser Error: %s", error ? error->message : "unknown"); + g_error_free(error); + gst_object_unref(GST_OBJECT(writer.sink_)); + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(loop)); + return -1; + } + + gst_bin_add_many(GST_BIN(pipeline), source, writer.sink_, NULL); + gst_element_link_many(source, writer.sink_, NULL); + bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); + gst_bus_add_watch(bus, bus_call, loop); + gst_object_unref(bus); + + log_printf(INFO, "Set State: Paused"); + gst_element_set_state(pipeline, GST_STATE_PAUSED); + log_printf(INFO, "Set State: Playing"); + gst_element_set_state(pipeline, GST_STATE_PLAYING); + + signal_start(loop); + ret = writer_start(&writer); + if(!ret) { + g_main_loop_run(loop); + signal_stop(); + } + + log_printf(NOTICE, "Stopping pipeline"); + gst_element_set_state (pipeline, GST_STATE_NULL); + writer_stop(&writer); + gst_object_unref(GST_OBJECT(pipeline)); + + return ret; +} + +int main(int argc, char* argv[]) +{ + log_init(); + + options_t opt; + int ret = options_parse(&opt, argc, argv); + if(ret) { + if(ret > 0) + fprintf(stderr, "syntax error near: %s\n\n", argv[ret]); + if(ret == -2) + fprintf(stderr, "memory error on options_parse, exitting\n"); + if(ret == -3) + options_print_version(); + if(ret == -4) + fprintf(stderr, "the interval must be bigger than 0\n"); + + if(ret != -2 && ret != -3 && ret != -4) + options_print_usage(); + + if(ret == -1 || ret == -3) + ret = 0; + + options_clear(&opt); + log_close(); + exit(ret); + } + slist_element_t* tmp = opt.log_targets_.first_; + while(tmp) { + ret = log_add_target(tmp->data_); + if(ret) { + switch(ret) { + case -2: fprintf(stderr, "memory error on log_add_target, exitting\n"); break; + case -3: fprintf(stderr, "unknown log target: '%s', exitting\n", (char*)(tmp->data_)); break; + case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", (char*)(tmp->data_)); break; + default: fprintf(stderr, "syntax error near: '%s', exitting\n", (char*)(tmp->data_)); break; + } + + options_clear(&opt); + log_close(); + exit(ret); + } + tmp = tmp->next_; + } + + log_printf(NOTICE, "just started..."); + options_parse_post(&opt); + + priv_info_t priv; + if(opt.username_) + if(priv_init(&priv, opt.username_, opt.groupname_)) { + options_clear(&opt); + log_close(); + exit(-1); + } + + FILE* pid_file = NULL; + if(opt.pid_file_) { + pid_file = fopen(opt.pid_file_, "w"); + if(!pid_file) { + log_printf(WARNING, "unable to open pid file: %s", strerror(errno)); + } + } + + if(opt.chroot_dir_) + if(do_chroot(opt.chroot_dir_)) { + options_clear(&opt); + log_close(); + exit(-1); + } + if(opt.username_) + if(priv_drop(&priv)) { + options_clear(&opt); + log_close(); + exit(-1); + } + + if(opt.daemonize_) { + pid_t oldpid = getpid(); + daemonize(); + log_printf(INFO, "running in background now (old pid: %d)", oldpid); + } + + if(pid_file) { + pid_t pid = getpid(); + fprintf(pid_file, "%d", pid); + fclose(pid_file); + } + + signal_init(); + gst_init(NULL, NULL); + const gchar *nano_str; + guint major, minor, micro, nano; + gst_version(&major, &minor, µ, &nano); + if (nano == 1) + nano_str = " (CVS)"; + else if (nano == 2) + nano_str = " (Prerelease)"; + else + nano_str = ""; + log_printf(NOTICE, "sydra linked against GStreamer %d.%d.%d%s", major, minor, micro, nano_str); + + ret = main_loop(&opt); + + options_clear(&opt); + + log_printf(NOTICE, "sydra shutdown"); + + gst_deinit(); + log_close(); + + return ret; +} |