/* * 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 * * 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 . * * In addition, as a special exception, the copyright holders hereby * grant permission for non-GPL-compatible GStreamer plugins to be used * and distributed together with GStreamer and sydra. * This permission goes above and beyond the permissions granted by the * GPL license sydra is covered by. */ #include "datatypes.h" #include "config.h" #include "options.h" #include "log.h" #include #include #include #include #define PARSE_BOOL_PARAM(SHORT, LONG, VALUE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ VALUE = 1; #define PARSE_INVERSE_BOOL_PARAM(SHORT, LONG, VALUE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ VALUE = 0; #define PARSE_INT_PARAM(SHORT, LONG, VALUE, BASE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ { \ if(argc < 1) \ return i; \ VALUE = strtol(argv[i+1], (char **)NULL, BASE); \ argc--; \ i++; \ } #define PARSE_STRING_PARAM(SHORT, LONG, VALUE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ { \ if(argc < 1 || argv[i+1][0] == '-') \ return i; \ if(VALUE) free(VALUE); \ VALUE = strdup(argv[i+1]); \ if(!VALUE) \ return -2; \ argc--; \ i++; \ } #define PARSE_STRING_PARAM_SEC(SHORT, LONG, VALUE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ { \ if(argc < 1 || argv[i+1][0] == '-') \ return i; \ if(VALUE) free(VALUE); \ VALUE = strdup(argv[i+1]); \ if(!VALUE) \ return -2; \ size_t j; \ for(j=0; j < strlen(argv[i+1]); ++j) \ argv[i+1][j] = '#'; \ argc--; \ i++; \ } #define PARSE_HEXSTRING_PARAM_SEC(SHORT, LONG, VALUE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ { \ if(argc < 1 || argv[i+1][0] == '-') \ return i; \ int ret; \ ret = options_parse_hex_string(argv[i+1], &VALUE); \ if(ret > 0) \ return i+1; \ else if(ret < 0) \ return ret; \ size_t j; \ for(j=0; j < strlen(argv[i+1]); ++j) \ argv[i+1][j] = '#'; \ argc--; \ i++; \ } #define PARSE_STRING_LIST(SHORT, LONG, LIST) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ { \ if(argc < 1 || argv[i+1][0] == '-') \ return i; \ int ret = string_list_add(&LIST, argv[i+1]); \ if(ret == -2) \ return ret; \ else if(ret) \ return i+1; \ argc--; \ i++; \ } #define PARSE_RESOLV_TYPE(SHORT, LONG, VALUE) \ else if(!strcmp(str,SHORT) || !strcmp(str,LONG)) \ { \ if(argc < 1 || argv[i+1][0] == '-') \ return i; \ if(!strcmp(argv[i+1], "4") || \ !strcmp(argv[i+1], "ipv4")) \ VALUE = IPV4_ONLY; \ else if(!strcmp(argv[i+1], "6") || \ !strcmp(argv[i+1], "ipv6")) \ VALUE = IPV6_ONLY; \ else \ return i+1; \ argc--; \ i++; \ } int options_parse_hex_string(const char* hex, buffer_t* buffer) { if(!hex || !buffer) return -1; u_int32_t hex_len = strlen(hex); if(hex_len%2) return 1; if(buffer->buf_) free(buffer->buf_); buffer->length_ = hex_len/2; buffer->buf_ = malloc(buffer->length_); if(!buffer->buf_) { buffer->length_ = 0; return -2; } const char* ptr = hex; int i; for(i=0;ilength_;++i) { u_int32_t tmp; sscanf(ptr, "%2X", &tmp); buffer->buf_[i] = (u_int8_t)tmp; ptr += 2; } return 0; } int options_parse(options_t* opt, int argc, char* argv[]) { if(!opt) return -1; options_default(opt); if(opt->progname_) free(opt->progname_); opt->progname_ = strdup(argv[0]); if(!opt->progname_) return -2; argc--; int i; for(i=1; argc > 0; ++i) { char* str = argv[i]; argc--; if(!strcmp(str,"-h") || !strcmp(str,"--help")) return -1; else if(!strcmp(str,"-v") || !strcmp(str,"--version")) return -3; PARSE_INVERSE_BOOL_PARAM("-D","--nodaemonize", opt->daemonize_) PARSE_STRING_PARAM("-u","--username", opt->username_) PARSE_STRING_PARAM("-g","--groupname", opt->groupname_) PARSE_STRING_PARAM("-C","--chroot", opt->chroot_dir_) PARSE_STRING_PARAM("-P","--write-pid", opt->pid_file_) PARSE_STRING_LIST("-L","--log", opt->log_targets_) PARSE_BOOL_PARAM("-U", "--debug", opt->debug_) PARSE_STRING_PARAM("-n","--appname", opt->appname_) PARSE_STRING_PARAM("-vs","--video-source", opt->video_src_) PARSE_STRING_PARAM("-ve","--video-encoder", opt->video_enc_) PARSE_STRING_PARAM("-vp","--video-payloader", opt->video_payloader_) PARSE_STRING_PARAM("-as","--audio-source", opt->audio_src_) PARSE_STRING_PARAM("-ae","--audio-encoder", opt->audio_enc_) PARSE_STRING_PARAM("-ap","--audio-payloader", opt->audio_payloader_) PARSE_STRING_PARAM("-o","--rtp-host", opt->rtp_host_) PARSE_INT_PARAM("-O","--rtp-port-base", opt->rtp_port_base_, 10) PARSE_STRING_PARAM("-V","--videosink", opt->preview_videosink_) PARSE_STRING_PARAM("-rv","--rec-video-encoder", opt->video_enc_rec_) PARSE_STRING_PARAM("-ra","--rec-audio-encoder", opt->audio_enc_rec_) PARSE_STRING_PARAM("-rm","--rec-mux", opt->rec_mux_) PARSE_STRING_PARAM("-R","--rec-name-format", opt->rec_name_format_) else return i; } if(opt->rtp_port_base_ < 1 || opt->rtp_port_base_ > 65535) return -4; if(opt->debug_) { string_list_add(&opt->log_targets_, "stdout:5"); opt->daemonize_ = 0; } if(!opt->log_targets_.first_) { string_list_add(&opt->log_targets_, "syslog:3,sydra,daemon"); } return 0; } void options_parse_post(options_t* opt) { if(!opt) return; // nothing yet } void options_default(options_t* opt) { if(!opt) return; opt->progname_ = strdup("sydra"); opt->daemonize_ = 1; opt->username_ = NULL; opt->groupname_ = NULL; opt->chroot_dir_ = NULL; opt->pid_file_ = NULL; string_list_init(&opt->log_targets_); opt->debug_ = 0; opt->appname_ = NULL; opt->video_src_ = strdup("v4l2src ! videoconvert ! videoscale ! video/x-raw,format=I420,width=864,height=480,framerate=25/1,pixel-aspect-ratio=1/1 ! identity"); opt->video_enc_ = strdup("vp8enc keyframe-max-dist=25 error-resilient=2 end-usage=1 target-bitrate=1800000 cpu-used=4 deadline=1000000 threads=2"); opt->video_payloader_ = strdup("rtpvp8pay"); opt->audio_src_ = strdup("autoaudiosrc ! audio/x-raw,format=S16LE,channels=1,rate=48000 ! identity"); opt->audio_enc_ = strdup("opusenc bitrate=64000 cbr=true packet-loss-percentage=0 inband-fec=false"); opt->audio_payloader_ = strdup("rtpopuspay"); opt->rtp_host_ = strdup("127.0.0.1"); opt->rtp_port_base_ = 5000; opt->preview_videosink_ = NULL; opt->video_enc_rec_ = NULL; opt->audio_enc_rec_ = NULL; opt->rec_mux_ = NULL; opt->rec_name_format_ = strdup("./recordings/%Y-%m-%d_%H-%M-%S"); } void options_clear(options_t* opt) { if(!opt) return; if(opt->progname_) free(opt->progname_); if(opt->username_) free(opt->username_); if(opt->groupname_) free(opt->groupname_); if(opt->chroot_dir_) free(opt->chroot_dir_); if(opt->pid_file_) free(opt->pid_file_); string_list_clear(&opt->log_targets_); if(opt->appname_) free(opt->appname_); if(opt->video_src_) free(opt->video_src_); if(opt->video_enc_) free(opt->video_enc_); if(opt->video_payloader_) free(opt->video_payloader_); if(opt->audio_src_) free(opt->audio_src_); if(opt->audio_enc_) free(opt->audio_enc_); if(opt->audio_payloader_) free(opt->audio_payloader_); if(opt->rtp_host_) free(opt->rtp_host_); if(opt->preview_videosink_) free(opt->preview_videosink_); if(opt->video_enc_rec_) free(opt->video_enc_rec_); if(opt->audio_enc_rec_) free(opt->audio_enc_rec_); if(opt->rec_mux_) free(opt->rec_mux_); if(opt->rec_name_format_) free(opt->rec_name_format_); } void options_print_usage() { printf("USAGE:\n"); printf("sydra [-h|--help] prints this...\n"); printf(" [-v|--version] print version info and exit\n"); printf(" [-D|--nodaemonize] don't run in background\n"); printf(" [-u|--username] change to this user\n"); printf(" [-g|--groupname] change to this group\n"); printf(" [-C|--chroot] chroot to this directory\n"); printf(" [-P|--write-pid] write pid to this file\n"); printf(" [-L|--log] :[,[,..]]\n"); printf(" add a log target, can be invoked several times\n"); printf(" [-U|--debug] don't daemonize and log to stdout with maximum log level\n"); printf(" [-n|--appname] set the application name (will be used by xvimagesink for window title)\n"); printf(" [-vs|--video-source pipeline for raw video (i.e. videotestsrc)\n"); printf(" [-ve|--video-encoder pipeline for video encoder (stream)\n"); printf(" [-vp|--video-payloader video payloader element (i.e. rtpvp8pay)\n"); printf(" [-as|--audio-source pipeline for raw audio (audiotestsrc)\n"); printf(" [-ae|--audio-encoder pipeline for audio encoder (stream)\n"); printf(" [-ap|--audio-payloader audio payloader element (i.e. rptopuspay)\n"); printf(" [-o|--rtp-host remote host for RTP packets\n"); printf(" [-O|--rtp-port-base base number for remote ports\n"); printf(" [-V|--videosink video sink element for local preview (i.e. xvimagesink) - leave empty to disable preview\n"); printf(" [-rv|--rec-video-encoder pipeline for video encoder (recording - leave empty for same as stream)\n"); printf(" [-ra|--rec-audio-encoder pipeline for audio encoder (recording - leave empty for same as stream)\n"); printf(" [-rm|--rec-mux muxer elemenent (i.e. matroskamux)\n"); printf(" [-r|--rec-name-format] the recording file name format, see manpage of strftime for the syntax\n"); } void options_print_version() { printf("%s\n", VERSION_STRING_0); printf("%s\n", VERSION_STRING_1); } void options_print(options_t* opt) { if(!opt) return; printf(" progname: '%s'\n", opt->progname_); printf(" daemonize: %d\n", opt->daemonize_); printf(" username: '%s'\n", opt->username_); printf(" groupname: '%s'\n", opt->groupname_); printf(" chroot_dir: '%s'\n", opt->chroot_dir_); printf(" pid_file: '%s'\n", opt->pid_file_); printf(" log_targets: \n"); string_list_print(&opt->log_targets_, " '", "'\n"); printf(" debug: %s\n", !opt->debug_ ? "false" : "true"); printf(" appname: >>%s<<\n", opt->appname_); printf(" video_src: >>%s<<\n", opt->video_src_); printf(" video_enc: >>%s<<\n", opt->video_enc_); printf(" video_payloader: >>%s<<\n", opt->video_payloader_); printf(" audio_src: >>%s<<\n", opt->audio_src_); printf(" audio_enc: >>%s<<\n", opt->audio_enc_); printf(" audio_payloader: >>%s<<\n", opt->audio_payloader_); printf(" rtp_host: >>%s<<\n", opt->rtp_host_); printf(" rtp_port_base: %d\n", opt->rtp_port_base_); printf(" preview_video_sink: >>%s<<\n", opt->preview_videosink_); printf(" video_enc_rec: >>%s<<\n", opt->video_enc_rec_); printf(" audio_enc_rec: >>%s<<\n", opt->audio_enc_rec_); printf(" rec_mux: >>%s<<\n", opt->rec_mux_); printf(" rec_name_format: '%s'\n", opt->rec_name_format_); }