#endif
#include <string.h>
#include <stdlib.h>
-#include "avformat.h"
+#include "libavutil/random.h"
+#include "libavutil/avstring.h"
+#include "libavformat/avformat.h"
+#include "libavformat/network.h"
+#include "libavformat/os_support.h"
+#include "libavformat/rtp.h"
+#include "libavformat/rtsp.h"
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
#endif
#include <errno.h>
#include <sys/time.h>
#include <dlfcn.h>
#endif
-#include "network.h"
#include "version.h"
#include "ffserver.h"
-#include "random.h"
-#include "avstring.h"
#include "cmdutils.h"
#undef exit
-static const char program_name[] = "FFserver";
+const char program_name[] = "FFserver";
static const int program_birth_year = 2000;
+static const OptionDef options[];
+
/* maximum number of simultaneous HTTP connections */
#define HTTP_MAX_CONNECTIONS 2000
int conns_served;
int64_t bytes_served;
int64_t feed_max_size; /* maximum storage size, zero means unlimited */
- int64_t feed_write_index; /* current write position in feed (it wraps round) */
+ int64_t feed_write_index; /* current write position in feed (it wraps around) */
int64_t feed_size; /* current size of feed */
struct FFStream *next_feed;
} FFStream;
typedef struct FeedData {
long long data_count;
- float avg_frame_size; /* frame size averraged over last frames with exponential mean */
+ float avg_frame_size; /* frame size averaged over last frames with exponential mean */
} FeedData;
static struct sockaddr_in my_http_addr;
static const char *my_program_name;
static const char *my_program_dir;
+static const char *config_filename;
static int ffserver_debug;
static int ffserver_daemon;
static int no_launch;
/* prepare header */
if (url_open_dyn_buf(&ctx->pb) >= 0) {
av_write_trailer(ctx);
- url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+ url_close_dyn_buf(ctx->pb, &c->pb_buffer);
}
}
}
char *p;
time_t ti;
int i, len;
- ByteIOContext pb1, *pb = &pb1;
+ ByteIOContext *pb;
- if (url_open_dyn_buf(pb) < 0) {
+ if (url_open_dyn_buf(&pb) < 0) {
/* XXX: return an error ? */
c->buffer_ptr = c->buffer;
c->buffer_end = c->buffer;
char buf[128];
char input_filename[1024];
AVFormatContext *s;
- int buf_size, i;
+ int buf_size, i, ret;
int64_t stream_pos;
/* find file name */
#endif
/* open stream */
- if (av_open_input_file(&s, input_filename, c->stream->ifmt,
- buf_size, c->stream->ap_in) < 0) {
- http_log("%s not found", input_filename);
+ if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
+ buf_size, c->stream->ap_in)) < 0) {
+ http_log("could not open %s: %d\n", input_filename, ret);
return -1;
}
s->flags |= AVFMT_FLAG_GENPTS;
/* XXX: potential leak */
return -1;
}
- c->fmt_ctx.pb.is_streamed = 1;
+ c->fmt_ctx.pb->is_streamed = 1;
av_set_parameters(&c->fmt_ctx, NULL);
if (av_write_header(&c->fmt_ctx) < 0)
return -1;
- len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
+ len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
if (av_write_frame(ctx, &pkt))
c->state = HTTPSTATE_SEND_DATA_TRAILER;
- len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+ len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
c->cur_frame_bytes = len;
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
codec->frame_number++;
- if (len == 0)
+ if (len == 0) {
+ av_free_packet(&pkt);
goto redo;
+ }
}
av_free_packet(&pkt);
}
return -1;
}
av_write_trailer(ctx);
- len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
+ len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
/* RTP packets are sent inside the RTSP TCP connection */
- ByteIOContext pb1, *pb = &pb1;
+ ByteIOContext *pb;
int interleaved_index, size;
uint8_t header[4];
HTTPContext *rtsp_c;
/* if already sending something, then wait. */
if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
break;
- if (url_open_dyn_buf(pb) < 0)
+ if (url_open_dyn_buf(&pb) < 0)
goto fail1;
interleaved_index = c->packet_stream_index * 2;
/* RTCP packets are sent at odd indexes */
/* We have a header in our hands that contains useful data */
AVFormatContext s;
AVInputFormat *fmt_in;
- ByteIOContext *pb = &s.pb;
int i;
memset(&s, 0, sizeof(s));
- url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
- pb->buf_end = c->buffer_end; /* ?? */
- pb->is_streamed = 1;
+ url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
+ s.pb->is_streamed = 1;
/* use feed output format name to find corresponding input format */
fmt_in = av_find_input_format(feed->fmt->name);
char url[1024];
char protocol[32];
char line[1024];
- ByteIOContext pb1;
int len;
RTSPHeader header1, *header = &header1;
av_strlcpy(c->url, url, sizeof(c->url));
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
- c->pb = &pb1;
- if (url_open_dyn_buf(c->pb) < 0) {
+ if (url_open_dyn_buf(&c->pb) < 0) {
/* XXX: cannot do more */
c->pb = NULL; /* safety */
return -1;
av_free(ctx);
return -1;
}
- url_close_dyn_buf(&ctx->pb, &dummy_buf);
+ url_close_dyn_buf(ctx->pb, &dummy_buf);
av_free(dummy_buf);
c->rtp_ctx[stream_index] = ctx;
{
FFStream *stream, *stream_next;
AVFormatContext *infile;
- int i;
+ int i, ret;
/* gather all streams */
for(stream = first_stream; stream != NULL; stream = stream_next) {
stream->ap_in->mpeg2ts_compute_pcr = 1;
}
- if (av_open_input_file(&infile, stream->feed_filename,
- stream->ifmt, 0, stream->ap_in) < 0) {
- http_log("%s not found", stream->feed_filename);
+ if ((ret = av_open_input_file(&infile, stream->feed_filename,
+ stream->ifmt, 0, stream->ap_in)) < 0) {
+ http_log("could not open %s: %d\n", stream->feed_filename, ret);
/* remove stream (no need to spend more time on it) */
fail:
remove_stream(stream);
}
/* XXX: need better api */
av_freep(&s->priv_data);
- url_fclose(&s->pb);
+ url_fclose(s->pb);
}
/* get feed size and write index */
fd = open(feed->feed_filename, O_RDONLY);
}
/* Bitrate tolerance is less for streaming */
if (av->bit_rate_tolerance == 0)
- av->bit_rate_tolerance = av->bit_rate / 4;
+ av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
+ (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
if (av->qmin == 0)
av->qmin = 3;
if (av->qmax == 0)
static int opt_audio_codec(const char *arg)
{
- AVCodec *p;
+ AVCodec *p= avcodec_find_encoder_by_name(arg);
- p = first_avcodec;
- while (p) {
- if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
- break;
- p = p->next;
- }
- if (p == NULL)
+ if (p == NULL || p->type != CODEC_TYPE_AUDIO)
return CODEC_ID_NONE;
return p->id;
static int opt_video_codec(const char *arg)
{
- AVCodec *p;
+ AVCodec *p= avcodec_find_encoder_by_name(arg);
- p = first_avcodec;
- while (p) {
- if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
- break;
- p = p->next;
- }
- if (p == NULL)
+ if (p == NULL || p->type != CODEC_TYPE_VIDEO)
return CODEC_ID_NONE;
return p->id;
if (feed) {
int i;
- feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
+ feed->child_argv = av_mallocz(64 * sizeof(char *));
for (i = 0; i < 62; i++) {
get_arg(arg, sizeof(arg), &p);
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
} else if (!strcasecmp(cmd, "FileMaxSize")) {
if (feed) {
- const char *p1;
+ char *p1;
double fsize;
get_arg(arg, sizeof(arg), &p);
p1 = arg;
- fsize = strtod(p1, (char **)&p1);
+ fsize = strtod(p1, &p1);
switch(toupper(*p1)) {
case 'K':
fsize *= 1024;
}
if (!errors) {
- IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
+ IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
IPAddressACL **naclp = 0;
acl.next = 0;
return 0;
}
-static void show_help(void)
-{
- show_banner(program_name, program_birth_year);
- printf("usage: ffserver [-L] [-h] [-f configfile]\n"
- "Hyper fast multi format Audio/Video streaming server\n"
- "\n"
- "-L : print the LICENSE\n"
- "-h : this help\n"
- "-f configfile : use configfile instead of /etc/ffserver.conf\n"
- );
-}
-
static void handle_child_exit(int sig)
{
pid_t pid;
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 },
+};
+
int main(int argc, char **argv)
{
- const char *config_filename;
- int c;
struct sigaction sigact;
av_register_all();
my_program_dir = getcwd(0, 0);
ffserver_daemon = 1;
- for(;;) {
- c = getopt(argc, argv, "ndLh?f:");
- if (c == -1)
- break;
- switch(c) {
- case 'L':
- show_banner(program_name, program_birth_year);
- show_license();
- exit(0);
- case '?':
- case 'h':
- show_help();
- exit(0);
- case 'n':
- no_launch = 1;
- break;
- case 'd':
- ffserver_debug = 1;
- ffserver_daemon = 0;
- break;
- case 'f':
- config_filename = optarg;
- break;
- default:
- exit(2);
- }
- }
+ parse_options(argc, argv, options, NULL);
putenv("http_proxy"); /* Kill the http_proxy */
if (!strcmp(logfilename, "-"))
logfile = stdout;
else
- logfile = fopen(logfilename, "w");
+ logfile = fopen(logfilename, "a");
}
if (http_server() < 0) {