767da5f3a0d49a54c347f08d2b600746ee41dc49
[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\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
870                 switch(st->codec.codec_type) {
871                 case CODEC_TYPE_AUDIO:
872                     type = "audio";
873                     break;
874                 case CODEC_TYPE_VIDEO:
875                     type = "video";
876                     break;
877                 default:
878                     av_abort();
879                 }
880                 q += sprintf(q, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s\n",
881                         i, type, st->codec.bit_rate/1000, codec ? codec->name : "");
882             }
883             q += sprintf(q, "</table>\n");
884
885         }       
886         stream = stream->next;
887     }
888     
889 #if 0
890     {
891         float avg;
892         AVCodecContext *enc;
893         char buf[1024];
894         
895         /* feed status */
896         stream = first_feed;
897         while (stream != NULL) {
898             q += sprintf(q, "<H1>Feed '%s'</H1>\n", stream->filename);
899             q += sprintf(q, "<TABLE>\n");
900             q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
901             for(i=0;i<stream->nb_streams;i++) {
902                 AVStream *st = stream->streams[i];
903                 FeedData *fdata = st->priv_data;
904                 enc = &st->codec;
905             
906                 avcodec_string(buf, sizeof(buf), enc);
907                 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
908                 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
909                     avg /= enc->frame_size;
910                 q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
911                              buf, enc->frame_number, fdata->data_count, avg / 1000.0);
912             }
913             q += sprintf(q, "</TABLE>\n");
914             stream = stream->next_feed;
915         }
916     }
917 #endif
918
919     /* connection status */
920     q += sprintf(q, "<H2>Connection Status</H2>\n");
921
922     q += sprintf(q, "Number of connections: %d / %d<BR>\n",
923                  nb_connections, nb_max_connections);
924
925     q += sprintf(q, "Bandwidth in use: %dk / %dk<BR>\n",
926                  nb_bandwidth, nb_max_bandwidth);
927
928     q += sprintf(q, "<TABLE>\n");
929     q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>State<TD>Size\n");
930     c1 = first_http_ctx;
931     i = 0;
932     while (c1 != NULL && q < (char *) c->buffer + sizeof(c->buffer) - 2048) {
933         i++;
934         p = inet_ntoa(c1->from_addr.sin_addr);
935         q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <TD> %Ld\n", 
936                      i, c1->stream->filename, 
937                      c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
938                      p, 
939                      http_state[c1->state],
940                      c1->data_count);
941         c1 = c1->next;
942     }
943     q += sprintf(q, "</TABLE>\n");
944     
945     /* date */
946     ti = time(NULL);
947     p = ctime(&ti);
948     q += sprintf(q, "<HR size=1 noshade>Generated at %s", p);
949     q += sprintf(q, "</BODY>\n</HTML>\n");
950
951     c->buffer_ptr = c->buffer;
952     c->buffer_end = q;
953 }
954
955
956 static void http_write_packet(void *opaque, 
957                               unsigned char *buf, int size)
958 {
959     HTTPContext *c = opaque;
960
961     if (c->buffer_ptr == c->buffer_end || !c->buffer_ptr)
962         c->buffer_ptr = c->buffer_end = c->buffer;
963
964     if (c->buffer_end - c->buffer + size > IOBUFFER_MAX_SIZE)
965         av_abort();
966
967     memcpy(c->buffer_end, buf, size);
968     c->buffer_end += size;
969 }
970
971 static int open_input_stream(HTTPContext *c, const char *info)
972 {
973     char buf[128];
974     char input_filename[1024];
975     AVFormatContext *s;
976     int buf_size;
977     INT64 stream_pos;
978
979     /* find file name */
980     if (c->stream->feed) {
981         strcpy(input_filename, c->stream->feed->feed_filename);
982         buf_size = FFM_PACKET_SIZE;
983         /* compute position (absolute time) */
984         if (find_info_tag(buf, sizeof(buf), "date", info)) {
985             stream_pos = parse_date(buf, 0);
986         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
987             int prebuffer = strtol(buf, 0, 10);
988             stream_pos = gettime() - prebuffer * 1000000;
989         } else {
990             stream_pos = gettime() - c->stream->prebuffer * 1000;
991         }
992     } else {
993         strcpy(input_filename, c->stream->feed_filename);
994         buf_size = 0;
995         /* compute position (relative time) */
996         if (find_info_tag(buf, sizeof(buf), "date", info)) {
997             stream_pos = parse_date(buf, 1);
998         } else {
999             stream_pos = 0;
1000         }
1001     }
1002     if (input_filename[0] == '\0')
1003         return -1;
1004
1005     /* open stream */
1006     if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0)
1007         return -1;
1008     c->fmt_in = s;
1009
1010     if (c->fmt_in->iformat->read_seek) {
1011         c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
1012     }
1013     
1014     //    printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
1015     return 0;
1016 }
1017
1018 static int http_prepare_data(HTTPContext *c)
1019 {
1020     int i;
1021
1022     switch(c->state) {
1023     case HTTPSTATE_SEND_DATA_HEADER:
1024         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1025         if (c->stream->feed) {
1026             /* open output stream by using specified codecs */
1027             c->fmt_ctx.oformat = c->stream->fmt;
1028             c->fmt_ctx.nb_streams = c->stream->nb_streams;
1029             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1030                 AVStream *st;
1031                 st = av_mallocz(sizeof(AVStream));
1032                 c->fmt_ctx.streams[i] = st;
1033                 if (c->stream->feed == c->stream)
1034                     memcpy(st, c->stream->streams[i], sizeof(AVStream));
1035                 else
1036                     memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]], sizeof(AVStream));
1037
1038                 st->codec.frame_number = 0; /* XXX: should be done in
1039                                                AVStream, not in codec */
1040             }
1041             c->got_key_frame = 0;
1042         } else {
1043             /* open output stream by using codecs in specified file */
1044             c->fmt_ctx.oformat = c->stream->fmt;
1045             c->fmt_ctx.nb_streams = c->fmt_in->nb_streams;
1046             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1047                 AVStream *st;
1048                 st = av_mallocz(sizeof(AVStream));
1049                 c->fmt_ctx.streams[i] = st;
1050                 memcpy(st, c->fmt_in->streams[i], sizeof(AVStream));
1051                 st->codec.frame_number = 0; /* XXX: should be done in
1052                                                AVStream, not in codec */
1053             }
1054             c->got_key_frame = 0;
1055         }
1056         init_put_byte(&c->fmt_ctx.pb, c->pbuffer, PACKET_MAX_SIZE,
1057                       1, c, NULL, http_write_packet, NULL);
1058         c->fmt_ctx.pb.is_streamed = 1;
1059         /* prepare header */
1060         av_write_header(&c->fmt_ctx);
1061         c->state = HTTPSTATE_SEND_DATA;
1062         c->last_packet_sent = 0;
1063         break;
1064     case HTTPSTATE_SEND_DATA:
1065         /* find a new packet */
1066 #if 0
1067         fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
1068         if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
1069             /* overflow : resync. We suppose that wptr is at this
1070                point a pointer to a valid packet */
1071             c->rptr = http_fifo.wptr;
1072             c->got_key_frame = 0;
1073         }
1074         
1075         start_rptr = c->rptr;
1076         if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
1077             return 0;
1078         payload_size = ntohs(hdr.payload_size);
1079         payload = av_malloc(payload_size);
1080         if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
1081             /* cannot read all the payload */
1082             av_free(payload);
1083             c->rptr = start_rptr;
1084             return 0;
1085         }
1086         
1087         c->last_http_fifo_write_count = http_fifo_write_count - 
1088             fifo_size(&http_fifo, c->rptr);
1089         
1090         if (c->stream->stream_type != STREAM_TYPE_MASTER) {
1091             /* test if the packet can be handled by this format */
1092             ret = 0;
1093             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1094                 AVStream *st = c->fmt_ctx.streams[i];
1095                 if (test_header(&hdr, &st->codec)) {
1096                     /* only begin sending when got a key frame */
1097                     if (st->codec.key_frame)
1098                         c->got_key_frame |= 1 << i;
1099                     if (c->got_key_frame & (1 << i)) {
1100                         ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i,
1101                                                                    payload, payload_size);
1102                     }
1103                     break;
1104                 }
1105             }
1106             if (ret) {
1107                 /* must send trailer now */
1108                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1109             }
1110         } else {
1111             /* master case : send everything */
1112             char *q;
1113             q = c->buffer;
1114             memcpy(q, &hdr, sizeof(hdr));
1115             q += sizeof(hdr);
1116             memcpy(q, payload, payload_size);
1117             q += payload_size;
1118             c->buffer_ptr = c->buffer;
1119             c->buffer_end = q;
1120         }
1121         av_free(payload);
1122 #endif
1123         {
1124             AVPacket pkt;
1125
1126             /* read a packet from the input stream */
1127             if (c->stream->feed) {
1128                 ffm_set_write_index(c->fmt_in, 
1129                                     c->stream->feed->feed_write_index,
1130                                     c->stream->feed->feed_size);
1131             }
1132
1133             if (c->stream->max_time && 
1134                 c->stream->max_time + c->start_time > time(0)) {
1135                 /* We have timed out */
1136                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1137             } else if (av_read_packet(c->fmt_in, &pkt) < 0) {
1138                 if (c->stream->feed && c->stream->feed->feed_opened) {
1139                     /* if coming from feed, it means we reached the end of the
1140                        ffm file, so must wait for more data */
1141                     c->state = HTTPSTATE_WAIT_FEED;
1142                     return 1; /* state changed */
1143                 } else {
1144                     /* must send trailer now because eof or error */
1145                     c->state = HTTPSTATE_SEND_DATA_TRAILER;
1146                 }
1147             } else {
1148                 /* send it to the appropriate stream */
1149                 if (c->stream->feed) {
1150                     /* if coming from a feed, select the right stream */
1151                     for(i=0;i<c->stream->nb_streams;i++) {
1152                         if (c->stream->feed_streams[i] == pkt.stream_index) {
1153                             pkt.stream_index = i;
1154                             if (pkt.flags & PKT_FLAG_KEY) {
1155                                 c->got_key_frame |= 1 << i;
1156                             }
1157                             /* See if we have all the key frames, then 
1158                              * we start to send. This logic is not quite
1159                              * right, but it works for the case of a 
1160                              * single video stream with one or more
1161                              * audio streams (for which every frame is 
1162                              * typically a key frame). 
1163                              */
1164                             if (!c->stream->send_on_key || ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
1165                                 goto send_it;
1166                             }
1167                         }
1168                     }
1169                 } else {
1170                     AVCodecContext *codec;
1171                 send_it:
1172                     /* Fudge here */
1173                     codec = &c->fmt_ctx.streams[pkt.stream_index]->codec;
1174
1175                     codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
1176
1177 #ifdef PJSG
1178                     if (codec->codec_type == CODEC_TYPE_AUDIO) {
1179                         codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
1180                         /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
1181                     }
1182 #endif
1183
1184                     if (av_write_packet(&c->fmt_ctx, &pkt, 0))
1185                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
1186
1187                     codec->frame_number++;
1188                 }
1189
1190                 av_free_packet(&pkt);
1191             }
1192         }
1193         break;
1194     default:
1195     case HTTPSTATE_SEND_DATA_TRAILER:
1196         /* last packet test ? */
1197         if (c->last_packet_sent)
1198             return -1;
1199         /* prepare header */
1200         av_write_trailer(&c->fmt_ctx);
1201         c->last_packet_sent = 1;
1202         break;
1203     }
1204     return 0;
1205 }
1206
1207 /* should convert the format at the same time */
1208 static int http_send_data(HTTPContext *c)
1209 {
1210     int len, ret;
1211
1212     while (c->buffer_ptr >= c->buffer_end) {
1213         ret = http_prepare_data(c);
1214         if (ret < 0)
1215             return -1;
1216         else if (ret == 0) {
1217             continue;
1218         } else {
1219             /* state change requested */
1220             return 0;
1221         }
1222     }
1223
1224     if (c->buffer_end > c->buffer_ptr) {
1225         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1226         if (len < 0) {
1227             if (errno != EAGAIN && errno != EINTR) {
1228                 /* error : close connection */
1229                 return -1;
1230             }
1231         } else {
1232             c->buffer_ptr += len;
1233             c->data_count += len;
1234             if (c->stream)
1235                 c->stream->bytes_served += len;
1236         }
1237     }
1238     return 0;
1239 }
1240
1241 static int http_start_receive_data(HTTPContext *c)
1242 {
1243     int fd;
1244
1245     if (c->stream->feed_opened)
1246         return -1;
1247
1248     /* open feed */
1249     fd = open(c->stream->feed_filename, O_RDWR);
1250     if (fd < 0)
1251         return -1;
1252     c->feed_fd = fd;
1253     
1254     c->stream->feed_write_index = ffm_read_write_index(fd);
1255     c->stream->feed_size = lseek(fd, 0, SEEK_END);
1256     lseek(fd, 0, SEEK_SET);
1257
1258     /* init buffer input */
1259     c->buffer_ptr = c->buffer;
1260     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
1261     c->stream->feed_opened = 1;
1262     return 0;
1263 }
1264     
1265 static int http_receive_data(HTTPContext *c)
1266 {
1267     HTTPContext *c1;
1268
1269     if (c->buffer_end > c->buffer_ptr) {
1270         int len;
1271
1272         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
1273         if (len < 0) {
1274             if (errno != EAGAIN && errno != EINTR) {
1275                 /* error : close connection */
1276                 goto fail;
1277             }
1278         } else if (len == 0) {
1279             /* end of connection : close it */
1280             goto fail;
1281         } else {
1282             c->buffer_ptr += len;
1283             c->data_count += len;
1284         }
1285     }
1286
1287     if (c->buffer_ptr >= c->buffer_end) {
1288         FFStream *feed = c->stream;
1289         /* a packet has been received : write it in the store, except
1290            if header */
1291         if (c->data_count > FFM_PACKET_SIZE) {
1292             
1293             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
1294             /* XXX: use llseek or url_seek */
1295             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
1296             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
1297             
1298             feed->feed_write_index += FFM_PACKET_SIZE;
1299             /* update file size */
1300             if (feed->feed_write_index > c->stream->feed_size)
1301                 feed->feed_size = feed->feed_write_index;
1302
1303             /* handle wrap around if max file size reached */
1304             if (feed->feed_write_index >= c->stream->feed_max_size)
1305                 feed->feed_write_index = FFM_PACKET_SIZE;
1306
1307             /* write index */
1308             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
1309
1310             /* wake up any waiting connections */
1311             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
1312                 if (c1->state == HTTPSTATE_WAIT_FEED && 
1313                     c1->stream->feed == c->stream->feed) {
1314                     c1->state = HTTPSTATE_SEND_DATA;
1315                 }
1316             }
1317         } else {
1318             /* We have a header in our hands that contains useful data */
1319             AVFormatContext s;
1320             AVInputFormat *fmt_in;
1321             ByteIOContext *pb = &s.pb;
1322             int i;
1323
1324             memset(&s, 0, sizeof(s));
1325
1326             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
1327             pb->buf_end = c->buffer_end;        /* ?? */
1328             pb->is_streamed = 1;
1329
1330             /* use feed output format name to find corresponding input format */
1331             fmt_in = av_find_input_format(feed->fmt->name);
1332             if (!fmt_in)
1333                 goto fail;
1334
1335             s.priv_data = av_mallocz(fmt_in->priv_data_size);
1336             if (!s.priv_data)
1337                 goto fail;
1338
1339             if (fmt_in->read_header(&s, 0) < 0) {
1340                 av_freep(&s.priv_data);
1341                 goto fail;
1342             }
1343
1344             /* Now we have the actual streams */
1345             if (s.nb_streams != feed->nb_streams) {
1346                 av_freep(&s.priv_data);
1347                 goto fail;
1348             }
1349             for (i = 0; i < s.nb_streams; i++) {
1350                 memcpy(&feed->streams[i]->codec, 
1351                        &s.streams[i]->codec, sizeof(AVCodecContext));
1352             } 
1353             av_freep(&s.priv_data);
1354         }
1355         c->buffer_ptr = c->buffer;
1356     }
1357
1358     return 0;
1359  fail:
1360     c->stream->feed_opened = 0;
1361     close(c->feed_fd);
1362     return -1;
1363 }
1364
1365 /* return the stream number in the feed */
1366 int add_av_stream(FFStream *feed,
1367                   AVStream *st)
1368 {
1369     AVStream *fst;
1370     AVCodecContext *av, *av1;
1371     int i;
1372
1373     av = &st->codec;
1374     for(i=0;i<feed->nb_streams;i++) {
1375         st = feed->streams[i];
1376         av1 = &st->codec;
1377         if (av1->codec_id == av->codec_id &&
1378             av1->codec_type == av->codec_type &&
1379             av1->bit_rate == av->bit_rate) {
1380
1381             switch(av->codec_type) {
1382             case CODEC_TYPE_AUDIO:
1383                 if (av1->channels == av->channels &&
1384                     av1->sample_rate == av->sample_rate)
1385                     goto found;
1386                 break;
1387             case CODEC_TYPE_VIDEO:
1388                 if (av1->width == av->width &&
1389                     av1->height == av->height &&
1390                     av1->frame_rate == av->frame_rate &&
1391                     av1->gop_size == av->gop_size)
1392                     goto found;
1393                 break;
1394             default:
1395                 av_abort();
1396             }
1397         }
1398     }
1399     
1400     fst = av_mallocz(sizeof(AVStream));
1401     if (!fst)
1402         return -1;
1403     fst->priv_data = av_mallocz(sizeof(FeedData));
1404     memcpy(&fst->codec, av, sizeof(AVCodecContext));
1405     feed->streams[feed->nb_streams++] = fst;
1406     return feed->nb_streams - 1;
1407  found:
1408     return i;
1409 }
1410
1411 /* compute the needed AVStream for each feed */
1412 void build_feed_streams(void)
1413 {
1414     FFStream *stream, *feed;
1415     int i;
1416
1417     /* gather all streams */
1418     for(stream = first_stream; stream != NULL; stream = stream->next) {
1419         feed = stream->feed;
1420         if (feed) {
1421             if (!stream->is_feed) {
1422                 for(i=0;i<stream->nb_streams;i++) {
1423                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
1424                 }
1425             } else {
1426                 for(i=0;i<stream->nb_streams;i++) {
1427                     stream->feed_streams[i] = i;
1428                 }
1429             }
1430         }
1431     }
1432
1433     /* create feed files if needed */
1434     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
1435         int fd;
1436
1437         if (!url_exist(feed->feed_filename)) {
1438             AVFormatContext s1, *s = &s1;
1439
1440             /* only write the header of the ffm file */
1441             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
1442                 fprintf(stderr, "Could not open output feed file '%s'\n",
1443                         feed->feed_filename);
1444                 exit(1);
1445             }
1446             s->oformat = feed->fmt;
1447             s->nb_streams = feed->nb_streams;
1448             for(i=0;i<s->nb_streams;i++) {
1449                 AVStream *st;
1450                 st = feed->streams[i];
1451                 s->streams[i] = st;
1452             }
1453             av_write_header(s);
1454             /* XXX: need better api */
1455             av_freep(&s->priv_data);
1456             url_fclose(&s->pb);
1457         }
1458         /* get feed size and write index */
1459         fd = open(feed->feed_filename, O_RDONLY);
1460         if (fd < 0) {
1461             fprintf(stderr, "Could not open output feed file '%s'\n",
1462                     feed->feed_filename);
1463             exit(1);
1464         }
1465
1466         feed->feed_write_index = ffm_read_write_index(fd);
1467         feed->feed_size = lseek(fd, 0, SEEK_END);
1468         /* ensure that we do not wrap before the end of file */
1469         if (feed->feed_max_size < feed->feed_size)
1470             feed->feed_max_size = feed->feed_size;
1471
1472         close(fd);
1473     }
1474 }
1475
1476 static void get_arg(char *buf, int buf_size, const char **pp)
1477 {
1478     const char *p;
1479     char *q;
1480     int quote;
1481
1482     p = *pp;
1483     while (isspace(*p)) p++;
1484     q = buf;
1485     quote = 0;
1486     if (*p == '\"' || *p == '\'')
1487         quote = *p++;
1488     for(;;) {
1489         if (quote) {
1490             if (*p == quote)
1491                 break;
1492         } else {
1493             if (isspace(*p))
1494                 break;
1495         }
1496         if (*p == '\0')
1497             break;
1498         if ((q - buf) < buf_size - 1)
1499             *q++ = *p;
1500         p++;
1501     }
1502     *q = '\0';
1503     if (quote && *p == quote)
1504         p++;
1505     *pp = p;
1506 }
1507
1508 /* add a codec and set the default parameters */
1509 void add_codec(FFStream *stream, AVCodecContext *av)
1510 {
1511     AVStream *st;
1512
1513     /* compute default parameters */
1514     switch(av->codec_type) {
1515     case CODEC_TYPE_AUDIO:
1516         if (av->bit_rate == 0)
1517             av->bit_rate = 64000;
1518         if (av->sample_rate == 0)
1519             av->sample_rate = 22050;
1520         if (av->channels == 0)
1521             av->channels = 1;
1522         break;
1523     case CODEC_TYPE_VIDEO:
1524         if (av->bit_rate == 0)
1525             av->bit_rate = 64000;
1526         if (av->frame_rate == 0)
1527             av->frame_rate = 5 * FRAME_RATE_BASE;
1528         if (av->width == 0 || av->height == 0) {
1529             av->width = 160;
1530             av->height = 128;
1531         }
1532         /* Bitrate tolerance is less for streaming */
1533         if (av->bit_rate_tolerance == 0)
1534             av->bit_rate_tolerance = av->bit_rate / 4;
1535         if (av->qmin == 0)
1536             av->qmin = 3;
1537         if (av->qmax == 0)
1538             av->qmax = 31;
1539         if (av->max_qdiff == 0)
1540             av->max_qdiff = 3;
1541         av->qcompress = 0.5;
1542         av->qblur = 0.5;
1543
1544         break;
1545     default:
1546         av_abort();
1547     }
1548
1549     st = av_mallocz(sizeof(AVStream));
1550     if (!st)
1551         return;
1552     stream->streams[stream->nb_streams++] = st;
1553     memcpy(&st->codec, av, sizeof(AVCodecContext));
1554 }
1555
1556 int opt_audio_codec(const char *arg)
1557 {
1558     AVCodec *p;
1559
1560     p = first_avcodec;
1561     while (p) {
1562         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
1563             break;
1564         p = p->next;
1565     }
1566     if (p == NULL) {
1567         return CODEC_ID_NONE;
1568     }
1569
1570     return p->id;
1571 }
1572
1573 int opt_video_codec(const char *arg)
1574 {
1575     AVCodec *p;
1576
1577     p = first_avcodec;
1578     while (p) {
1579         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
1580             break;
1581         p = p->next;
1582     }
1583     if (p == NULL) {
1584         return CODEC_ID_NONE;
1585     }
1586
1587     return p->id;
1588 }
1589
1590 int parse_ffconfig(const char *filename)
1591 {
1592     FILE *f;
1593     char line[1024];
1594     char cmd[64];
1595     char arg[1024];
1596     const char *p;
1597     int val, errors, line_num;
1598     FFStream **last_stream, *stream;
1599     FFStream **last_feed, *feed;
1600     AVCodecContext audio_enc, video_enc;
1601     int audio_id, video_id;
1602
1603     f = fopen(filename, "r");
1604     if (!f) {
1605         perror(filename);
1606         return -1;
1607     }
1608     
1609     errors = 0;
1610     line_num = 0;
1611     first_stream = NULL;
1612     last_stream = &first_stream;
1613     first_feed = NULL;
1614     last_feed = &first_feed;
1615     stream = NULL;
1616     feed = NULL;
1617     audio_id = CODEC_ID_NONE;
1618     video_id = CODEC_ID_NONE;
1619     for(;;) {
1620         if (fgets(line, sizeof(line), f) == NULL)
1621             break;
1622         line_num++;
1623         p = line;
1624         while (isspace(*p)) 
1625             p++;
1626         if (*p == '\0' || *p == '#')
1627             continue;
1628
1629         get_arg(cmd, sizeof(cmd), &p);
1630         
1631         if (!strcasecmp(cmd, "Port")) {
1632             get_arg(arg, sizeof(arg), &p);
1633             my_addr.sin_port = htons (atoi(arg));
1634         } else if (!strcasecmp(cmd, "BindAddress")) {
1635             get_arg(arg, sizeof(arg), &p);
1636             if (!inet_aton(arg, &my_addr.sin_addr)) {
1637                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
1638                         filename, line_num, arg);
1639                 errors++;
1640             }
1641         } else if (!strcasecmp(cmd, "MaxClients")) {
1642             get_arg(arg, sizeof(arg), &p);
1643             val = atoi(arg);
1644             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
1645                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
1646                         filename, line_num, arg);
1647                 errors++;
1648             } else {
1649                 nb_max_connections = val;
1650             }
1651         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
1652             get_arg(arg, sizeof(arg), &p);
1653             val = atoi(arg);
1654             if (val < 10 || val > 100000) {
1655                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
1656                         filename, line_num, arg);
1657                 errors++;
1658             } else {
1659                 nb_max_bandwidth = val;
1660             }
1661         } else if (!strcasecmp(cmd, "CustomLog")) {
1662             get_arg(logfilename, sizeof(logfilename), &p);
1663         } else if (!strcasecmp(cmd, "<Feed")) {
1664             /*********************************************/
1665             /* Feed related options */
1666             char *q;
1667             if (stream || feed) {
1668                 fprintf(stderr, "%s:%d: Already in a tag\n",
1669                         filename, line_num);
1670             } else {
1671                 feed = av_mallocz(sizeof(FFStream));
1672                 /* add in stream list */
1673                 *last_stream = feed;
1674                 last_stream = &feed->next;
1675                 /* add in feed list */
1676                 *last_feed = feed;
1677                 last_feed = &feed->next_feed;
1678                 
1679                 get_arg(feed->filename, sizeof(feed->filename), &p);
1680                 q = strrchr(feed->filename, '>');
1681                 if (*q)
1682                     *q = '\0';
1683                 feed->fmt = guess_format("ffm", NULL, NULL);
1684                 /* defaut feed file */
1685                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
1686                          "/tmp/%s.ffm", feed->filename);
1687                 feed->feed_max_size = 5 * 1024 * 1024;
1688                 feed->is_feed = 1;
1689                 feed->feed = feed; /* self feeding :-) */
1690             }
1691         } else if (!strcasecmp(cmd, "File")) {
1692             if (feed) {
1693                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
1694             } else if (stream) {
1695                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
1696             }
1697         } else if (!strcasecmp(cmd, "FileMaxSize")) {
1698             if (feed) {
1699                 const char *p1;
1700                 double fsize;
1701
1702                 get_arg(arg, sizeof(arg), &p);
1703                 p1 = arg;
1704                 fsize = strtod(p1, (char **)&p1);
1705                 switch(toupper(*p1)) {
1706                 case 'K':
1707                     fsize *= 1024;
1708                     break;
1709                 case 'M':
1710                     fsize *= 1024 * 1024;
1711                     break;
1712                 case 'G':
1713                     fsize *= 1024 * 1024 * 1024;
1714                     break;
1715                 }
1716                 feed->feed_max_size = (INT64)fsize;
1717             }
1718         } else if (!strcasecmp(cmd, "</Feed>")) {
1719             if (!feed) {
1720                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
1721                         filename, line_num);
1722                 errors++;
1723             } else {
1724                 /* Make sure that we start out clean */
1725                 if (unlink(feed->feed_filename) < 0 
1726                     && errno != ENOENT) {
1727                     fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
1728                         filename, line_num, feed->feed_filename, strerror(errno));
1729                     errors++;
1730                 }
1731             }
1732             feed = NULL;
1733         } else if (!strcasecmp(cmd, "<Stream")) {
1734             /*********************************************/
1735             /* Stream related options */
1736             char *q;
1737             if (stream || feed) {
1738                 fprintf(stderr, "%s:%d: Already in a tag\n",
1739                         filename, line_num);
1740             } else {
1741                 stream = av_mallocz(sizeof(FFStream));
1742                 *last_stream = stream;
1743                 last_stream = &stream->next;
1744
1745                 get_arg(stream->filename, sizeof(stream->filename), &p);
1746                 q = strrchr(stream->filename, '>');
1747                 if (*q)
1748                     *q = '\0';
1749                 stream->fmt = guess_format(NULL, stream->filename, NULL);
1750                 memset(&audio_enc, 0, sizeof(AVCodecContext));
1751                 memset(&video_enc, 0, sizeof(AVCodecContext));
1752                 audio_id = CODEC_ID_NONE;
1753                 video_id = CODEC_ID_NONE;
1754                 if (stream->fmt) {
1755                     audio_id = stream->fmt->audio_codec;
1756                     video_id = stream->fmt->video_codec;
1757                 }
1758             }
1759         } else if (!strcasecmp(cmd, "Feed")) {
1760             get_arg(arg, sizeof(arg), &p);
1761             if (stream) {
1762                 FFStream *sfeed;
1763                 
1764                 sfeed = first_feed;
1765                 while (sfeed != NULL) {
1766                     if (!strcmp(sfeed->filename, arg))
1767                         break;
1768                     sfeed = sfeed->next_feed;
1769                 }
1770                 if (!sfeed) {
1771                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
1772                             filename, line_num, arg);
1773                 } else {
1774                     stream->feed = sfeed;
1775                 }
1776             }
1777         } else if (!strcasecmp(cmd, "Format")) {
1778             get_arg(arg, sizeof(arg), &p);
1779             if (!strcmp(arg, "status")) {
1780                 stream->stream_type = STREAM_TYPE_STATUS;
1781                 stream->fmt = NULL;
1782             } else {
1783                 stream->stream_type = STREAM_TYPE_LIVE;
1784                 /* jpeg cannot be used here, so use single frame jpeg */
1785                 if (!strcmp(arg, "jpeg"))
1786                     strcpy(arg, "singlejpeg");
1787                 stream->fmt = guess_format(arg, NULL, NULL);
1788                 if (!stream->fmt) {
1789                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
1790                             filename, line_num, arg);
1791                     errors++;
1792                 }
1793             }
1794             if (stream->fmt) {
1795                 audio_id = stream->fmt->audio_codec;
1796                 video_id = stream->fmt->video_codec;
1797             }
1798         } else if (!strcasecmp(cmd, "Preroll")) {
1799             get_arg(arg, sizeof(arg), &p);
1800             if (stream) {
1801                 stream->prebuffer = atoi(arg) * 1000;
1802             }
1803         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
1804             if (stream) {
1805                 stream->send_on_key = 1;
1806             }
1807         } else if (!strcasecmp(cmd, "AudioCodec")) {
1808             get_arg(arg, sizeof(arg), &p);
1809             audio_id = opt_audio_codec(arg);
1810             if (audio_id == CODEC_ID_NONE) {
1811                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
1812                         filename, line_num, arg);
1813                 errors++;
1814             }
1815         } else if (!strcasecmp(cmd, "VideoCodec")) {
1816             get_arg(arg, sizeof(arg), &p);
1817             video_id = opt_video_codec(arg);
1818             if (video_id == CODEC_ID_NONE) {
1819                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
1820                         filename, line_num, arg);
1821                 errors++;
1822             }
1823         } else if (!strcasecmp(cmd, "MaxTime")) {
1824             get_arg(arg, sizeof(arg), &p);
1825             if (stream) {
1826                 stream->max_time = atoi(arg);
1827             }
1828         } else if (!strcasecmp(cmd, "AudioBitRate")) {
1829             get_arg(arg, sizeof(arg), &p);
1830             if (stream) {
1831                 audio_enc.bit_rate = atoi(arg) * 1000;
1832             }
1833         } else if (!strcasecmp(cmd, "AudioChannels")) {
1834             get_arg(arg, sizeof(arg), &p);
1835             if (stream) {
1836                 audio_enc.channels = atoi(arg);
1837             }
1838         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
1839             get_arg(arg, sizeof(arg), &p);
1840             if (stream) {
1841                 audio_enc.sample_rate = atoi(arg);
1842             }
1843         } else if (!strcasecmp(cmd, "VideoBitRate")) {
1844             get_arg(arg, sizeof(arg), &p);
1845             if (stream) {
1846                 video_enc.bit_rate = atoi(arg) * 1000;
1847             }
1848         } else if (!strcasecmp(cmd, "VideoSize")) {
1849             get_arg(arg, sizeof(arg), &p);
1850             if (stream) {
1851                 parse_image_size(&video_enc.width, &video_enc.height, arg);
1852                 if ((video_enc.width % 16) != 0 ||
1853                     (video_enc.height % 16) != 0) {
1854                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
1855                             filename, line_num);
1856                     errors++;
1857                 }
1858             }
1859         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
1860             get_arg(arg, sizeof(arg), &p);
1861             if (stream) {
1862                 video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
1863             }
1864         } else if (!strcasecmp(cmd, "VideoGopSize")) {
1865             get_arg(arg, sizeof(arg), &p);
1866             if (stream) {
1867                 video_enc.gop_size = atoi(arg);
1868             }
1869         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
1870             if (stream) {
1871                 video_enc.gop_size = 1;
1872             }
1873         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
1874             if (stream) {
1875                 video_enc.flags |= CODEC_FLAG_HQ;
1876             }
1877         } else if (!strcasecmp(cmd, "VideoQDiff")) {
1878             if (stream) {
1879                 video_enc.max_qdiff = atoi(arg);
1880                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
1881                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
1882                             filename, line_num);
1883                     errors++;
1884                 }
1885             }
1886         } else if (!strcasecmp(cmd, "VideoQMax")) {
1887             if (stream) {
1888                 video_enc.qmax = atoi(arg);
1889                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
1890                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
1891                             filename, line_num);
1892                     errors++;
1893                 }
1894             }
1895         } else if (!strcasecmp(cmd, "VideoQMin")) {
1896             if (stream) {
1897                 video_enc.qmin = atoi(arg);
1898                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
1899                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
1900                             filename, line_num);
1901                     errors++;
1902                 }
1903             }
1904         } else if (!strcasecmp(cmd, "NoVideo")) {
1905             video_id = CODEC_ID_NONE;
1906         } else if (!strcasecmp(cmd, "NoAudio")) {
1907             audio_id = CODEC_ID_NONE;
1908         } else if (!strcasecmp(cmd, "</Stream>")) {
1909             if (!stream) {
1910                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
1911                         filename, line_num);
1912                 errors++;
1913             }
1914             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
1915                 if (audio_id != CODEC_ID_NONE) {
1916                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
1917                     audio_enc.codec_id = audio_id;
1918                     add_codec(stream, &audio_enc);
1919                 }
1920                 if (video_id != CODEC_ID_NONE) {
1921                     video_enc.codec_type = CODEC_TYPE_VIDEO;
1922                     video_enc.codec_id = video_id;
1923                     add_codec(stream, &video_enc);
1924                 }
1925             }
1926             stream = NULL;
1927         } else {
1928             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
1929                     filename, line_num, cmd);
1930             errors++;
1931         }
1932     }
1933
1934     fclose(f);
1935     if (errors)
1936         return -1;
1937     else
1938         return 0;
1939 }
1940
1941
1942 void *http_server_thread(void *arg)
1943 {
1944     http_server(my_addr);
1945     return NULL;
1946 }
1947
1948 #if 0
1949 static void write_packet(FFCodec *ffenc,
1950                          UINT8 *buf, int size)
1951 {
1952     PacketHeader hdr;
1953     AVCodecContext *enc = &ffenc->enc;
1954     UINT8 *wptr;
1955     mk_header(&hdr, enc, size);
1956     wptr = http_fifo.wptr;
1957     fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
1958     fifo_write(&http_fifo, buf, size, &wptr);
1959     /* atomic modification of wptr */
1960     http_fifo.wptr = wptr;
1961     ffenc->data_count += size;
1962     ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
1963 }
1964 #endif
1965
1966 void help(void)
1967 {
1968     printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Gerard Lantau\n"
1969            "usage: ffserver [-L] [-h] [-f configfile]\n"
1970            "Hyper fast multi format Audio/Video streaming server\n"
1971            "\n"
1972            "-L            : print the LICENCE\n"
1973            "-h            : this help\n"
1974            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
1975            );
1976 }
1977
1978 void licence(void)
1979 {
1980     printf(
1981     "ffserver version " FFMPEG_VERSION "\n"
1982     "Copyright (c) 2000, 2001, 2002 Gerard Lantau\n"
1983     "This program is free software; you can redistribute it and/or modify\n"
1984     "it under the terms of the GNU General Public License as published by\n"
1985     "the Free Software Foundation; either version 2 of the License, or\n"
1986     "(at your option) any later version.\n"
1987     "\n"
1988     "This program is distributed in the hope that it will be useful,\n"
1989     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1990     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1991     "GNU General Public License for more details.\n"
1992     "\n"
1993     "You should have received a copy of the GNU General Public License\n"
1994     "along with this program; if not, write to the Free Software\n"
1995     "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
1996     );
1997 }
1998
1999 int main(int argc, char **argv)
2000 {
2001     const char *config_filename;
2002     int c;
2003
2004     register_all();
2005
2006     config_filename = "/etc/ffserver.conf";
2007
2008     for(;;) {
2009         c = getopt_long_only(argc, argv, "Lh?f:", NULL, NULL);
2010         if (c == -1)
2011             break;
2012         switch(c) {
2013         case 'L':
2014             licence();
2015             exit(1);
2016         case '?':
2017         case 'h':
2018             help();
2019             exit(1);
2020         case 'f':
2021             config_filename = optarg;
2022             break;
2023         default:
2024             exit(2);
2025         }
2026     }
2027
2028     /* address on which the server will handle connections */
2029     my_addr.sin_family = AF_INET;
2030     my_addr.sin_port = htons (8080);
2031     my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
2032     nb_max_connections = 5;
2033     nb_max_bandwidth = 1000;
2034     first_stream = NULL;
2035     logfilename[0] = '\0';
2036
2037     if (parse_ffconfig(config_filename) < 0) {
2038         fprintf(stderr, "Incorrect config file - exiting.\n");
2039         exit(1);
2040     }
2041
2042     build_feed_streams();
2043
2044     /* signal init */
2045     signal(SIGPIPE, SIG_IGN);
2046
2047     /* open log file if needed */
2048     if (logfilename[0] != '\0') {
2049         if (!strcmp(logfilename, "-"))
2050             logfile = stdout;
2051         else
2052             logfile = fopen(logfilename, "w");
2053     }
2054
2055     if (http_server(my_addr) < 0) {
2056         fprintf(stderr, "Could start http server\n");
2057         exit(1);
2058     }
2059
2060     return 0;
2061 }