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