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