Newer
Older
} else if (!strcasecmp(cmd, "Author")) {
get_arg(stream->author, sizeof(stream->author), &p);
} else if (!strcasecmp(cmd, "Comment")) {
get_arg(stream->comment, sizeof(stream->comment), &p);
} else if (!strcasecmp(cmd, "Copyright")) {
get_arg(stream->copyright, sizeof(stream->copyright), &p);
} else if (!strcasecmp(cmd, "Title")) {
get_arg(stream->title, sizeof(stream->title), &p);
} else if (!strcasecmp(cmd, "Preroll")) {
get_arg(arg, sizeof(arg), &p);
stream->prebuffer = atof(arg) * 1000;
Philip Gladstone
committed
} else if (!strcasecmp(cmd, "StartSendOnKey")) {
Philip Gladstone
committed
stream->send_on_key = 1;
Philip Gladstone
committed
} else if (!strcasecmp(cmd, "AudioCodec")) {
get_arg(arg, sizeof(arg), &p);
audio_id = opt_audio_codec(arg);
if (audio_id == CODEC_ID_NONE) {
fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
Philip Gladstone
committed
filename, line_num, arg);
errors++;
}
} else if (!strcasecmp(cmd, "VideoCodec")) {
get_arg(arg, sizeof(arg), &p);
video_id = opt_video_codec(arg);
if (video_id == CODEC_ID_NONE) {
fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
Philip Gladstone
committed
filename, line_num, arg);
errors++;
}
} else if (!strcasecmp(cmd, "MaxTime")) {
get_arg(arg, sizeof(arg), &p);
stream->max_time = atof(arg) * 1000;
} else if (!strcasecmp(cmd, "AudioBitRate")) {
get_arg(arg, sizeof(arg), &p);
audio_enc.bit_rate = atoi(arg) * 1000;
} else if (!strcasecmp(cmd, "AudioChannels")) {
get_arg(arg, sizeof(arg), &p);
audio_enc.channels = atoi(arg);
} else if (!strcasecmp(cmd, "AudioSampleRate")) {
get_arg(arg, sizeof(arg), &p);
} else if (!strcasecmp(cmd, "AudioQuality")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
} else if (!strcasecmp(cmd, "VideoBitRateRange")) {
if (stream) {
int minrate, maxrate;
get_arg(arg, sizeof(arg), &p);
if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
video_enc.rc_min_rate = minrate * 1000;
video_enc.rc_max_rate = maxrate * 1000;
} else {
fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
filename, line_num, arg);
errors++;
}
}
Philip Gladstone
committed
} else if (!strcasecmp(cmd, "Debug")) {
if (stream) {
get_arg(arg, sizeof(arg), &p);
video_enc.debug = strtol(arg,0,0);
}
} else if (!strcasecmp(cmd, "Strict")) {
if (stream) {
get_arg(arg, sizeof(arg), &p);
video_enc.strict_std_compliance = atoi(arg);
}
Henning Haaland Kulander
committed
} else if (!strcasecmp(cmd, "VideoBufferSize")) {
if (stream) {
get_arg(arg, sizeof(arg), &p);
Philip Gladstone
committed
video_enc.rc_buffer_size = atoi(arg) * 8*1024;
Henning Haaland Kulander
committed
}
} else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
if (stream) {
get_arg(arg, sizeof(arg), &p);
video_enc.bit_rate_tolerance = atoi(arg) * 1000;
}
} else if (!strcasecmp(cmd, "VideoBitRate")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.bit_rate = atoi(arg) * 1000;
}
} else if (!strcasecmp(cmd, "VideoSize")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
if ((video_enc.width % 16) != 0 ||
(video_enc.height % 16) != 0) {
fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
filename, line_num);
errors++;
}
}
} else if (!strcasecmp(cmd, "VideoFrameRate")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
}
} else if (!strcasecmp(cmd, "VideoGopSize")) {
get_arg(arg, sizeof(arg), &p);
video_enc.gop_size = atoi(arg);
} else if (!strcasecmp(cmd, "VideoIntraOnly")) {
} else if (!strcasecmp(cmd, "VideoHighQuality")) {
video_enc.mb_decision = FF_MB_DECISION_BITS;
Philip Gladstone
committed
} else if (!strcasecmp(cmd, "Video4MotionVector")) {
if (stream) {
video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
Philip Gladstone
committed
video_enc.flags |= CODEC_FLAG_4MV;
}
} else if (!strcasecmp(cmd, "VideoTag")) {
get_arg(arg, sizeof(arg), &p);
if ((strlen(arg) == 4) && stream)
video_enc.codec_tag = ff_get_fourcc(arg);
} else if (!strcasecmp(cmd, "BitExact")) {
video_enc.flags |= CODEC_FLAG_BITEXACT;
} else if (!strcasecmp(cmd, "DctFastint")) {
video_enc.dct_algo = FF_DCT_FASTINT;
} else if (!strcasecmp(cmd, "IdctSimple")) {
video_enc.idct_algo = FF_IDCT_SIMPLE;
} else if (!strcasecmp(cmd, "Qscale")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.flags |= CODEC_FLAG_QSCALE;
video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
}
} else if (!strcasecmp(cmd, "VideoQDiff")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.max_qdiff = atoi(arg);
if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
filename, line_num);
errors++;
}
}
} else if (!strcasecmp(cmd, "VideoQMax")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.qmax = atoi(arg);
if (video_enc.qmax < 1 || video_enc.qmax > 31) {
fprintf(stderr, "%s:%d: VideoQMax out of range\n",
filename, line_num);
errors++;
}
}
} else if (!strcasecmp(cmd, "VideoQMin")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.qmin = atoi(arg);
if (video_enc.qmin < 1 || video_enc.qmin > 31) {
fprintf(stderr, "%s:%d: VideoQMin out of range\n",
filename, line_num);
errors++;
}
}
D Richard Felker III
committed
} else if (!strcasecmp(cmd, "LumaElim")) {
get_arg(arg, sizeof(arg), &p);
D Richard Felker III
committed
video_enc.luma_elim_threshold = atoi(arg);
} else if (!strcasecmp(cmd, "ChromaElim")) {
get_arg(arg, sizeof(arg), &p);
D Richard Felker III
committed
video_enc.chroma_elim_threshold = atoi(arg);
} else if (!strcasecmp(cmd, "LumiMask")) {
get_arg(arg, sizeof(arg), &p);
D Richard Felker III
committed
video_enc.lumi_masking = atof(arg);
} else if (!strcasecmp(cmd, "DarkMask")) {
get_arg(arg, sizeof(arg), &p);
D Richard Felker III
committed
video_enc.dark_masking = atof(arg);
} else if (!strcasecmp(cmd, "NoVideo")) {
video_id = CODEC_ID_NONE;
} else if (!strcasecmp(cmd, "NoAudio")) {
audio_id = CODEC_ID_NONE;
} else if (!strcasecmp(cmd, "ACL")) {
IPAddressACL acl;
get_arg(arg, sizeof(arg), &p);
if (strcasecmp(arg, "allow") == 0)
acl.action = IP_ALLOW;
else if (strcasecmp(arg, "deny") == 0)
acl.action = IP_DENY;
fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
filename, line_num, arg);
errors++;
}
get_arg(arg, sizeof(arg), &p);
if (resolve_host(&acl.first, arg) != 0) {
fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
filename, line_num, arg);
errors++;
acl.last = acl.first;
get_arg(arg, sizeof(arg), &p);
if (arg[0]) {
if (resolve_host(&acl.last, arg) != 0) {
fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
filename, line_num, arg);
errors++;
}
}
if (!errors) {
IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
IPAddressACL **naclp = 0;
*nacl = acl;
naclp = &stream->acl;
naclp = &feed->acl;
fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
filename, line_num);
errors++;
}
if (naclp) {
while (*naclp)
naclp = &(*naclp)->next;
*naclp = nacl;
}
}
Fabrice Bellard
committed
} else if (!strcasecmp(cmd, "RTSPOption")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
av_freep(&stream->rtsp_option);
Fabrice Bellard
committed
}
Fabrice Bellard
committed
} else if (!strcasecmp(cmd, "MulticastAddress")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
Alex Beregszaszi
committed
if (resolve_host(&stream->multicast_ip, arg) != 0) {
fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
Fabrice Bellard
committed
filename, line_num, arg);
errors++;
}
stream->is_multicast = 1;
stream->loop = 1; /* default is looping */
Fabrice Bellard
committed
}
} else if (!strcasecmp(cmd, "MulticastPort")) {
get_arg(arg, sizeof(arg), &p);
Fabrice Bellard
committed
stream->multicast_port = atoi(arg);
} else if (!strcasecmp(cmd, "MulticastTTL")) {
get_arg(arg, sizeof(arg), &p);
stream->multicast_ttl = atoi(arg);
} else if (!strcasecmp(cmd, "NoLoop")) {
stream->loop = 0;
} else if (!strcasecmp(cmd, "</Stream>")) {
if (!stream) {
fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
filename, line_num);
errors++;
}
if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
if (audio_id != CODEC_ID_NONE) {
audio_enc.codec_type = CODEC_TYPE_AUDIO;
audio_enc.codec_id = audio_id;
add_codec(stream, &audio_enc);
}
if (video_id != CODEC_ID_NONE) {
video_enc.codec_type = CODEC_TYPE_VIDEO;
video_enc.codec_id = video_id;
add_codec(stream, &video_enc);
}
}
stream = NULL;
} else if (!strcasecmp(cmd, "<Redirect")) {
/*********************************************/
char *q;
if (stream || feed || redirect) {
fprintf(stderr, "%s:%d: Already in a tag\n",
filename, line_num);
errors++;
} else {
redirect = av_mallocz(sizeof(FFStream));
*last_stream = redirect;
last_stream = &redirect->next;
get_arg(redirect->filename, sizeof(redirect->filename), &p);
q = strrchr(redirect->filename, '>');
if (*q)
*q = '\0';
redirect->stream_type = STREAM_TYPE_REDIRECT;
}
} else if (!strcasecmp(cmd, "URL")) {
get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
} else if (!strcasecmp(cmd, "</Redirect>")) {
if (!redirect) {
fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
filename, line_num);
errors++;
}
if (!redirect->feed_filename[0]) {
fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
filename, line_num);
errors++;
}
redirect = NULL;
Fabrice Bellard
committed
} else if (!strcasecmp(cmd, "LoadModule")) {
get_arg(arg, sizeof(arg), &p);
#ifdef HAVE_DLOPEN
Fabrice Bellard
committed
load_module(arg);
fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
filename, line_num, arg);
errors++;
#endif
fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
filename, line_num, cmd);
errors++;
}
}
fclose(f);
if (errors)
return -1;
else
return 0;
}
static void show_banner(void)
printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2006 Fabrice Bellard, et al.\n");
}
static void show_help(void)
{
show_banner();
printf("usage: ffserver [-L] [-h] [-f configfile]\n"
"Hyper fast multi format Audio/Video streaming server\n"
"\n"
"-h : this help\n"
"-f configfile : use configfile instead of /etc/ffserver.conf\n"
);
}
static void show_license(void)
Diego Biurrun
committed
"FFmpeg is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU Lesser General Public\n"
"License as published by the Free Software Foundation; either\n"
Diego Biurrun
committed
"version 2.1 of the License, or (at your option) any later version.\n"
Diego Biurrun
committed
"FFmpeg is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
"Lesser General Public License for more details.\n"
"You should have received a copy of the GNU Lesser General Public\n"
Diego Biurrun
committed
"License along with FFmpeg; if not, write to the Free Software\n"
"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
static void handle_child_exit(int sig)
{
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
FFStream *feed;
for (feed = first_feed; feed; feed = feed->next) {
if (feed->pid == pid) {
int uptime = time(0) - feed->pid_start;
feed->pid = 0;
fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
/* Turn off any more restarts */
feed->child_argv = 0;
}
}
}
need_to_start_children = 1;
}
int main(int argc, char **argv)
{
const char *config_filename;
int c;
av_register_all();
my_program_dir = getcwd(0, 0);
Fabrice Bellard
committed
ffserver_daemon = 1;
Fabrice Bellard
committed
c = getopt(argc, argv, "ndLh?f:");
case 'n':
no_launch = 1;
break;
case 'd':
ffserver_debug = 1;
Fabrice Bellard
committed
ffserver_daemon = 0;
break;
case 'f':
config_filename = optarg;
break;
default:
exit(2);
}
}
putenv("http_proxy"); /* Kill the http_proxy */
av_init_random(av_gettime() + (getpid() << 16), &random_state);
Fabrice Bellard
committed
/* address on which the server will handle HTTP connections */
my_http_addr.sin_family = AF_INET;
my_http_addr.sin_port = htons (8080);
my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
/* address on which the server will handle RTSP connections */
my_rtsp_addr.sin_family = AF_INET;
my_rtsp_addr.sin_port = htons (5454);
my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
max_bandwidth = 1000;
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;
sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
sigaction(SIGCHLD, &sigact, 0);
if (parse_ffconfig(config_filename) < 0) {
fprintf(stderr, "Incorrect config file - exiting.\n");
exit(1);
}
Fabrice Bellard
committed
build_file_streams();
compute_bandwidth();
Fabrice Bellard
committed
/* put the process in background and detach it from its TTY */
if (ffserver_daemon) {
int pid;
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
} else if (pid > 0) {
/* parent : exit */
exit(0);
} else {
/* child */
setsid();
chdir("/");
close(0);
open("/dev/null", O_RDWR);
close(1);
dup(0);
}
close(2);
Fabrice Bellard
committed
dup(0);
}
}
/* signal init */
signal(SIGPIPE, SIG_IGN);
/* open log file if needed */
if (logfilename[0] != '\0') {
if (!strcmp(logfilename, "-"))
logfile = stdout;
else
logfile = fopen(logfilename, "w");
}
Fabrice Bellard
committed
if (http_server() < 0) {
fprintf(stderr, "Could not start server\n");