main.cpp 3.91 KB
Newer Older
1
/**
2 3 4
 * @file main.cpp
 * @brief Spawn single instance of streamer for each sensor port.
 * @copyright Copyright (C) 2017 Elphel Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * @author AUTHOR <EMAIL>
 *
 * @par License:
 *  This program 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
 *  (at your option) any later version.
 *
 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21

22 23 24 25 26 27 28 29 30 31
#include <iostream>
#include <string>
#include <map>

#include "streamer.h"

using namespace std;

#include <unistd.h>
#include <linux/sysctl.h>
32 33 34 35 36 37 38 39
#include <elphel/c313a.h>
#include <pthread.h>

/**
 * Unconditionally cancel all threads.
 * @param   threads   an array of thread pointers
 * @return  None
 */
40
void clean_up(pthread_t *threads, size_t sz) {
41 42 43 44 45 46 47
	int ret_val;

	for (size_t i = 0; i < sz; i++) {
		ret_val = pthread_cancel(threads[i]);
		if (!ret_val)
			cout << "pthread_cancel returned " << ret_val << ", sensor port " << i << endl;
	}
48
}
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/**
 * Print help message on stdout.
 * @param   argv   a list of command-line arguments, used to get the name of application
 * @return  None
 */
void print_help(char *argv[])
{
	const char *msg = "Simple RTSP streamer implementation for Elphel393 series cameras.\n"
			"Usage: %s [-s <port>][-D <sound_card>][-f <fps>][-h], where\n\n"
			"\t-h\t\tprint this help message;\n"
			"\t-s <port>\tstream sound from USB microphone over sensor port <port> channel. By default, audio streaming is not\n"
			"\t\t\tenabled if this option is not specified;\n"
			"\t-D <sound_card>\tuse <sound_card> device for sound stream input. The default device is plughw:0,0;\n"
			"\t-f <fps>\tlimit frames per second for video streaming, works for free running mode only.\n"; // this one is processed in streamer class
	printf(msg, argv[0]);
}

67
int main(int argc, char *argv[]) {
68
	int ret_val;
69
	int audio_port = -1;
70 71
	string opt;
	map<string, string> args;
72
	map<string, string>::iterator args_it;
73 74
	pthread_t threads[SENSOR_PORTS];
	Streamer *streamers[SENSOR_PORTS] = {NULL};
75

76
	// copy command-line arguments to a map container for further processing in streamer class
77 78 79
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-' && argv[i][1] != '\0') {
			if (opt != "")
80 81 82 83
				args[opt] = "";
			opt = &argv[i][1];
			continue;
		} else {
84
			if (opt != "") {
85 86 87 88 89
				args[opt] = argv[i];
				opt = "";
			}
		}
	}
90
	if (opt != "")
91
		args[opt] = "";
92
	for (map<string, string>::iterator it = args.begin(); it != args.end(); it++) {
93 94
		cerr << "|" << (*it).first << "| == |" << (*it).second << "|" << endl;
	}
95 96 97 98 99 100 101 102 103
	if ((args_it = args.find("h")) != args.end()) {
		print_help(argv);
		exit(EXIT_SUCCESS);
	} else if ((args_it = args.find("s")) != args.end()) {
		audio_port = strtol(args_it->second.c_str(), NULL, 10);
		// sanity check, invalid conversion produces 0 which is fine
		if (audio_port < 0 || audio_port >= SENSOR_PORTS)
			audio_port = -1;
	}
104

105 106
	for (int i = 0; i < SENSOR_PORTS; i++) {
		bool audio_en;
107
		pthread_attr_t attr;
108 109 110 111 112

		if (i == audio_port)
			audio_en = true;
		else
			audio_en = false;
113
		cout << "Start thread " << i << endl;
114
		streamers[i] = new Streamer(args, i, audio_en);
115 116

		pthread_attr_init(&attr);
117 118 119 120
		ret_val = pthread_create(&threads[i], &attr, Streamer::pthread_f, (void *) streamers[i]);
		if (ret_val != 0) {
			cerr << "Can not spawn streamer thread for port " << i;
			cerr << ", pthread_create returned " << ret_val << endl;
121
			clean_up(threads, SENSOR_PORTS);
122 123 124 125
			exit(EXIT_FAILURE);
		}
		pthread_attr_destroy(&attr);
	}
126 127
	for (size_t i = 0; i < SENSOR_PORTS; i++)
		pthread_join(threads[i], NULL);
128

129 130
	return 0;
}