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