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