Newer
Older
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) {
AVRational frame_rate;
if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
fprintf(stderr, "Incorrect frame rate\n");
errors++;
} else {
video_enc.time_base.num = frame_rate.den;
video_enc.time_base.den = frame_rate.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, "AVOptionVideo") ||
!strcasecmp(cmd, "AVOptionAudio")) {
char arg2[1024];
AVCodecContext *avctx;
int type;
get_arg(arg, sizeof(arg), &p);
get_arg(arg2, sizeof(arg2), &p);
if (!strcasecmp(cmd, "AVOptionVideo")) {
avctx = &video_enc;
type = AV_OPT_FLAG_VIDEO_PARAM;
} else {
avctx = &audio_enc;
type = AV_OPT_FLAG_AUDIO_PARAM;
}
if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
errors++;
}
} 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 = 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);
}
} 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 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;
}
static void opt_debug()
{
ffserver_debug = 1;
ffserver_daemon = 0;
}
static void opt_show_help(void)
{
printf("usage: ffserver [options]\n"
"Hyper fast multi format Audio/Video streaming server\n");
printf("\n");
show_help_options(options, "Main options:\n", 0, 0);
}
static const OptionDef options[] = {
{ "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
{ "version", OPT_EXIT, {(void*)show_version}, "show version" },
{ "L", OPT_EXIT, {(void*)show_license}, "show license" },
{ "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
{ "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
{ "d", 0, {(void*)opt_debug}, "enable debug mode" },
{ "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
{ NULL },
};
av_register_all();
show_banner();
my_program_dir = getcwd(0, 0);
Fabrice Bellard
committed
ffserver_daemon = 1;
parse_options(argc, argv, options, NULL);
Stefano Sabatini
committed
unsetenv("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, "a");
Fabrice Bellard
committed
if (http_server() < 0) {
fprintf(stderr, "Could not start server\n");