From a32b141e1c7bbdc5e36e9d3debf262eb1c26ddfc Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Fri, 26 Sep 2014 00:29:10 +0200 Subject: now using GOptions for command line parsing --- src/options.c | 462 +++++++++++++++++++++++++++------------------------------- 1 file changed, 217 insertions(+), 245 deletions(-) (limited to 'src/options.c') diff --git a/src/options.c b/src/options.c index 1d5a0d6..6f7a0fc 100644 --- a/src/options.c +++ b/src/options.c @@ -39,192 +39,32 @@ #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_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++; \ - } +#include +#include - -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("-a","--rtp-host", opt->rtp_host_) - PARSE_INT_PARAM("-o","--rtp-port-base", opt->rtp_port_base_, 10) - PARSE_STRING_PARAM("-A","--rtp-addr-local", opt->rtp_addr_local_) - PARSE_INT_PARAM("-O","--rtp-port-base-local", opt->rtp_port_base_local_, 10) - PARSE_INT_PARAM("-t","--timeout", opt->timeout_, 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 || - opt->rtp_port_base_local_ < 1 || opt->rtp_port_base_local_ > 65535) - return -4; - - if(opt->timeout_ < 0) - return -5; - - 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) +static void options_defaults(options_t* opt) { if(!opt) return; - opt->progname_ = strdup("sydra"); + opt->progname_ = g_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->log_targets_ = NULL; 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=1200000 cpu-used=4 deadline=1000000 threads=2"); - opt->video_payloader_ = strdup("rtpvp8pay"); + opt->video_src_ = g_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_ = g_strdup("vp8enc keyframe-max-dist=25 error-resilient=2 end-usage=1 target-bitrate=1200000 cpu-used=4 deadline=1000000 threads=2"); + opt->video_payloader_ = g_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->audio_src_ = g_strdup("autoaudiosrc ! audio/x-raw,format=S16LE,channels=1,rate=48000 ! identity"); + opt->audio_enc_ = g_strdup("opusenc bitrate=64000 cbr=true packet-loss-percentage=0 inband-fec=false"); + opt->audio_payloader_ = g_strdup("rtpopuspay"); opt->rtp_host_ = NULL; opt->rtp_port_base_ = 5000; @@ -237,91 +77,219 @@ void options_default(options_t* opt) 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"); + opt->rec_name_format_ = g_strdup("./recordings/%Y-%m-%d_%H-%M-%S"); } -void options_clear(options_t* opt) +static GOptionGroup* options_get_av_group(options_t* opt) +{ + GOptionEntry av_entries[] = { + { "video-source", 0, 0, G_OPTION_ARG_STRING, &opt->video_src_, + "pipeline for raw video (i.e. videotestsrc)", "BIN DESCRIPTION" }, + { "video-encoder", 0, 0, G_OPTION_ARG_STRING, &opt->video_enc_, + "pipeline for video encoder (i.e. videoconvert ! vp8enc)", "BIN DESCRIPTION" }, + { "video-payloader", 0, 0, G_OPTION_ARG_STRING, &opt->video_payloader_, + "video RTP payloader element (i.e. rtpvp8pay)", "ELEMENT" }, + { "audio-source", 0, 0, G_OPTION_ARG_STRING, &opt->audio_src_, + "pipeline for raw audio (i.e. audiotestsrc)", "BIN DESCRIPTION" }, + { "audio-encoder", 0, 0, G_OPTION_ARG_STRING, &opt->audio_enc_, + "pipeline for audio encoder (i.e. audioconvert ! opusenc)", "BIN DESCRIPTION" }, + { "audio-payloader", 0, 0, G_OPTION_ARG_STRING, &opt->audio_payloader_, + "audio RTP payloader element (i.e. rtpopuspay)", "ELEMENT" }, + { NULL } + }; + GOptionGroup* av_group = g_option_group_new ("av", "Audio/Video Options", + "Show Audio/Video Options", NULL, NULL); + if(!av_group) return NULL; + g_option_group_add_entries(av_group, av_entries); + + return av_group; +} + +static GOptionGroup* options_get_rtp_group(options_t* opt) +{ + GOptionEntry rtp_entries[] = { + { "rtp-host", 'a', 0, G_OPTION_ARG_STRING, &opt->rtp_host_, + "remote host for RTP packets", "HOST" }, + { "rtp-port-base", 'o', 0, G_OPTION_ARG_INT, &opt->rtp_port_base_, + "base number for remote ports", "PORT" }, + { "rtp-addr-local", 'A', 0, G_OPTION_ARG_STRING, &opt->rtp_addr_local_, + "local address to bind to", "ADDRESS" }, + { "rtp-port-base-local", 'O', 0, G_OPTION_ARG_INT, &opt->rtp_port_base_local_, + "base number for local ports to bind to", "PORT" }, + { "timeout", 't', 0, G_OPTION_ARG_INT, &opt->timeout_, + "client timeout in seconds (0 means no timeout)", "VALUE" }, + { NULL } + }; + GOptionGroup* rtp_group = g_option_group_new ("rtp", "RTP Options", + "Show RTP Options", NULL, NULL); + if(!rtp_group) return NULL; + g_option_group_add_entries(rtp_group, rtp_entries); + + return rtp_group; +} + +static GOptionGroup* options_get_rec_group(options_t* opt) +{ + GOptionEntry rec_entries[] = { + { "rec-video-encoder", 0, 0, G_OPTION_ARG_STRING, &opt->video_enc_rec_, + "pipeline for video encoder for recording (i.e. videoconvert ! jpegenc) - leave empty to use same as for RTP", "BIN DESCRIPTION" }, + { "rec-audio-encoder", 0, 0, G_OPTION_ARG_STRING, &opt->audio_enc_rec_, + "pipeline for audio encoder for recording (i.e. audioconvert ! vorbisenc) - leave empty to use same as for RTP", "BIN DESCRIPTION" }, + { "rec-mux", 0, 0, G_OPTION_ARG_STRING, &opt->rec_mux_, + "muxer elemenent for recording (i.e. matroskamux) - leave empty to disable recording", "ELEMENT" }, + { "rec-name-format", 0, 0, G_OPTION_ARG_STRING, &opt->rec_name_format_, + "the recording file name format string, see manpage of strftime for the syntax", "FORMATSTRING" }, + { NULL } + }; + GOptionGroup* rec_group = g_option_group_new ("rec", "Recording Options", + "Show Recording Options", NULL, NULL); + if(!rec_group) return NULL; + g_option_group_add_entries(rec_group, rec_entries); + + return rec_group; +} + +static int options_parse_post(options_t* opt); + +int options_parse(options_t* opt, int argc, char* argv[]) { if(!opt) - return; + return -1; + + options_defaults(opt); + + g_free(opt->progname_); + opt->progname_ = g_strdup(argv[0]); + if(!opt->progname_) + return -255; + + gboolean show_version = FALSE; + GOptionEntry main_entries[] = { + { "version", 'v', 0, G_OPTION_ARG_NONE, &show_version, + "print version info and exit", NULL }, + { "nodaemonize", 'D', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt->daemonize_, + "don't run in background", NULL }, + { "username", 'u', 0, G_OPTION_ARG_STRING, &opt->username_, + "change to this user", "USERNAME" }, + { "group", 'g', 0, G_OPTION_ARG_STRING, &opt->groupname_, + "change to this group", "GROUP" }, + { "chroot", 'C', 0, G_OPTION_ARG_STRING, &opt->chroot_dir_, + "chroot to this directory", "PATH" }, + { "write-pid", 'P', 0, G_OPTION_ARG_STRING, &opt->pid_file_, + "write pid to this file", "PATH" }, + { "log", 'L', 0, G_OPTION_ARG_STRING_ARRAY, &opt->log_targets_, + "add a log target, can be invoked several times", ":[,[,..]]" }, + { "debug", 'U', 0, G_OPTION_ARG_NONE, &opt->debug_, + "don't daemonize and log to stdout with maximum log level", NULL }, + { "appname", 'n', 0, G_OPTION_ARG_STRING, &opt->appname_, + "set the application name (will be used by xvimagesink for window title)", "NAME" }, + { "videosink", 'V', 0, G_OPTION_ARG_STRING, &opt->preview_videosink_, + "video sink element for local preview (i.e. xvimagesink) - leave empty to disable preview", "BIN DESCRIPTION" }, + { NULL } + }; + GOptionContext *ctx = g_option_context_new("- spreadspace streaming hydra "); + g_option_context_add_main_entries(ctx, main_entries, NULL); + + GOptionGroup* av_group = options_get_av_group(opt); + GOptionGroup* rtp_group = options_get_rtp_group(opt); + GOptionGroup* rec_group = options_get_rec_group(opt); + GOptionGroup* gst_group = gst_init_get_option_group(); + if(!av_group || !rtp_group || !rec_group || !gst_group) { + printf("Failed to initialize: memory error\n"); + return -255; + } + g_option_context_add_group(ctx, av_group); + g_option_context_add_group(ctx, rtp_group); + g_option_context_add_group(ctx, rec_group); + g_option_context_add_group(ctx, gst_group); + GError *err = NULL; + if(!g_option_context_parse(ctx, &argc, &argv, &err)) { + printf("Failed to initialize: %s\n", err->message); + g_error_free(err); + return 1; + } + + if(show_version) + return -1; + + return options_parse_post(opt); +} + +static int options_parse_post(options_t* opt) +{ + if(opt->rtp_port_base_ < 1 || opt->rtp_port_base_ > 65535 || + opt->rtp_port_base_local_ < 1 || opt->rtp_port_base_local_ > 65535) { + printf("Failed to initialize: rtp port is invalid\n"); + return -2; + } + + if(opt->timeout_ < 0) { + printf("Failed to initialize: timeout is invalid\n"); + return -3; + } + + if(opt->debug_) { + opt->daemonize_ = 0; + g_strfreev(opt->log_targets_); + opt->log_targets_ = g_new(gchar*, 2); + if(!opt->log_targets_) return -255; + opt->log_targets_[0] = g_strdup("stdout:5"); + if(!(opt->log_targets_[0])) return -255; + opt->log_targets_[1] = NULL; + } + + if(!g_strv_length(opt->log_targets_)) { + opt->log_targets_ = g_new(gchar*, 2); + if(!opt->log_targets_) return -255; + opt->log_targets_[0] = g_strdup("syslog:3,sydra,daemon"); + if(!(opt->log_targets_[0])) return -255; + opt->log_targets_[1] = NULL; + } - 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->rtp_addr_local_) - free(opt->rtp_addr_local_); - 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_); + return 0; } -void options_print_usage() +void options_clear(options_t* opt) { - 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(" [-a|--rtp-host remote host for RTP packets\n"); - printf(" [-o|--rtp-port-base base number for remote ports\n"); - printf(" [-A|--rtp-addr-local local address to bind to\n"); - printf(" [-O|--rtp-port-base-local base number for local ports to bind to\n"); - printf(" [-t|--timeout client timeout (0 means no timeout)\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"); + if(!opt) + return; + + g_free(opt->progname_); + g_free(opt->username_); + g_free(opt->groupname_); + g_free(opt->chroot_dir_); + g_free(opt->pid_file_); + g_strfreev(opt->log_targets_); + g_free(opt->appname_); + g_free(opt->video_src_); + g_free(opt->video_enc_); + g_free(opt->video_payloader_); + g_free(opt->audio_src_); + g_free(opt->audio_enc_); + g_free(opt->audio_payloader_); + g_free(opt->rtp_host_); + g_free(opt->rtp_addr_local_); + g_free(opt->preview_videosink_); + g_free(opt->video_enc_rec_); + g_free(opt->audio_enc_rec_); + g_free(opt->rec_mux_); + g_free(opt->rec_name_format_); } void options_print_version() { printf("%s\n", VERSION_STRING_0); printf("%s\n", VERSION_STRING_1); + 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 = ""; + printf(" linked against GStreamer %d.%d.%d%s\n", major, minor, micro, nano_str); } void options_print(options_t* opt) @@ -330,14 +298,18 @@ void options_print(options_t* opt) return; printf(" progname: '%s'\n", opt->progname_); - printf(" daemonize: %d\n", opt->daemonize_); + printf(" daemonize: %s\n", opt->daemonize_ ? "true" : "false"); 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"); + gchar* lt = opt->log_targets_ ? g_strjoinv ("'\n '", opt->log_targets_) : NULL; + if(lt) { + printf(" '%s'\n", lt); + g_free(lt); + } + printf(" debug: %s\n", opt->debug_ ? "true" : "false"); printf(" appname: >>%s<<\n", opt->appname_); printf(" video_src: >>%s<<\n", opt->video_src_); printf(" video_enc: >>%s<<\n", opt->video_enc_); -- cgit v1.2.3