* Added yet more output to the status page to try and track down a problem
[ffmpeg.git] / ffserver.c
1 /*
2  * Multiple format streaming server
3  * Copyright (c) 2000, 2001, 2002 Gerard Lantau.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <netinet/in.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/ioctl.h>
27 #include <sys/poll.h>
28 #include <errno.h>
29 #include <sys/time.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #include <ctype.h>
37 #include <signal.h>
38 #include <assert.h>
39
40 #include "bswap.h" // needed for the bitstream writer in common.h which is included in avformat.h
41 #include "avformat.h"
42
43 /* maximum number of simultaneous HTTP connections */
44 #define HTTP_MAX_CONNECTIONS 2000
45
46 enum HTTPState {
47     HTTPSTATE_WAIT_REQUEST,
48     HTTPSTATE_SEND_HEADER,
49     HTTPSTATE_SEND_DATA_HEADER,
50     HTTPSTATE_SEND_DATA,
51     HTTPSTATE_SEND_DATA_TRAILER,
52     HTTPSTATE_RECEIVE_DATA,
53     HTTPSTATE_WAIT_FEED,
54 };
55
56 const char *http_state[] = {
57     "WAIT_REQUEST",
58     "SEND_HEADER",
59     "SEND_DATA_HEADER",
60     "SEND_DATA",
61     "SEND_DATA_TRAILER",
62     "RECEIVE_DATA",
63     "WAIT_FEED",
64 };
65
66 #define IOBUFFER_MAX_SIZE 32768
67 #define PACKET_MAX_SIZE 16384
68
69 /* coef for exponential mean for bitrate estimation in statistics */
70 #define AVG_COEF 0.9
71
72 /* timeouts are in ms */
73 #define REQUEST_TIMEOUT (15 * 1000)
74 #define SYNC_TIMEOUT (10 * 1000)
75
76 /* context associated with one connection */
77 typedef struct HTTPContext {
78     enum HTTPState state;
79     int fd; /* socket file descriptor */
80     struct sockaddr_in from_addr; /* origin */
81     struct pollfd *poll_entry; /* used when polling */
82     long timeout;
83     UINT8 *buffer_ptr, *buffer_end;
84     int http_error;
85     struct HTTPContext *next;
86     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
87     INT64 data_count;
88     /* feed input */
89     int feed_fd;
90     /* input format handling */
91     AVFormatContext *fmt_in;
92     /* output format handling */
93     struct FFStream *stream;
94     AVFormatContext fmt_ctx;
95     int last_packet_sent; /* true if last data packet was sent */
96     int suppress_log;
97     int bandwidth;
98     time_t start_time;
99     char protocol[16];
100     char method[16];
101     char url[128];
102     UINT8 buffer[IOBUFFER_MAX_SIZE];
103     UINT8 pbuffer[PACKET_MAX_SIZE];
104 } HTTPContext;
105
106 /* each generated stream is described here */
107 enum StreamType {
108     STREAM_TYPE_LIVE,
109     STREAM_TYPE_STATUS,
110 };
111
112 /* description of each stream of the ffserver.conf file */
113 typedef struct FFStream {
114     enum StreamType stream_type;
115     char filename[1024];     /* stream filename */
116     struct FFStream *feed;
117     AVOutputFormat *fmt;
118     int nb_streams;
119     int prebuffer;      /* Number of millseconds early to start */
120     time_t max_time;
121     int send_on_key;
122     AVStream *streams[MAX_STREAMS];
123     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
124     char feed_filename[1024]; /* file name of the feed storage, or
125                                  input file name for a stream */
126     struct FFStream *next;
127     /* feed specific */
128     int feed_opened;     /* true if someone if writing to feed */
129     int is_feed;         /* true if it is a feed */
130     int conns_served;
131     INT64 bytes_served;
132     INT64 feed_max_size;      /* maximum storage size */
133     INT64 feed_write_index;   /* current write position in feed (it wraps round) */
134     INT64 feed_size;          /* current size of feed */
135     struct FFStream *next_feed;
136 } FFStream;
137
138 typedef struct FeedData {
139     long long data_count;
140     float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
141 } FeedData;
142
143 struct sockaddr_in my_addr;
144 char logfilename[1024];
145 HTTPContext *first_http_ctx;
146 FFStream *first_feed;   /* contains only feeds */
147 FFStream *first_stream; /* contains all streams, including feeds */
148
149 static int handle_http(HTTPContext *c, long cur_time);
150 static int http_parse_request(HTTPContext *c);
151 static int http_send_data(HTTPContext *c);
152 static void compute_stats(HTTPContext *c);
153 static int open_input_stream(HTTPContext *c, const char *info);
154 static int http_start_receive_data(HTTPContext *c);
155 static int http_receive_data(HTTPContext *c);
156
157 int nb_max_connections;
158 int nb_connections;
159
160 int nb_max_bandwidth;
161 int nb_bandwidth;
162
163 static long gettime_ms(void)
164 {
165     struct timeval tv;
166
167     gettimeofday(&tv,NULL);
168     return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
169 }
170
171 static FILE *logfile = NULL;
172
173 static void http_log(char *fmt, ...)
174 {
175     va_list ap;
176     va_start(ap, fmt);
177     
178     if (logfile) {
179         vfprintf(logfile, fmt, ap);
180         fflush(logfile);
181     }
182     va_end(ap);
183 }
184
185 static void log_connection(HTTPContext *c)
186 {
187     char buf1[32], buf2[32], *p;
188     time_t ti;
189
190     if (c->suppress_log) 
191         return;
192
193     /* XXX: reentrant function ? */
194     p = inet_ntoa(c->from_addr.sin_addr);
195     strcpy(buf1, p);
196     ti = time(NULL);
197     p = ctime(&ti);
198     strcpy(buf2, p);
199     p = buf2 + strlen(p) - 1;
200     if (*p == '\n')
201         *p = '\0';
202     http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
203              buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
204 }
205
206 /* main loop of the http server */
207 static int http_server(struct sockaddr_in my_addr)
208 {
209     int server_fd, tmp, ret;
210     struct sockaddr_in from_addr;
211     struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
212     HTTPContext *c, **cp;
213     long cur_time;
214
215     server_fd = socket(AF_INET,SOCK_STREAM,0);
216     if (server_fd < 0) {
217         perror ("socket");
218         return -1;
219     }
220         
221     tmp = 1;
222     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
223
224     if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
225         perror ("bind");
226         close(server_fd);
227         return -1;
228     }
229   
230     if (listen (server_fd, 5) < 0) {
231         perror ("listen");
232         close(server_fd);
233         return -1;
234     }
235
236     http_log("ffserver started.\n");
237
238     fcntl(server_fd, F_SETFL, O_NONBLOCK);
239     first_http_ctx = NULL;
240     nb_connections = 0;
241     first_http_ctx = NULL;
242     for(;;) {
243         poll_entry = poll_table;
244         poll_entry->fd = server_fd;
245         poll_entry->events = POLLIN;
246         poll_entry++;
247
248         /* wait for events on each HTTP handle */
249         c = first_http_ctx;
250         while (c != NULL) {
251             int fd;
252             fd = c->fd;
253             switch(c->state) {
254             case HTTPSTATE_WAIT_REQUEST:
255                 c->poll_entry = poll_entry;
256                 poll_entry->fd = fd;
257                 poll_entry->events = POLLIN;
258                 poll_entry++;
259                 break;
260             case HTTPSTATE_SEND_HEADER:
261             case HTTPSTATE_SEND_DATA_HEADER:
262             case HTTPSTATE_SEND_DATA:
263             case HTTPSTATE_SEND_DATA_TRAILER:
264                 c->poll_entry = poll_entry;
265                 poll_entry->fd = fd;
266                 poll_entry->events = POLLOUT;
267                 poll_entry++;
268                 break;
269             case HTTPSTATE_RECEIVE_DATA:
270                 c->poll_entry = poll_entry;
271                 poll_entry->fd = fd;
272                 poll_entry->events = POLLIN;
273                 poll_entry++;
274                 break;
275             case HTTPSTATE_WAIT_FEED:
276                 /* need to catch errors */
277                 c->poll_entry = poll_entry;
278                 poll_entry->fd = fd;
279                 poll_entry->events = POLLIN;/* Maybe this will work */
280                 poll_entry++;
281                 break;
282             default:
283                 c->poll_entry = NULL;
284                 break;
285             }
286             c = c->next;
287         }
288
289         /* wait for an event on one connection. We poll at least every
290            second to handle timeouts */
291         do {
292             ret = poll(poll_table, poll_entry - poll_table, 1000);
293         } while (ret == -1);
294         
295         cur_time = gettime_ms();
296
297         /* now handle the events */
298
299         cp = &first_http_ctx;
300         while ((*cp) != NULL) {
301             c = *cp;
302             if (handle_http (c, cur_time) < 0) {
303                 /* close and free the connection */
304                 log_connection(c);
305                 close(c->fd);
306                 if (c->fmt_in)
307                     av_close_input_file(c->fmt_in);
308                 *cp = c->next;
309                 nb_bandwidth -= c->bandwidth;
310                 av_free(c);
311                 nb_connections--;
312             } else {
313                 cp = &c->next;
314             }
315         }
316
317         /* new connection request ? */
318         poll_entry = poll_table;
319         if (poll_entry->revents & POLLIN) {
320             int fd, len;
321
322             len = sizeof(from_addr);
323             fd = accept(server_fd, (struct sockaddr *)&from_addr, 
324                         &len);
325             if (fd >= 0) {
326                 fcntl(fd, F_SETFL, O_NONBLOCK);
327                 /* XXX: should output a warning page when coming
328                    close to the connection limit */
329                 if (nb_connections >= nb_max_connections) {
330                     close(fd);
331                 } else {
332                     /* add a new connection */
333                     c = av_mallocz(sizeof(HTTPContext));
334                     c->next = first_http_ctx;
335                     first_http_ctx = c;
336                     c->fd = fd;
337                     c->poll_entry = NULL;
338                     c->from_addr = from_addr;
339                     c->state = HTTPSTATE_WAIT_REQUEST;
340                     c->buffer_ptr = c->buffer;
341                     c->buffer_end = c->buffer + IOBUFFER_MAX_SIZE;
342                     c->timeout = cur_time + REQUEST_TIMEOUT;
343                     nb_connections++;
344                 }
345             }
346         }
347         poll_entry++;
348     }
349 }
350
351 static int handle_http(HTTPContext *c, long cur_time)
352 {
353     int len;
354     
355     switch(c->state) {
356     case HTTPSTATE_WAIT_REQUEST:
357         /* timeout ? */
358         if ((c->timeout - cur_time) < 0)
359             return -1;
360         if (c->poll_entry->revents & (POLLERR | POLLHUP))
361             return -1;
362
363         /* no need to read if no events */
364         if (!(c->poll_entry->revents & POLLIN))
365             return 0;
366         /* read the data */
367         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
368         if (len < 0) {
369             if (errno != EAGAIN && errno != EINTR)
370                 return -1;
371         } else if (len == 0) {
372             return -1;
373         } else {
374             /* search for end of request. XXX: not fully correct since garbage could come after the end */
375             UINT8 *ptr;
376             c->buffer_ptr += len;
377             ptr = c->buffer_ptr;
378             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
379                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
380                 /* request found : parse it and reply */
381                 if (http_parse_request(c) < 0)
382                     return -1;
383             } else if (ptr >= c->buffer_end) {
384                 /* request too long: cannot do anything */
385                 return -1;
386             }
387         }
388         break;
389
390     case HTTPSTATE_SEND_HEADER:
391         if (c->poll_entry->revents & (POLLERR | POLLHUP))
392             return -1;
393
394         /* no need to read if no events */
395         if (!(c->poll_entry->revents & POLLOUT))
396             return 0;
397         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
398         if (len < 0) {
399             if (errno != EAGAIN && errno != EINTR) {
400                 /* error : close connection */
401                 return -1;
402             }
403         } else {
404             c->buffer_ptr += len;
405             if (c->stream)
406                 c->stream->bytes_served += len;
407             c->data_count += len;
408             if (c->buffer_ptr >= c->buffer_end) {
409                 /* if error, exit */
410                 if (c->http_error)
411                     return -1;
412                 /* all the buffer was send : synchronize to the incoming stream */
413                 c->state = HTTPSTATE_SEND_DATA_HEADER;
414                 c->buffer_ptr = c->buffer_end = c->buffer;
415             }
416         }
417         break;
418
419     case HTTPSTATE_SEND_DATA:
420     case HTTPSTATE_SEND_DATA_HEADER:
421     case HTTPSTATE_SEND_DATA_TRAILER:
422         /* no need to read if no events */
423         if (c->poll_entry->revents & (POLLERR | POLLHUP))
424             return -1;
425         
426         if (!(c->poll_entry->revents & POLLOUT))
427             return 0;
428         if (http_send_data(c) < 0)
429             return -1;
430         break;
431     case HTTPSTATE_RECEIVE_DATA:
432         /* no need to read if no events */
433         if (c->poll_entry->revents & (POLLERR | POLLHUP))
434             return -1;
435         if (!(c->poll_entry->revents & POLLIN))
436             return 0;
437         if (http_receive_data(c) < 0)
438             return -1;
439         break;
440     case HTTPSTATE_WAIT_FEED:
441         /* no need to read if no events */
442         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
443             return -1;
444
445         /* nothing to do, we'll be waken up by incoming feed packets */
446         break;
447     default:
448         return -1;
449     }
450     return 0;
451 }
452
453
454 /* parse http request and prepare header */
455 static int http_parse_request(HTTPContext *c)
456 {
457     char *p;
458     int post;
459     int doing_asx;
460     int doing_ram;
461     char cmd[32];
462     char info[1024], *filename;
463     char url[1024], *q;
464     char protocol[32];
465     char msg[1024];
466     const char *mime_type;
467     FFStream *stream;
468     int i;
469
470     p = c->buffer;
471     q = cmd;
472     while (!isspace(*p) && *p != '\0') {
473         if ((q - cmd) < sizeof(cmd) - 1)
474             *q++ = *p;
475         p++;
476     }
477     *q = '\0';
478
479     pstrcpy(c->method, sizeof(c->method), cmd);
480
481     if (!strcmp(cmd, "GET"))
482         post = 0;
483     else if (!strcmp(cmd, "POST"))
484         post = 1;
485     else
486         return -1;
487
488     while (isspace(*p)) p++;
489     q = url;
490     while (!isspace(*p) && *p != '\0') {
491         if ((q - url) < sizeof(url) - 1)
492             *q++ = *p;
493         p++;
494     }
495     *q = '\0';
496
497     pstrcpy(c->url, sizeof(c->url), url);
498
499     while (isspace(*p)) p++;
500     q = protocol;
501     while (!isspace(*p) && *p != '\0') {
502         if ((q - protocol) < sizeof(protocol) - 1)
503             *q++ = *p;
504         p++;
505     }
506     *q = '\0';
507     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
508         return -1;
509
510     pstrcpy(c->protocol, sizeof(c->protocol), protocol);
511     
512     /* find the filename and the optional info string in the request */
513     p = url;
514     if (*p == '/')
515         p++;
516     filename = p;
517     p = strchr(p, '?');
518     if (p) {
519         pstrcpy(info, sizeof(info), p);
520         *p = '\0';
521     } else {
522         info[0] = '\0';
523     }
524
525     if (strlen(filename) > 4 && strcmp(".asx", filename + strlen(filename) - 4) == 0) {
526         doing_asx = 1;
527         filename[strlen(filename)-1] = 'f';
528     } else {
529         doing_asx = 0;
530     }
531
532     if (strlen(filename) > 4 && 
533         (strcmp(".rpm", filename + strlen(filename) - 4) == 0 ||
534          strcmp(".ram", filename + strlen(filename) - 4) == 0)) {
535         doing_ram = 1;
536         strcpy(filename + strlen(filename)-2, "m");
537     } else {
538         doing_ram = 0;
539     }
540
541     stream = first_stream;
542     while (stream != NULL) {
543         if (!strcmp(stream->filename, filename))
544             break;
545         stream = stream->next;
546     }
547     if (stream == NULL) {
548         sprintf(msg, "File '%s' not found", url);
549         goto send_error;
550     }
551
552     if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
553         /* See if we meet the bandwidth requirements */
554         for(i=0;i<stream->nb_streams;i++) {
555             AVStream *st = stream->streams[i];
556             switch(st->codec.codec_type) {
557             case CODEC_TYPE_AUDIO:
558                 c->bandwidth += st->codec.bit_rate;
559                 break;
560             case CODEC_TYPE_VIDEO:
561                 c->bandwidth += st->codec.bit_rate;
562                 break;
563             default:
564                 av_abort();
565             }
566         }
567     }
568
569     c->bandwidth /= 1000;
570     nb_bandwidth += c->bandwidth;
571
572     if (post == 0 && nb_max_bandwidth < nb_bandwidth) {
573         c->http_error = 200;
574         q = c->buffer;
575         q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
576         q += sprintf(q, "Content-type: text/html\r\n");
577         q += sprintf(q, "\r\n");
578         q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
579         q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
580         q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
581             nb_bandwidth, nb_max_bandwidth);
582         q += sprintf(q, "</body></html>\r\n");
583
584         /* prepare output buffer */
585         c->buffer_ptr = c->buffer;
586         c->buffer_end = q;
587         c->state = HTTPSTATE_SEND_HEADER;
588         return 0;
589     }
590     
591     if (doing_asx || doing_ram) {
592         char *hostinfo = 0;
593         
594         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
595             if (strncasecmp(p, "Host:", 5) == 0) {
596                 hostinfo = p + 5;
597                 break;
598             }
599             p = strchr(p, '\n');
600             if (!p)
601                 break;
602
603             p++;
604         }
605
606         if (hostinfo) {
607             char *eoh;
608             char hostbuf[260];
609
610             while (isspace(*hostinfo))
611                 hostinfo++;
612
613             eoh = strchr(hostinfo, '\n');
614             if (eoh) {
615                 if (eoh[-1] == '\r')
616                     eoh--;
617
618                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
619                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
620                     hostbuf[eoh - hostinfo] = 0;
621
622                     c->http_error = 200;
623                     q = c->buffer;
624                     if (doing_asx) {
625                         q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
626                         q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
627                         q += sprintf(q, "\r\n");
628                         q += sprintf(q, "<ASX Version=\"3\">\r\n");
629                         q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
630                         q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", 
631                                 hostbuf, filename, info);
632                         q += sprintf(q, "</ASX>\r\n");
633                     } else if (doing_ram) {
634                         q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
635                         q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
636                         q += sprintf(q, "\r\n");
637                         q += sprintf(q, "# Autogenerated by ffserver\r\n");
638                         q += sprintf(q, "http://%s/%s%s\r\n", 
639                                 hostbuf, filename, info);
640                     } else
641                         av_abort();
642
643                     /* prepare output buffer */
644                     c->buffer_ptr = c->buffer;
645                     c->buffer_end = q;
646                     c->state = HTTPSTATE_SEND_HEADER;
647                     return 0;
648                 }
649             }
650         }
651
652         sprintf(msg, "ASX/RAM file not handled");
653         goto send_error;
654     }
655
656     c->stream = stream;
657     stream->conns_served++;
658
659     /* XXX: add there authenticate and IP match */
660
661     if (post) {
662         /* if post, it means a feed is being sent */
663         if (!stream->is_feed) {
664             /* However it might be a status report from WMP! Lets log the data
665              * as it might come in handy one day
666              */
667             char *logline = 0;
668             
669             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
670                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
671                     logline = p;
672                     break;
673                 }
674                 p = strchr(p, '\n');
675                 if (!p)
676                     break;
677
678                 p++;
679             }
680
681             if (logline) {
682                 char *eol = strchr(logline, '\n');
683
684                 logline += 17;
685
686                 if (eol) {
687                     if (eol[-1] == '\r')
688                         eol--;
689                     http_log("%.*s\n", eol - logline, logline);
690                     c->suppress_log = 1;
691                 }
692             }
693             
694             sprintf(msg, "POST command not handled");
695             goto send_error;
696         }
697         if (http_start_receive_data(c) < 0) {
698             sprintf(msg, "could not open feed");
699             goto send_error;
700         }
701         c->http_error = 0;
702         c->state = HTTPSTATE_RECEIVE_DATA;
703         return 0;
704     }
705
706     if (c->stream->stream_type == STREAM_TYPE_STATUS)
707         goto send_stats;
708
709     /* open input stream */
710     if (open_input_stream(c, info) < 0) {
711         sprintf(msg, "Input stream corresponding to '%s' not found", url);
712         goto send_error;
713     }
714
715     /* prepare http header */
716     q = c->buffer;
717     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
718     mime_type = c->stream->fmt->mime_type;
719     if (!mime_type)
720         mime_type = "application/x-octet_stream";
721     q += sprintf(q, "Pragma: no-cache\r\n");
722
723     /* for asf, we need extra headers */
724     if (!strcmp(c->stream->fmt->name,"asf")) {
725         q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=1234\r\nPragma: features=\"broadcast\"\r\n");
726         /* mime_type = "application/octet-stream"; */
727         /* video/x-ms-asf seems better -- netscape doesn't crash any more! */
728         mime_type = "video/x-ms-asf";
729     }
730     q += sprintf(q, "Content-Type: %s\r\n", mime_type);
731     q += sprintf(q, "\r\n");
732     
733     /* prepare output buffer */
734     c->http_error = 0;
735     c->buffer_ptr = c->buffer;
736     c->buffer_end = q;
737     c->state = HTTPSTATE_SEND_HEADER;
738     return 0;
739  send_error:
740     c->http_error = 404;
741     q = c->buffer;
742     q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
743     q += sprintf(q, "Content-type: %s\r\n", "text/html");
744     q += sprintf(q, "\r\n");
745     q += sprintf(q, "<HTML>\n");
746     q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
747     q += sprintf(q, "<BODY>%s</BODY>\n", msg);
748     q += sprintf(q, "</HTML>\n");
749
750     /* prepare output buffer */
751     c->buffer_ptr = c->buffer;
752     c->buffer_end = q;
753     c->state = HTTPSTATE_SEND_HEADER;
754     return 0;
755  send_stats:
756     compute_stats(c);
757     c->http_error = 200; /* horrible : we use this value to avoid
758                             going to the send data state */
759     c->state = HTTPSTATE_SEND_HEADER;
760     return 0;
761 }
762
763 static void compute_stats(HTTPContext *c)
764 {
765     HTTPContext *c1;
766     FFStream *stream;
767     char *q, *p;
768     time_t ti;
769     int i;
770
771     q = c->buffer;
772     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
773     q += sprintf(q, "Content-type: %s\r\n", "text/html");
774     q += sprintf(q, "Pragma: no-cache\r\n");
775     q += sprintf(q, "\r\n");
776     
777     q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE></HEAD>\n<BODY>");
778     q += sprintf(q, "<H1>FFServer Status</H1>\n");
779     /* format status */
780     q += sprintf(q, "<H2>Available Streams</H2>\n");
781     q += sprintf(q, "<TABLE cellspacing=0 cellpadding=4>\n");
782     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");
783     stream = first_stream;
784     while (stream != NULL) {
785         char sfilename[1024];
786         char *eosf;
787
788         if (stream->feed != stream) {
789             pstrcpy(sfilename, sizeof(sfilename) - 1, stream->filename);
790             eosf = sfilename + strlen(sfilename);
791             if (eosf - sfilename >= 4) {
792                 if (strcmp(eosf - 4, ".asf") == 0) {
793                     strcpy(eosf - 4, ".asx");
794                 } else if (strcmp(eosf - 3, ".rm") == 0) {
795                     strcpy(eosf - 3, ".ram");
796                 }
797             }
798             
799             q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
800                          sfilename, stream->filename);
801             q += sprintf(q, "<td align=right> %d <td align=right> %lld",
802                         stream->conns_served, stream->bytes_served / 1000);
803             switch(stream->stream_type) {
804             case STREAM_TYPE_LIVE:
805                 {
806                     int audio_bit_rate = 0;
807                     int video_bit_rate = 0;
808                     char *audio_codec_name = "";
809                     char *video_codec_name = "";
810                     char *audio_codec_name_extra = "";
811                     char *video_codec_name_extra = "";
812
813                     for(i=0;i<stream->nb_streams;i++) {
814                         AVStream *st = stream->streams[i];
815                         AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
816                         switch(st->codec.codec_type) {
817                         case CODEC_TYPE_AUDIO:
818                             audio_bit_rate += st->codec.bit_rate;
819                             if (codec) {
820                                 if (*audio_codec_name)
821                                     audio_codec_name_extra = "...";
822                                 audio_codec_name = codec->name;
823                             }
824                             break;
825                         case CODEC_TYPE_VIDEO:
826                             video_bit_rate += st->codec.bit_rate;
827                             if (codec) {
828                                 if (*video_codec_name)
829                                     video_codec_name_extra = "...";
830                                 video_codec_name = codec->name;
831                             }
832                             break;
833                         default:
834                             av_abort();
835                         }
836                     }
837                     q += sprintf(q, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s", 
838                                  stream->fmt->name,
839                                  (audio_bit_rate + video_bit_rate) / 1000,
840                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
841                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
842                     if (stream->feed) {
843                         q += sprintf(q, "<TD>%s", stream->feed->filename);
844                     } else {
845                         q += sprintf(q, "<TD>%s", stream->feed_filename);
846                     }
847                     q += sprintf(q, "\n");
848                 }
849                 break;
850             default:
851                 q += sprintf(q, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
852                 break;
853             }
854         }
855         stream = stream->next;
856     }
857     q += sprintf(q, "</TABLE>\n");
858
859     stream = first_stream;
860     while (stream != NULL) {
861         if (stream->feed == stream) {
862             q += sprintf(q, "<h2>Feed %s</h2>", stream->filename);
863             q += sprintf(q, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
864
865             for (i = 0; i < stream->nb_streams; i++) {
866                 AVStream *st = stream->streams[i];
867                 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
868                 char *type = "unknown";
869                 char parameters[64];
870
871                 parameters[0] = 0;
872
873                 switch(st->codec.codec_type) {
874                 case CODEC_TYPE_AUDIO:
875                     type = "audio";
876                     break;
877                 case CODEC_TYPE_VIDEO:
878                     type = "video";
879                     sprintf(parameters, "%dx%d, q=%d-%d", st->codec.width, st->codec.height,
880                                 st->codec.qmin, st->codec.qmax);
881                     break;
882                 default:
883                     av_abort();
884                 }
885                 q += sprintf(q, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
886                         i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
887             }
888             q += sprintf(q, "</table>\n");
889
890         }       
891         stream = stream->next;
892     }
893     
894 #if 0
895     {
896         float avg;
897         AVCodecContext *enc;
898         char buf[1024];
899         
900         /* feed status */
901         stream = first_feed;
902         while (stream != NULL) {
903             q += sprintf(q, "<H1>Feed '%s'</H1>\n", stream->filename);
904             q += sprintf(q, "<TABLE>\n");
905             q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
906             for(i=0;i<stream->nb_streams;i++) {
907                 AVStream *st = stream->streams[i];
908                 FeedData *fdata = st->priv_data;
909                 enc = &st->codec;
910             
911                 avcodec_string(buf, sizeof(buf), enc);
912                 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
913                 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
914                     avg /= enc->frame_size;
915                 q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
916                              buf, enc->frame_number, fdata->data_count, avg / 1000.0);
917             }
918             q += sprintf(q, "</TABLE>\n");
919             stream = stream->next_feed;
920         }
921     }
922 #endif
923
924     /* connection status */
925     q += sprintf(q, "<H2>Connection Status</H2>\n");
926
927     q += sprintf(q, "Number of connections: %d / %d<BR>\n",
928                  nb_connections, nb_max_connections);
929
930     q += sprintf(q, "Bandwidth in use: %dk / %dk<BR>\n",
931                  nb_bandwidth, nb_max_bandwidth);
932
933     q += sprintf(q, "<TABLE>\n");
934     q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n");
935     c1 = first_http_ctx;
936     i = 0;
937     while (c1 != NULL && q < (char *) c->buffer + sizeof(c->buffer) - 2048) {
938         i++;
939         p = inet_ntoa(c1->from_addr.sin_addr);
940         q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <TD> %Ld\n", 
941                      i, c1->stream->filename, 
942                      c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
943                      p, 
944                      http_state[c1->state],
945                      c1->data_count);
946         c1 = c1->next;
947     }
948     q += sprintf(q, "</TABLE>\n");
949     
950     /* date */
951     ti = time(NULL);
952     p = ctime(&ti);
953     q += sprintf(q, "<HR size=1 noshade>Generated at %s", p);
954     q += sprintf(q, "</BODY>\n</HTML>\n");
955
956     c->buffer_ptr = c->buffer;
957     c->buffer_end = q;
958 }
959
960
961 static void http_write_packet(void *opaque, 
962                               unsigned char *buf, int size)
963 {
964     HTTPContext *c = opaque;
965
966     if (c->buffer_ptr == c->buffer_end || !c->buffer_ptr)
967         c->buffer_ptr = c->buffer_end = c->buffer;
968
969     if (c->buffer_end - c->buffer + size > IOBUFFER_MAX_SIZE)
970         av_abort();
971
972     memcpy(c->buffer_end, buf, size);
973     c->buffer_end += size;
974 }
975
976 static int open_input_stream(HTTPContext *c, const char *info)
977 {
978     char buf[128];
979     char input_filename[1024];
980     AVFormatContext *s;
981     int buf_size;
982     INT64 stream_pos;
983
984     /* find file name */
985     if (c->stream->feed) {
986         strcpy(input_filename, c->stream->feed->feed_filename);
987         buf_size = FFM_PACKET_SIZE;
988         /* compute position (absolute time) */
989         if (find_info_tag(buf, sizeof(buf), "date", info)) {
990             stream_pos = parse_date(buf, 0);
991         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
992             int prebuffer = strtol(buf, 0, 10);
993             stream_pos = gettime() - prebuffer * 1000000;
994         } else {
995             stream_pos = gettime() - c->stream->prebuffer * 1000;
996         }
997     } else {
998         strcpy(input_filename, c->stream->feed_filename);
999         buf_size = 0;
1000         /* compute position (relative time) */
1001         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1002             stream_pos = parse_date(buf, 1);
1003         } else {
1004             stream_pos = 0;
1005         }
1006     }
1007     if (input_filename[0] == '\0')
1008         return -1;
1009
1010     /* open stream */
1011     if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0)
1012         return -1;
1013     c->fmt_in = s;
1014
1015     if (c->fmt_in->iformat->read_seek) {
1016         c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
1017     }
1018     
1019     //    printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
1020     return 0;
1021 }
1022
1023 static int http_prepare_data(HTTPContext *c)
1024 {
1025     int i;
1026
1027     switch(c->state) {
1028     case HTTPSTATE_SEND_DATA_HEADER:
1029         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1030         if (c->stream->feed) {
1031             /* open output stream by using specified codecs */
1032             c->fmt_ctx.oformat = c->stream->fmt;
1033             c->fmt_ctx.nb_streams = c->stream->nb_streams;
1034             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1035                 AVStream *st;
1036                 st = av_mallocz(sizeof(AVStream));
1037                 c->fmt_ctx.streams[i] = st;
1038                 if (c->stream->feed == c->stream)
1039                     memcpy(st, c->stream->streams[i], sizeof(AVStream));
1040                 else
1041                     memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]], sizeof(AVStream));
1042
1043                 st->codec.frame_number = 0; /* XXX: should be done in
1044                                                AVStream, not in codec */
1045             }
1046             c->got_key_frame = 0;
1047         } else {
1048             /* open output stream by using codecs in specified file */
1049             c->fmt_ctx.oformat = c->stream->fmt;
1050             c->fmt_ctx.nb_streams = c->fmt_in->nb_streams;
1051             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1052                 AVStream *st;
1053                 st = av_mallocz(sizeof(AVStream));
1054                 c->fmt_ctx.streams[i] = st;
1055                 memcpy(st, c->fmt_in->streams[i], sizeof(AVStream));
1056                 st->codec.frame_number = 0; /* XXX: should be done in
1057                                                AVStream, not in codec */
1058             }
1059             c->got_key_frame = 0;
1060         }
1061         init_put_byte(&c->fmt_ctx.pb, c->pbuffer, PACKET_MAX_SIZE,
1062                       1, c, NULL, http_write_packet, NULL);
1063         c->fmt_ctx.pb.is_streamed = 1;
1064         /* prepare header */
1065         av_write_header(&c->fmt_ctx);
1066         c->state = HTTPSTATE_SEND_DATA;
1067         c->last_packet_sent = 0;
1068         break;
1069     case HTTPSTATE_SEND_DATA:
1070         /* find a new packet */
1071 #if 0
1072         fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
1073         if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
1074             /* overflow : resync. We suppose that wptr is at this
1075                point a pointer to a valid packet */
1076             c->rptr = http_fifo.wptr;
1077             c->got_key_frame = 0;
1078         }
1079         
1080         start_rptr = c->rptr;
1081         if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
1082             return 0;
1083         payload_size = ntohs(hdr.payload_size);
1084         payload = av_malloc(payload_size);
1085         if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
1086             /* cannot read all the payload */
1087             av_free(payload);
1088             c->rptr = start_rptr;
1089             return 0;
1090         }
1091         
1092         c->last_http_fifo_write_count = http_fifo_write_count - 
1093             fifo_size(&http_fifo, c->rptr);
1094         
1095         if (c->stream->stream_type != STREAM_TYPE_MASTER) {
1096             /* test if the packet can be handled by this format */
1097             ret = 0;
1098             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1099                 AVStream *st = c->fmt_ctx.streams[i];
1100                 if (test_header(&hdr, &st->codec)) {
1101                     /* only begin sending when got a key frame */
1102                     if (st->codec.key_frame)
1103                         c->got_key_frame |= 1 << i;
1104                     if (c->got_key_frame & (1 << i)) {
1105                         ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i,
1106                                                                    payload, payload_size);
1107                     }
1108                     break;
1109                 }
1110             }
1111             if (ret) {
1112                 /* must send trailer now */
1113                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1114             }
1115         } else {
1116             /* master case : send everything */
1117             char *q;
1118             q = c->buffer;
1119             memcpy(q, &hdr, sizeof(hdr));
1120             q += sizeof(hdr);
1121             memcpy(q, payload, payload_size);
1122             q += payload_size;
1123             c->buffer_ptr = c->buffer;
1124             c->buffer_end = q;
1125         }
1126         av_free(payload);
1127 #endif
1128         {
1129             AVPacket pkt;
1130
1131             /* read a packet from the input stream */
1132             if (c->stream->feed) {
1133                 ffm_set_write_index(c->fmt_in, 
1134                                     c->stream->feed->feed_write_index,
1135                                     c->stream->feed->feed_size);
1136             }
1137
1138             if (c->stream->max_time && 
1139                 c->stream->max_time + c->start_time > time(0)) {
1140                 /* We have timed out */
1141                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1142             } else if (av_read_packet(c->fmt_in, &pkt) < 0) {
1143                 if (c->stream->feed && c->stream->feed->feed_opened) {
1144                     /* if coming from feed, it means we reached the end of the
1145                        ffm file, so must wait for more data */
1146                     c->state = HTTPSTATE_WAIT_FEED;
1147                     return 1; /* state changed */
1148                 } else {
1149                     /* must send trailer now because eof or error */
1150                     c->state = HTTPSTATE_SEND_DATA_TRAILER;
1151                 }
1152             } else {
1153                 /* send it to the appropriate stream */
1154                 if (c->stream->feed) {
1155                     /* if coming from a feed, select the right stream */
1156                     for(i=0;i<c->stream->nb_streams;i++) {
1157                         if (c->stream->feed_streams[i] == pkt.stream_index) {
1158                             pkt.stream_index = i;
1159                             if (pkt.flags & PKT_FLAG_KEY) {
1160                                 c->got_key_frame |= 1 << i;
1161                             }
1162                             /* See if we have all the key frames, then 
1163                              * we start to send. This logic is not quite
1164                              * right, but it works for the case of a 
1165                              * single video stream with one or more
1166                              * audio streams (for which every frame is 
1167                              * typically a key frame). 
1168                              */
1169                             if (!c->stream->send_on_key || ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
1170                                 goto send_it;
1171                             }
1172                         }
1173                     }
1174                 } else {
1175                     AVCodecContext *codec;
1176                 send_it:
1177                     /* Fudge here */
1178                     codec = &c->fmt_ctx.streams[pkt.stream_index]->codec;
1179
1180                     codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
1181
1182 #ifdef PJSG
1183                     if (codec->codec_type == CODEC_TYPE_AUDIO) {
1184                         codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
1185                         /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
1186                     }
1187 #endif
1188
1189                     if (av_write_packet(&c->fmt_ctx, &pkt, 0))
1190                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
1191
1192                     codec->frame_number++;
1193                 }
1194
1195                 av_free_packet(&pkt);
1196             }
1197         }
1198         break;
1199     default:
1200     case HTTPSTATE_SEND_DATA_TRAILER:
1201         /* last packet test ? */
1202         if (c->last_packet_sent)
1203             return -1;
1204         /* prepare header */
1205         av_write_trailer(&c->fmt_ctx);
1206         c->last_packet_sent = 1;
1207         break;
1208     }
1209     return 0;
1210 }
1211
1212 /* should convert the format at the same time */
1213 static int http_send_data(HTTPContext *c)
1214 {
1215     int len, ret;
1216
1217     while (c->buffer_ptr >= c->buffer_end) {
1218         ret = http_prepare_data(c);
1219         if (ret < 0)
1220             return -1;
1221         else if (ret == 0) {
1222             continue;
1223         } else {
1224             /* state change requested */
1225             return 0;
1226         }
1227     }
1228
1229     if (c->buffer_end > c->buffer_ptr) {
1230         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1231         if (len < 0) {
1232             if (errno != EAGAIN && errno != EINTR) {
1233                 /* error : close connection */
1234                 return -1;
1235             }
1236         } else {
1237             c->buffer_ptr += len;
1238             c->data_count += len;
1239             if (c->stream)
1240                 c->stream->bytes_served += len;
1241         }
1242     }
1243     return 0;
1244 }
1245
1246 static int http_start_receive_data(HTTPContext *c)
1247 {
1248     int fd;
1249
1250     if (c->stream->feed_opened)
1251         return -1;
1252
1253     /* open feed */
1254     fd = open(c->stream->feed_filename, O_RDWR);
1255     if (fd < 0)
1256         return -1;
1257     c->feed_fd = fd;
1258     
1259     c->stream->feed_write_index = ffm_read_write_index(fd);
1260     c->stream->feed_size = lseek(fd, 0, SEEK_END);
1261     lseek(fd, 0, SEEK_SET);
1262
1263     /* init buffer input */
1264     c->buffer_ptr = c->buffer;
1265     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
1266     c->stream->feed_opened = 1;
1267     return 0;
1268 }
1269     
1270 static int http_receive_data(HTTPContext *c)
1271 {
1272     HTTPContext *c1;
1273
1274     if (c->buffer_end > c->buffer_ptr) {
1275         int len;
1276
1277         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1278         if (len < 0) {
1279             if (errno != EAGAIN && errno != EINTR) {
1280                 /* error : close connection */
1281                 goto fail;
1282             }
1283         } else if (len == 0) {
1284             /* end of connection : close it */
1285             goto fail;
1286         } else {
1287             c->buffer_ptr += len;
1288             c->data_count += len;
1289         }
1290     }
1291
1292     if (c->buffer_ptr >= c->buffer_end) {
1293         FFStream *feed = c->stream;
1294         /* a packet has been received : write it in the store, except
1295            if header */
1296         if (c->data_count > FFM_PACKET_SIZE) {
1297             
1298             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
1299             /* XXX: use llseek or url_seek */
1300             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
1301             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
1302             
1303             feed->feed_write_index += FFM_PACKET_SIZE;
1304             /* update file size */
1305             if (feed->feed_write_index > c->stream->feed_size)
1306                 feed->feed_size = feed->feed_write_index;
1307
1308             /* handle wrap around if max file size reached */
1309             if (feed->feed_write_index >= c->stream->feed_max_size)
1310                 feed->feed_write_index = FFM_PACKET_SIZE;
1311
1312             /* write index */
1313             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
1314
1315             /* wake up any waiting connections */
1316             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
1317                 if (c1->state == HTTPSTATE_WAIT_FEED && 
1318                     c1->stream->feed == c->stream->feed) {
1319                     c1->state = HTTPSTATE_SEND_DATA;
1320                 }
1321             }
1322         } else {
1323             /* We have a header in our hands that contains useful data */
1324             AVFormatContext s;
1325             AVInputFormat *fmt_in;
1326             ByteIOContext *pb = &s.pb;
1327             int i;
1328
1329             memset(&s, 0, sizeof(s));
1330
1331             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
1332             pb->buf_end = c->buffer_end;        /* ?? */
1333             pb->is_streamed = 1;
1334
1335             /* use feed output format name to find corresponding input format */
1336             fmt_in = av_find_input_format(feed->fmt->name);
1337             if (!fmt_in)
1338                 goto fail;
1339
1340             s.priv_data = av_mallocz(fmt_in->priv_data_size);
1341             if (!s.priv_data)
1342                 goto fail;
1343
1344             if (fmt_in->read_header(&s, 0) < 0) {
1345                 av_freep(&s.priv_data);
1346                 goto fail;
1347             }
1348
1349             /* Now we have the actual streams */
1350             if (s.nb_streams != feed->nb_streams) {
1351                 av_freep(&s.priv_data);
1352                 goto fail;
1353             }
1354             for (i = 0; i < s.nb_streams; i++) {
1355                 memcpy(&feed->streams[i]->codec, 
1356                        &s.streams[i]->codec, sizeof(AVCodecContext));
1357             } 
1358             av_freep(&s.priv_data);
1359         }
1360         c->buffer_ptr = c->buffer;
1361     }
1362
1363     return 0;
1364  fail:
1365     c->stream->feed_opened = 0;
1366     close(c->feed_fd);
1367     return -1;
1368 }
1369
1370 /* return the stream number in the feed */
1371 int add_av_stream(FFStream *feed,
1372                   AVStream *st)
1373 {
1374     AVStream *fst;
1375     AVCodecContext *av, *av1;
1376     int i;
1377
1378     av = &st->codec;
1379     for(i=0;i<feed->nb_streams;i++) {
1380         st = feed->streams[i];
1381         av1 = &st->codec;
1382         if (av1->codec_id == av->codec_id &&
1383             av1->codec_type == av->codec_type &&
1384             av1->bit_rate == av->bit_rate) {
1385
1386             switch(av->codec_type) {
1387             case CODEC_TYPE_AUDIO:
1388                 if (av1->channels == av->channels &&
1389                     av1->sample_rate == av->sample_rate)
1390                     goto found;
1391                 break;
1392             case CODEC_TYPE_VIDEO:
1393                 if (av1->width == av->width &&
1394                     av1->height == av->height &&
1395                     av1->frame_rate == av->frame_rate &&
1396                     av1->gop_size == av->gop_size)
1397                     goto found;
1398                 break;
1399             default:
1400                 av_abort();
1401             }
1402         }
1403     }
1404     
1405     fst = av_mallocz(sizeof(AVStream));
1406     if (!fst)
1407         return -1;
1408     fst->priv_data = av_mallocz(sizeof(FeedData));
1409     memcpy(&fst->codec, av, sizeof(AVCodecContext));
1410     feed->streams[feed->nb_streams++] = fst;
1411     return feed->nb_streams - 1;
1412  found:
1413     return i;
1414 }
1415
1416 /* compute the needed AVStream for each feed */
1417 void build_feed_streams(void)
1418 {
1419     FFStream *stream, *feed;
1420     int i;
1421
1422     /* gather all streams */
1423     for(stream = first_stream; stream != NULL; stream = stream->next) {
1424         feed = stream->feed;
1425         if (feed) {
1426             if (!stream->is_feed) {
1427                 for(i=0;i<stream->nb_streams;i++) {
1428                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
1429                 }
1430             } else {
1431                 for(i=0;i<stream->nb_streams;i++) {
1432                     stream->feed_streams[i] = i;
1433                 }
1434             }
1435         }
1436     }
1437
1438     /* create feed files if needed */
1439     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
1440         int fd;
1441
1442         if (!url_exist(feed->feed_filename)) {
1443             AVFormatContext s1, *s = &s1;
1444
1445             /* only write the header of the ffm file */
1446             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
1447                 fprintf(stderr, "Could not open output feed file '%s'\n",
1448                         feed->feed_filename);
1449                 exit(1);
1450             }
1451             s->oformat = feed->fmt;
1452             s->nb_streams = feed->nb_streams;
1453             for(i=0;i<s->nb_streams;i++) {
1454                 AVStream *st;
1455                 st = feed->streams[i];
1456                 s->streams[i] = st;
1457             }
1458             av_write_header(s);
1459             /* XXX: need better api */
1460             av_freep(&s->priv_data);
1461             url_fclose(&s->pb);
1462         }
1463         /* get feed size and write index */
1464         fd = open(feed->feed_filename, O_RDONLY);
1465         if (fd < 0) {
1466             fprintf(stderr, "Could not open output feed file '%s'\n",
1467                     feed->feed_filename);
1468             exit(1);
1469         }
1470
1471         feed->feed_write_index = ffm_read_write_index(fd);
1472         feed->feed_size = lseek(fd, 0, SEEK_END);
1473         /* ensure that we do not wrap before the end of file */
1474         if (feed->feed_max_size < feed->feed_size)
1475             feed->feed_max_size = feed->feed_size;
1476
1477         close(fd);
1478     }
1479 }
1480
1481 static void get_arg(char *buf, int buf_size, const char **pp)
1482 {
1483     const char *p;
1484     char *q;
1485     int quote;
1486
1487     p = *pp;
1488     while (isspace(*p)) p++;
1489     q = buf;
1490     quote = 0;
1491     if (*p == '\"' || *p == '\'')
1492         quote = *p++;
1493     for(;;) {
1494         if (quote) {
1495             if (*p == quote)
1496                 break;
1497         } else {
1498             if (isspace(*p))
1499                 break;
1500         }
1501         if (*p == '\0')
1502             break;
1503         if ((q - buf) < buf_size - 1)
1504             *q++ = *p;
1505         p++;
1506     }
1507     *q = '\0';
1508     if (quote && *p == quote)
1509         p++;
1510     *pp = p;
1511 }
1512
1513 /* add a codec and set the default parameters */
1514 void add_codec(FFStream *stream, AVCodecContext *av)
1515 {
1516     AVStream *st;
1517
1518     /* compute default parameters */
1519     switch(av->codec_type) {
1520     case CODEC_TYPE_AUDIO:
1521         if (av->bit_rate == 0)
1522             av->bit_rate = 64000;
1523         if (av->sample_rate == 0)
1524             av->sample_rate = 22050;
1525         if (av->channels == 0)
1526             av->channels = 1;
1527         break;
1528     case CODEC_TYPE_VIDEO:
1529         if (av->bit_rate == 0)
1530             av->bit_rate = 64000;
1531         if (av->frame_rate == 0)
1532             av->frame_rate = 5 * FRAME_RATE_BASE;
1533         if (av->width == 0 || av->height == 0) {
1534             av->width = 160;
1535             av->height = 128;
1536         }
1537         /* Bitrate tolerance is less for streaming */
1538         if (av->bit_rate_tolerance == 0)
1539             av->bit_rate_tolerance = av->bit_rate / 4;
1540         if (av->qmin == 0)
1541             av->qmin = 3;
1542         if (av->qmax == 0)
1543             av->qmax = 31;
1544         if (av->max_qdiff == 0)
1545             av->max_qdiff = 3;
1546         av->qcompress = 0.5;
1547         av->qblur = 0.5;
1548
1549         break;
1550     default:
1551         av_abort();
1552     }
1553
1554     st = av_mallocz(sizeof(AVStream));
1555     if (!st)
1556         return;
1557     stream->streams[stream->nb_streams++] = st;
1558     memcpy(&st->codec, av, sizeof(AVCodecContext));
1559 }
1560
1561 int opt_audio_codec(const char *arg)
1562 {
1563     AVCodec *p;
1564
1565     p = first_avcodec;
1566     while (p) {
1567         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
1568             break;
1569         p = p->next;
1570     }
1571     if (p == NULL) {
1572         return CODEC_ID_NONE;
1573     }
1574
1575     return p->id;
1576 }
1577
1578 int opt_video_codec(const char *arg)
1579 {
1580     AVCodec *p;
1581
1582     p = first_avcodec;
1583     while (p) {
1584         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
1585             break;
1586         p = p->next;
1587     }
1588     if (p == NULL) {
1589         return CODEC_ID_NONE;
1590     }
1591
1592     return p->id;
1593 }
1594
1595 int parse_ffconfig(const char *filename)
1596 {
1597     FILE *f;
1598     char line[1024];
1599     char cmd[64];
1600     char arg[1024];
1601     const char *p;
1602     int val, errors, line_num;
1603     FFStream **last_stream, *stream;
1604     FFStream **last_feed, *feed;
1605     AVCodecContext audio_enc, video_enc;
1606     int audio_id, video_id;
1607
1608     f = fopen(filename, "r");
1609     if (!f) {
1610         perror(filename);
1611         return -1;
1612     }
1613     
1614     errors = 0;
1615     line_num = 0;
1616     first_stream = NULL;
1617     last_stream = &first_stream;
1618     first_feed = NULL;
1619     last_feed = &first_feed;
1620     stream = NULL;
1621     feed = NULL;
1622     audio_id = CODEC_ID_NONE;
1623     video_id = CODEC_ID_NONE;
1624     for(;;) {
1625         if (fgets(line, sizeof(line), f) == NULL)
1626             break;
1627         line_num++;
1628         p = line;
1629         while (isspace(*p)) 
1630             p++;
1631         if (*p == '\0' || *p == '#')
1632             continue;
1633
1634         get_arg(cmd, sizeof(cmd), &p);
1635         
1636         if (!strcasecmp(cmd, "Port")) {
1637             get_arg(arg, sizeof(arg), &p);
1638             my_addr.sin_port = htons (atoi(arg));
1639         } else if (!strcasecmp(cmd, "BindAddress")) {
1640             get_arg(arg, sizeof(arg), &p);
1641             if (!inet_aton(arg, &my_addr.sin_addr)) {
1642                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
1643                         filename, line_num, arg);
1644                 errors++;
1645             }
1646         } else if (!strcasecmp(cmd, "MaxClients")) {
1647             get_arg(arg, sizeof(arg), &p);
1648             val = atoi(arg);
1649             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
1650                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
1651                         filename, line_num, arg);
1652                 errors++;
1653             } else {
1654                 nb_max_connections = val;
1655             }
1656         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
1657             get_arg(arg, sizeof(arg), &p);
1658             val = atoi(arg);
1659             if (val < 10 || val > 100000) {
1660                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
1661                         filename, line_num, arg);
1662                 errors++;
1663             } else {
1664                 nb_max_bandwidth = val;
1665             }
1666         } else if (!strcasecmp(cmd, "CustomLog")) {
1667             get_arg(logfilename, sizeof(logfilename), &p);
1668         } else if (!strcasecmp(cmd, "<Feed")) {
1669             /*********************************************/
1670             /* Feed related options */
1671             char *q;
1672             if (stream || feed) {
1673                 fprintf(stderr, "%s:%d: Already in a tag\n",
1674                         filename, line_num);
1675             } else {
1676                 feed = av_mallocz(sizeof(FFStream));
1677                 /* add in stream list */
1678                 *last_stream = feed;
1679                 last_stream = &feed->next;
1680                 /* add in feed list */
1681                 *last_feed = feed;
1682                 last_feed = &feed->next_feed;
1683                 
1684                 get_arg(feed->filename, sizeof(feed->filename), &p);
1685                 q = strrchr(feed->filename, '>');
1686                 if (*q)
1687                     *q = '\0';
1688                 feed->fmt = guess_format("ffm", NULL, NULL);
1689                 /* defaut feed file */
1690                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
1691                          "/tmp/%s.ffm", feed->filename);
1692                 feed->feed_max_size = 5 * 1024 * 1024;
1693                 feed->is_feed = 1;
1694                 feed->feed = feed; /* self feeding :-) */
1695             }
1696         } else if (!strcasecmp(cmd, "File")) {
1697             if (feed) {
1698                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
1699             } else if (stream) {
1700                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
1701             }
1702         } else if (!strcasecmp(cmd, "FileMaxSize")) {
1703             if (feed) {
1704                 const char *p1;
1705                 double fsize;
1706
1707                 get_arg(arg, sizeof(arg), &p);
1708                 p1 = arg;
1709                 fsize = strtod(p1, (char **)&p1);
1710                 switch(toupper(*p1)) {
1711                 case 'K':
1712                     fsize *= 1024;
1713                     break;
1714                 case 'M':
1715                     fsize *= 1024 * 1024;
1716                     break;
1717                 case 'G':
1718                     fsize *= 1024 * 1024 * 1024;
1719                     break;
1720                 }
1721                 feed->feed_max_size = (INT64)fsize;
1722             }
1723         } else if (!strcasecmp(cmd, "</Feed>")) {
1724             if (!feed) {
1725                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
1726                         filename, line_num);
1727                 errors++;
1728             } else {
1729                 /* Make sure that we start out clean */
1730                 if (unlink(feed->feed_filename) < 0 
1731                     && errno != ENOENT) {
1732                     fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
1733                         filename, line_num, feed->feed_filename, strerror(errno));
1734                     errors++;
1735                 }
1736             }
1737             feed = NULL;
1738         } else if (!strcasecmp(cmd, "<Stream")) {
1739             /*********************************************/
1740             /* Stream related options */
1741             char *q;
1742             if (stream || feed) {
1743                 fprintf(stderr, "%s:%d: Already in a tag\n",
1744                         filename, line_num);
1745             } else {
1746                 stream = av_mallocz(sizeof(FFStream));
1747                 *last_stream = stream;
1748                 last_stream = &stream->next;
1749
1750                 get_arg(stream->filename, sizeof(stream->filename), &p);
1751                 q = strrchr(stream->filename, '>');
1752                 if (*q)
1753                     *q = '\0';
1754                 stream->fmt = guess_format(NULL, stream->filename, NULL);
1755                 memset(&audio_enc, 0, sizeof(AVCodecContext));
1756                 memset(&video_enc, 0, sizeof(AVCodecContext));
1757                 audio_id = CODEC_ID_NONE;
1758                 video_id = CODEC_ID_NONE;
1759                 if (stream->fmt) {
1760                     audio_id = stream->fmt->audio_codec;
1761                     video_id = stream->fmt->video_codec;
1762                 }
1763             }
1764         } else if (!strcasecmp(cmd, "Feed")) {
1765             get_arg(arg, sizeof(arg), &p);
1766             if (stream) {
1767                 FFStream *sfeed;
1768                 
1769                 sfeed = first_feed;
1770                 while (sfeed != NULL) {
1771                     if (!strcmp(sfeed->filename, arg))
1772                         break;
1773                     sfeed = sfeed->next_feed;
1774                 }
1775                 if (!sfeed) {
1776                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
1777                             filename, line_num, arg);
1778                 } else {
1779                     stream->feed = sfeed;
1780                 }
1781             }
1782         } else if (!strcasecmp(cmd, "Format")) {
1783             get_arg(arg, sizeof(arg), &p);
1784             if (!strcmp(arg, "status")) {
1785                 stream->stream_type = STREAM_TYPE_STATUS;
1786                 stream->fmt = NULL;
1787             } else {
1788                 stream->stream_type = STREAM_TYPE_LIVE;
1789                 /* jpeg cannot be used here, so use single frame jpeg */
1790                 if (!strcmp(arg, "jpeg"))
1791                     strcpy(arg, "singlejpeg");
1792                 stream->fmt = guess_format(arg, NULL, NULL);
1793                 if (!stream->fmt) {
1794                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
1795                             filename, line_num, arg);
1796                     errors++;
1797                 }
1798             }
1799             if (stream->fmt) {
1800                 audio_id = stream->fmt->audio_codec;
1801                 video_id = stream->fmt->video_codec;
1802             }
1803         } else if (!strcasecmp(cmd, "Preroll")) {
1804             get_arg(arg, sizeof(arg), &p);
1805             if (stream) {
1806                 stream->prebuffer = atoi(arg) * 1000;
1807             }
1808         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
1809             if (stream) {
1810                 stream->send_on_key = 1;
1811             }
1812         } else if (!strcasecmp(cmd, "AudioCodec")) {
1813             get_arg(arg, sizeof(arg), &p);
1814             audio_id = opt_audio_codec(arg);
1815             if (audio_id == CODEC_ID_NONE) {
1816                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
1817                         filename, line_num, arg);
1818                 errors++;
1819             }
1820         } else if (!strcasecmp(cmd, "VideoCodec")) {
1821             get_arg(arg, sizeof(arg), &p);
1822             video_id = opt_video_codec(arg);
1823             if (video_id == CODEC_ID_NONE) {
1824                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
1825                         filename, line_num, arg);
1826                 errors++;
1827             }
1828         } else if (!strcasecmp(cmd, "MaxTime")) {
1829             get_arg(arg, sizeof(arg), &p);
1830             if (stream) {
1831                 stream->max_time = atoi(arg);
1832             }
1833         } else if (!strcasecmp(cmd, "AudioBitRate")) {
1834             get_arg(arg, sizeof(arg), &p);
1835             if (stream) {
1836                 audio_enc.bit_rate = atoi(arg) * 1000;
1837             }
1838         } else if (!strcasecmp(cmd, "AudioChannels")) {
1839             get_arg(arg, sizeof(arg), &p);
1840             if (stream) {
1841                 audio_enc.channels = atoi(arg);
1842             }
1843         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
1844             get_arg(arg, sizeof(arg), &p);
1845             if (stream) {
1846                 audio_enc.sample_rate = atoi(arg);
1847             }
1848         } else if (!strcasecmp(cmd, "VideoBitRate")) {
1849             get_arg(arg, sizeof(arg), &p);
1850             if (stream) {
1851                 video_enc.bit_rate = atoi(arg) * 1000;
1852             }
1853         } else if (!strcasecmp(cmd, "VideoSize")) {
1854             get_arg(arg, sizeof(arg), &p);
1855             if (stream) {
1856                 parse_image_size(&video_enc.width, &video_enc.height, arg);
1857                 if ((video_enc.width % 16) != 0 ||
1858                     (video_enc.height % 16) != 0) {
1859                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
1860                             filename, line_num);
1861                     errors++;
1862                 }
1863             }
1864         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
1865             get_arg(arg, sizeof(arg), &p);
1866             if (stream) {
1867                 video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
1868             }
1869         } else if (!strcasecmp(cmd, "VideoGopSize")) {
1870             get_arg(arg, sizeof(arg), &p);
1871             if (stream) {
1872                 video_enc.gop_size = atoi(arg);
1873             }
1874         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
1875             if (stream) {
1876                 video_enc.gop_size = 1;
1877             }
1878         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
1879             if (stream) {
1880                 video_enc.flags |= CODEC_FLAG_HQ;
1881             }
1882         } else if (!strcasecmp(cmd, "VideoQDiff")) {
1883             if (stream) {
1884                 video_enc.max_qdiff = atoi(arg);
1885                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
1886                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
1887                             filename, line_num);
1888                     errors++;
1889                 }
1890             }
1891         } else if (!strcasecmp(cmd, "VideoQMax")) {
1892             if (stream) {
1893                 video_enc.qmax = atoi(arg);
1894                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
1895                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
1896                             filename, line_num);
1897                     errors++;
1898                 }
1899             }
1900         } else if (!strcasecmp(cmd, "VideoQMin")) {
1901             if (stream) {
1902                 video_enc.qmin = atoi(arg);
1903                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
1904                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
1905                             filename, line_num);
1906                     errors++;
1907                 }
1908             }
1909         } else if (!strcasecmp(cmd, "NoVideo")) {
1910             video_id = CODEC_ID_NONE;
1911         } else if (!strcasecmp(cmd, "NoAudio")) {
1912             audio_id = CODEC_ID_NONE;
1913         } else if (!strcasecmp(cmd, "</Stream>")) {
1914             if (!stream) {
1915                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
1916                         filename, line_num);
1917                 errors++;
1918             }
1919             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
1920                 if (audio_id != CODEC_ID_NONE) {
1921                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
1922                     audio_enc.codec_id = audio_id;
1923                     add_codec(stream, &audio_enc);
1924                 }
1925                 if (video_id != CODEC_ID_NONE) {
1926                     video_enc.codec_type = CODEC_TYPE_VIDEO;
1927                     video_enc.codec_id = video_id;
1928                     add_codec(stream, &video_enc);
1929                 }
1930             }
1931             stream = NULL;
1932         } else {
1933             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
1934                     filename, line_num, cmd);
1935             errors++;
1936         }
1937     }
1938
1939     fclose(f);
1940     if (errors)
1941         return -1;
1942     else
1943         return 0;
1944 }
1945
1946
1947 void *http_server_thread(void *arg)
1948 {
1949     http_server(my_addr);
1950     return NULL;
1951 }
1952
1953 #if 0
1954 static void write_packet(FFCodec *ffenc,
1955                          UINT8 *buf, int size)
1956 {
1957     PacketHeader hdr;
1958     AVCodecContext *enc = &ffenc->enc;
1959     UINT8 *wptr;
1960     mk_header(&hdr, enc, size);
1961     wptr = http_fifo.wptr;
1962     fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
1963     fifo_write(&http_fifo, buf, size, &wptr);
1964     /* atomic modification of wptr */
1965     http_fifo.wptr = wptr;
1966     ffenc->data_count += size;
1967     ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
1968 }
1969 #endif
1970
1971 void help(void)
1972 {
1973     printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Gerard Lantau\n"
1974            "usage: ffserver [-L] [-h] [-f configfile]\n"
1975            "Hyper fast multi format Audio/Video streaming server\n"
1976            "\n"
1977            "-L            : print the LICENCE\n"
1978            "-h            : this help\n"
1979            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
1980            );
1981 }
1982
1983 void licence(void)
1984 {
1985     printf(
1986     "ffserver version " FFMPEG_VERSION "\n"
1987     "Copyright (c) 2000, 2001, 2002 Gerard Lantau\n"
1988     "This program is free software; you can redistribute it and/or modify\n"
1989     "it under the terms of the GNU General Public License as published by\n"
1990     "the Free Software Foundation; either version 2 of the License, or\n"
1991     "(at your option) any later version.\n"
1992     "\n"
1993     "This program is distributed in the hope that it will be useful,\n"
1994     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1995     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1996     "GNU General Public License for more details.\n"
1997     "\n"
1998     "You should have received a copy of the GNU General Public License\n"
1999     "along with this program; if not, write to the Free Software\n"
2000     "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
2001     );
2002 }
2003
2004 int main(int argc, char **argv)
2005 {
2006     const char *config_filename;
2007     int c;
2008
2009     register_all();
2010
2011     config_filename = "/etc/ffserver.conf";
2012
2013     for(;;) {
2014         c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL);
2015         if (c == -1)
2016             break;
2017         switch(c) {
2018         case 'L':
2019             licence();
2020             exit(1);
2021         case '?':
2022         case 'h':
2023             help();
2024             exit(1);
2025         case 'f':
2026             config_filename = optarg;
2027             break;
2028         default:
2029             exit(2);
2030         }
2031     }
2032
2033     /* address on which the server will handle connections */
2034     my_addr.sin_family = AF_INET;
2035     my_addr.sin_port = htons (8080);
2036     my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
2037     nb_max_connections = 5;
2038     nb_max_bandwidth = 1000;
2039     first_stream = NULL;
2040     logfilename[0] = '\0';
2041
2042     if (parse_ffconfig(config_filename) < 0) {
2043         fprintf(stderr, "Incorrect config file - exiting.\n");
2044         exit(1);
2045     }
2046
2047     build_feed_streams();
2048
2049     /* signal init */
2050     signal(SIGPIPE, SIG_IGN);
2051
2052     /* open log file if needed */
2053     if (logfilename[0] != '\0') {
2054         if (!strcmp(logfilename, "-"))
2055             logfile = stdout;
2056         else
2057             logfile = fopen(logfilename, "w");
2058     }
2059
2060     if (http_server(my_addr) < 0) {
2061         fprintf(stderr, "Could start http server\n");
2062         exit(1);
2063     }
2064
2065     return 0;
2066 }