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