Newer
Older
if (stream) {
get_arg(stream->title, sizeof(stream->title), &p);
}
} else if (!strcasecmp(cmd, "Preroll")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
stream->prebuffer = atof(arg) * 1000;
Philip Gladstone
committed
} else if (!strcasecmp(cmd, "StartSendOnKey")) {
if (stream) {
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",
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",
filename, line_num, arg);
errors++;
}
} else if (!strcasecmp(cmd, "MaxTime")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
stream->max_time = atof(arg) * 1000;
}
} else if (!strcasecmp(cmd, "AudioBitRate")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
audio_enc.bit_rate = atoi(arg) * 1000;
}
} else if (!strcasecmp(cmd, "AudioChannels")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
audio_enc.channels = atoi(arg);
}
} else if (!strcasecmp(cmd, "AudioSampleRate")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
audio_enc.sample_rate = atoi(arg);
}
} 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++;
}
}
Henning Haaland Kulander
committed
} else if (!strcasecmp(cmd, "VideoBufferSize")) {
if (stream) {
get_arg(arg, sizeof(arg), &p);
video_enc.rc_buffer_size = atoi(arg) * 1024;
}
} 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) {
parse_image_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) {
Michael Niedermayer
committed
video_enc.frame_rate_base= DEFAULT_FRAME_RATE_BASE;
video_enc.frame_rate = (int)(strtod(arg, NULL) * video_enc.frame_rate_base);
}
} else if (!strcasecmp(cmd, "VideoGopSize")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.gop_size = atoi(arg);
}
} else if (!strcasecmp(cmd, "VideoIntraOnly")) {
if (stream) {
video_enc.gop_size = 1;
}
} else if (!strcasecmp(cmd, "VideoHighQuality")) {
if (stream) {
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, "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);
if (stream) {
video_enc.luma_elim_threshold = atoi(arg);
}
} else if (!strcasecmp(cmd, "ChromaElim")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.chroma_elim_threshold = atoi(arg);
}
} else if (!strcasecmp(cmd, "LumiMask")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
video_enc.lumi_masking = atof(arg);
}
} else if (!strcasecmp(cmd, "DarkMask")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
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;
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
} else if (!strcasecmp(cmd, "ACL")) {
IPAddressACL acl;
struct hostent *he;
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;
} else {
fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
filename, line_num, arg);
errors++;
}
get_arg(arg, sizeof(arg), &p);
he = gethostbyname(arg);
if (!he) {
fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
filename, line_num, arg);
errors++;
} else {
/* Only take the first */
acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
acl.last = acl.first;
}
get_arg(arg, sizeof(arg), &p);
if (arg[0]) {
he = gethostbyname(arg);
if (!he) {
fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
filename, line_num, arg);
errors++;
} else {
/* Only take the first */
acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
}
}
if (!errors) {
IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
IPAddressACL **naclp = 0;
*nacl = acl;
nacl->next = 0;
if (stream) {
naclp = &stream->acl;
} else if (feed) {
naclp = &feed->acl;
} else {
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);
/* XXX: av_strdup ? */
stream->rtsp_option = av_malloc(strlen(arg) + 1);
if (stream->rtsp_option) {
strcpy(stream->rtsp_option, arg);
}
}
Fabrice Bellard
committed
} else if (!strcasecmp(cmd, "MulticastAddress")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
if (!inet_aton(arg, &stream->multicast_ip)) {
fprintf(stderr, "%s:%d: Invalid IP address: %s\n",
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);
if (stream) {
stream->multicast_port = atoi(arg);
}
} else if (!strcasecmp(cmd, "MulticastTTL")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
stream->multicast_ttl = atoi(arg);
}
} else if (!strcasecmp(cmd, "NoLoop")) {
if (stream) {
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;
if (!video_enc.rc_buffer_size) {
video_enc.rc_buffer_size = 40 * 1024;
}
add_codec(stream, &video_enc);
}
}
stream = NULL;
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
} 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")) {
if (redirect) {
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 CONFIG_HAVE_DLOPEN
Fabrice Bellard
committed
load_module(arg);
#else
fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
filename, line_num, arg);
errors++;
#endif
} else {
fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
filename, line_num, cmd);
errors++;
}
}
fclose(f);
if (errors)
return -1;
else
return 0;
}
#if 0
static void write_packet(FFCodec *ffenc,
{
PacketHeader hdr;
AVCodecContext *enc = &ffenc->enc;
fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
fifo_write(&http_fifo, buf, size, &wptr);
/* atomic modification of wptr */
http_fifo.wptr = wptr;
ffenc->data_count += size;
ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
}
#endif
static void show_banner(void)
printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\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)
"This library 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"
"version 2 of the License, or (at your option) any later version.\n"
"This library 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"
"License along with this library; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
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);
if (uptime < 30) {
/* 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 */
srandom(gettime_ms() + (getpid() << 16));
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");