Commit 2ac887ba authored by Philip Gladstone's avatar Philip Gladstone

* Give the max stream time configuration item a chance of working

* Add parameters to set author/comment/copyright/title to streamed asf
* Format the stats output a little bit better.

Originally committed as revision 663 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 2824c473
...@@ -95,7 +95,7 @@ typedef struct HTTPContext { ...@@ -95,7 +95,7 @@ typedef struct HTTPContext {
int last_packet_sent; /* true if last data packet was sent */ int last_packet_sent; /* true if last data packet was sent */
int suppress_log; int suppress_log;
int bandwidth; int bandwidth;
time_t start_time; long start_time; /* In milliseconds - this wraps fairly often */
int wmp_client_id; int wmp_client_id;
char protocol[16]; char protocol[16];
char method[16]; char method[16];
...@@ -121,12 +121,16 @@ typedef struct FFStream { ...@@ -121,12 +121,16 @@ typedef struct FFStream {
AVOutputFormat *fmt; AVOutputFormat *fmt;
int nb_streams; int nb_streams;
int prebuffer; /* Number of millseconds early to start */ int prebuffer; /* Number of millseconds early to start */
time_t max_time; long max_time; /* Number of milliseconds to run */
int send_on_key; int send_on_key;
AVStream *streams[MAX_STREAMS]; AVStream *streams[MAX_STREAMS];
int feed_streams[MAX_STREAMS]; /* index of streams in the feed */ int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
char feed_filename[1024]; /* file name of the feed storage, or char feed_filename[1024]; /* file name of the feed storage, or
input file name for a stream */ input file name for a stream */
char author[512];
char title[512];
char copyright[512];
char comment[512];
pid_t pid; /* Of ffmpeg process */ pid_t pid; /* Of ffmpeg process */
char **child_argv; char **child_argv;
struct FFStream *next; struct FFStream *next;
...@@ -154,7 +158,7 @@ FFStream *first_stream; /* contains all streams, including feeds */ ...@@ -154,7 +158,7 @@ FFStream *first_stream; /* contains all streams, including feeds */
static int handle_http(HTTPContext *c, long cur_time); static int handle_http(HTTPContext *c, long cur_time);
static int http_parse_request(HTTPContext *c); static int http_parse_request(HTTPContext *c);
static int http_send_data(HTTPContext *c); static int http_send_data(HTTPContext *c, long cur_time);
static void compute_stats(HTTPContext *c); static void compute_stats(HTTPContext *c);
static int open_input_stream(HTTPContext *c, const char *info); static int open_input_stream(HTTPContext *c, const char *info);
static int http_start_receive_data(HTTPContext *c); static int http_start_receive_data(HTTPContext *c);
...@@ -162,6 +166,9 @@ static int http_receive_data(HTTPContext *c); ...@@ -162,6 +166,9 @@ static int http_receive_data(HTTPContext *c);
static const char *my_program_name; static const char *my_program_name;
static int ffserver_debug;
static int no_launch;
int nb_max_connections; int nb_max_connections;
int nb_connections; int nb_connections;
...@@ -213,6 +220,9 @@ static void log_connection(HTTPContext *c) ...@@ -213,6 +220,9 @@ static void log_connection(HTTPContext *c)
static void start_children(FFStream *feed) static void start_children(FFStream *feed)
{ {
if (no_launch)
return;
for (; feed; feed = feed->next) { for (; feed; feed = feed->next) {
if (feed->child_argv) { if (feed->child_argv) {
feed->pid = fork(); feed->pid = fork();
...@@ -227,15 +237,17 @@ static void start_children(FFStream *feed) ...@@ -227,15 +237,17 @@ static void start_children(FFStream *feed)
char *slash; char *slash;
int i; int i;
for (i = 0; i < 10; i++) { if (!ffserver_debug) {
close(i); for (i = 0; i < 10; i++) {
} close(i);
}
i = open("/dev/null", O_RDWR); i = open("/dev/null", O_RDWR);
if (i) if (i)
dup2(i, 0); dup2(i, 0);
dup2(i, 1); dup2(i, 1);
dup2(i, 2); dup2(i, 2);
}
pstrcpy(pathname, sizeof(pathname), my_program_name); pstrcpy(pathname, sizeof(pathname), my_program_name);
...@@ -404,6 +416,7 @@ static int http_server(struct sockaddr_in my_addr) ...@@ -404,6 +416,7 @@ static int http_server(struct sockaddr_in my_addr)
c->buffer_ptr = c->buffer; c->buffer_ptr = c->buffer;
c->buffer_end = c->buffer + c->buffer_size; c->buffer_end = c->buffer + c->buffer_size;
c->timeout = cur_time + REQUEST_TIMEOUT; c->timeout = cur_time + REQUEST_TIMEOUT;
c->start_time = cur_time;
nb_connections++; nb_connections++;
} }
} }
...@@ -494,7 +507,7 @@ static int handle_http(HTTPContext *c, long cur_time) ...@@ -494,7 +507,7 @@ static int handle_http(HTTPContext *c, long cur_time)
if (!(c->poll_entry->revents & POLLOUT)) if (!(c->poll_entry->revents & POLLOUT))
return 0; return 0;
if (http_send_data(c) < 0) if (http_send_data(c, cur_time) < 0)
return -1; return -1;
break; break;
case HTTPSTATE_RECEIVE_DATA: case HTTPSTATE_RECEIVE_DATA:
...@@ -1060,6 +1073,17 @@ static int http_parse_request(HTTPContext *c) ...@@ -1060,6 +1073,17 @@ static int http_parse_request(HTTPContext *c)
return 0; return 0;
} }
static int fmt_bytecount(char *q, INT64 count)
{
static const char *suffix = " kMGTP";
const char *s;
for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
}
return sprintf(q, "%lld%c", count, *s);
}
static void compute_stats(HTTPContext *c) static void compute_stats(HTTPContext *c)
{ {
HTTPContext *c1; HTTPContext *c1;
...@@ -1093,7 +1117,7 @@ static void compute_stats(HTTPContext *c) ...@@ -1093,7 +1117,7 @@ static void compute_stats(HTTPContext *c)
/* format status */ /* format status */
q += sprintf(q, "<H2>Available Streams</H2>\n"); q += sprintf(q, "<H2>Available Streams</H2>\n");
q += sprintf(q, "<TABLE cellspacing=0 cellpadding=4>\n"); q += sprintf(q, "<TABLE cellspacing=0 cellpadding=4>\n");
q += sprintf(q, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>kbytes<Th valign=top>Format<Th>Bit rate<br>kbits/s<Th align=left>Video<br>kbits/s<th><br>Codec<Th align=left>Audio<br>kbits/s<th><br>Codec<Th align=left valign=top>Feed\n"); q += sprintf(q, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>bytes<Th valign=top>Format<Th>Bit rate<br>kbits/s<Th align=left>Video<br>kbits/s<th><br>Codec<Th align=left>Audio<br>kbits/s<th><br>Codec<Th align=left valign=top>Feed\n");
stream = first_stream; stream = first_stream;
while (stream != NULL) { while (stream != NULL) {
char sfilename[1024]; char sfilename[1024];
...@@ -1112,8 +1136,9 @@ static void compute_stats(HTTPContext *c) ...@@ -1112,8 +1136,9 @@ static void compute_stats(HTTPContext *c)
q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ",
sfilename, stream->filename); sfilename, stream->filename);
q += sprintf(q, "<td align=right> %d <td align=right> %lld", q += sprintf(q, "<td align=right> %d <td align=right> ",
stream->conns_served, stream->bytes_served / 1000); stream->conns_served);
q += fmt_bytecount(q, stream->bytes_served);
switch(stream->stream_type) { switch(stream->stream_type) {
case STREAM_TYPE_LIVE: case STREAM_TYPE_LIVE:
{ {
...@@ -1286,13 +1311,14 @@ static void compute_stats(HTTPContext *c) ...@@ -1286,13 +1311,14 @@ static void compute_stats(HTTPContext *c)
i++; i++;
p = inet_ntoa(c1->from_addr.sin_addr); p = inet_ntoa(c1->from_addr.sin_addr);
q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <td align=right> %d <TD align=right> %Ld\n", q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <td align=right> %d <TD align=right> ",
i, c1->stream->filename, i, c1->stream->filename,
c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
p, p,
http_state[c1->state], http_state[c1->state],
bitrate / 1000, bitrate / 1000);
c1->data_count); q += fmt_bytecount(q, c1->data_count);
*q++ = '\n';
c1 = c1->next; c1 = c1->next;
} }
q += sprintf(q, "</TABLE>\n"); q += sprintf(q, "</TABLE>\n");
...@@ -1388,13 +1414,18 @@ static int open_input_stream(HTTPContext *c, const char *info) ...@@ -1388,13 +1414,18 @@ static int open_input_stream(HTTPContext *c, const char *info)
return 0; return 0;
} }
static int http_prepare_data(HTTPContext *c) static int http_prepare_data(HTTPContext *c, long cur_time)
{ {
int i; int i;
switch(c->state) { switch(c->state) {
case HTTPSTATE_SEND_DATA_HEADER: case HTTPSTATE_SEND_DATA_HEADER:
memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx)); memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), c->stream->author);
pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), c->stream->comment);
pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), c->stream->copyright);
pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), c->stream->title);
if (c->stream->feed) { if (c->stream->feed) {
/* open output stream by using specified codecs */ /* open output stream by using specified codecs */
c->fmt_ctx.oformat = c->stream->fmt; c->fmt_ctx.oformat = c->stream->fmt;
...@@ -1504,7 +1535,7 @@ static int http_prepare_data(HTTPContext *c) ...@@ -1504,7 +1535,7 @@ static int http_prepare_data(HTTPContext *c)
} }
if (c->stream->max_time && if (c->stream->max_time &&
c->stream->max_time + c->start_time > time(0)) { c->stream->max_time + c->start_time - cur_time < 0) {
/* We have timed out */ /* We have timed out */
c->state = HTTPSTATE_SEND_DATA_TRAILER; c->state = HTTPSTATE_SEND_DATA_TRAILER;
} else if (av_read_packet(c->fmt_in, &pkt) < 0) { } else if (av_read_packet(c->fmt_in, &pkt) < 0) {
...@@ -1591,12 +1622,12 @@ static int http_prepare_data(HTTPContext *c) ...@@ -1591,12 +1622,12 @@ static int http_prepare_data(HTTPContext *c)
} }
/* should convert the format at the same time */ /* should convert the format at the same time */
static int http_send_data(HTTPContext *c) static int http_send_data(HTTPContext *c, long cur_time)
{ {
int len, ret; int len, ret;
while (c->buffer_ptr >= c->buffer_end) { while (c->buffer_ptr >= c->buffer_end) {
ret = http_prepare_data(c); ret = http_prepare_data(c, cur_time);
if (ret < 0) if (ret < 0)
return -1; return -1;
else if (ret == 0) { else if (ret == 0) {
...@@ -2223,6 +2254,22 @@ int parse_ffconfig(const char *filename) ...@@ -2223,6 +2254,22 @@ int parse_ffconfig(const char *filename)
filename, line_num); filename, line_num);
errors++; errors++;
} }
} else if (!strcasecmp(cmd, "Author")) {
if (stream) {
get_arg(stream->author, sizeof(stream->author), &p);
}
} else if (!strcasecmp(cmd, "Comment")) {
if (stream) {
get_arg(stream->comment, sizeof(stream->comment), &p);
}
} else if (!strcasecmp(cmd, "Copyright")) {
if (stream) {
get_arg(stream->copyright, sizeof(stream->copyright), &p);
}
} else if (!strcasecmp(cmd, "Title")) {
if (stream) {
get_arg(stream->title, sizeof(stream->title), &p);
}
} else if (!strcasecmp(cmd, "Preroll")) { } else if (!strcasecmp(cmd, "Preroll")) {
get_arg(arg, sizeof(arg), &p); get_arg(arg, sizeof(arg), &p);
if (stream) { if (stream) {
...@@ -2251,7 +2298,7 @@ int parse_ffconfig(const char *filename) ...@@ -2251,7 +2298,7 @@ int parse_ffconfig(const char *filename)
} else if (!strcasecmp(cmd, "MaxTime")) { } else if (!strcasecmp(cmd, "MaxTime")) {
get_arg(arg, sizeof(arg), &p); get_arg(arg, sizeof(arg), &p);
if (stream) { if (stream) {
stream->max_time = atoi(arg); stream->max_time = atoi(arg) * 1000;
} }
} else if (!strcasecmp(cmd, "AudioBitRate")) { } else if (!strcasecmp(cmd, "AudioBitRate")) {
get_arg(arg, sizeof(arg), &p); get_arg(arg, sizeof(arg), &p);
...@@ -2470,7 +2517,7 @@ int main(int argc, char **argv) ...@@ -2470,7 +2517,7 @@ int main(int argc, char **argv)
my_program_name = argv[0]; my_program_name = argv[0];
for(;;) { for(;;) {
c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL); c = getopt_long_only(argc, argv, "ndLh?f:", NULL, NULL);
if (c == -1) if (c == -1)
break; break;
switch(c) { switch(c) {
...@@ -2481,6 +2528,12 @@ int main(int argc, char **argv) ...@@ -2481,6 +2528,12 @@ int main(int argc, char **argv)
case 'h': case 'h':
help(); help();
exit(1); exit(1);
case 'n':
no_launch = 1;
break;
case 'd':
ffserver_debug = 1;
break;
case 'f': case 'f':
config_filename = optarg; config_filename = optarg;
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment