* const warning fix
[ffmpeg.git] / 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 <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/wait.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #include <ctype.h>
37 #include <signal.h>
38 #include <dlfcn.h>
39
40 #include "ffserver.h"
41
42 /* maximum number of simultaneous HTTP connections */
43 #define HTTP_MAX_CONNECTIONS 2000
44
45 enum HTTPState {
46     HTTPSTATE_WAIT_REQUEST,
47     HTTPSTATE_SEND_HEADER,
48     HTTPSTATE_SEND_DATA_HEADER,
49     HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
50     HTTPSTATE_SEND_DATA_TRAILER,
51     HTTPSTATE_RECEIVE_DATA,       
52     HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
53     HTTPSTATE_WAIT,               /* wait before sending next packets */
54     HTTPSTATE_WAIT_SHORT,         /* short wait for short term 
55                                      bandwidth limitation */
56     HTTPSTATE_READY,
57
58     RTSPSTATE_WAIT_REQUEST,
59     RTSPSTATE_SEND_REPLY,
60 };
61
62 const char *http_state[] = {
63     "HTTP_WAIT_REQUEST",
64     "HTTP_SEND_HEADER",
65
66     "SEND_DATA_HEADER",
67     "SEND_DATA",
68     "SEND_DATA_TRAILER",
69     "RECEIVE_DATA",
70     "WAIT_FEED",
71     "WAIT",
72     "WAIT_SHORT",
73     "READY",
74
75     "RTSP_WAIT_REQUEST",
76     "RTSP_SEND_REPLY",
77 };
78
79 #define IOBUFFER_INIT_SIZE 8192
80
81 /* coef for exponential mean for bitrate estimation in statistics */
82 #define AVG_COEF 0.9
83
84 /* timeouts are in ms */
85 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
86 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
87
88 #define SYNC_TIMEOUT (10 * 1000)
89
90 typedef struct {
91     INT64 count1, count2;
92     long time1, time2;
93 } DataRateData;
94
95 /* context associated with one connection */
96 typedef struct HTTPContext {
97     enum HTTPState state;
98     int fd; /* socket file descriptor */
99     struct sockaddr_in from_addr; /* origin */
100     struct pollfd *poll_entry; /* used when polling */
101     long timeout;
102     UINT8 *buffer_ptr, *buffer_end;
103     int http_error;
104     struct HTTPContext *next;
105     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
106     INT64 data_count;
107     /* feed input */
108     int feed_fd;
109     /* input format handling */
110     AVFormatContext *fmt_in;
111     long start_time;            /* In milliseconds - this wraps fairly often */
112     INT64 first_pts;            /* initial pts value */
113     int pts_stream_index;       /* stream we choose as clock reference */
114     /* output format handling */
115     struct FFStream *stream;
116     /* -1 is invalid stream */
117     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
118     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
119     int switch_pending;
120     AVFormatContext fmt_ctx; /* instance of FFStream for one user */
121     int last_packet_sent; /* true if last data packet was sent */
122     int suppress_log;
123     int bandwidth;
124     DataRateData datarate;
125     int wmp_client_id;
126     char protocol[16];
127     char method[16];
128     char url[128];
129     int buffer_size;
130     UINT8 *buffer;
131     int is_packetized; /* if true, the stream is packetized */
132     int packet_stream_index; /* current stream for output in state machine */
133     
134     /* RTSP state specific */
135     UINT8 *pb_buffer; /* XXX: use that in all the code */
136     ByteIOContext *pb;
137     int seq; /* RTSP sequence number */
138
139     /* RTP state specific */
140     enum RTSPProtocol rtp_protocol;
141     char session_id[32]; /* session id */
142     AVFormatContext *rtp_ctx[MAX_STREAMS];
143     URLContext *rtp_handles[MAX_STREAMS];
144     /* RTP short term bandwidth limitation */
145     int packet_byte_count;
146     int packet_start_time_us; /* used for short durations (a few
147                                  seconds max) */
148 } HTTPContext;
149
150 /* each generated stream is described here */
151 enum StreamType {
152     STREAM_TYPE_LIVE,
153     STREAM_TYPE_STATUS,
154     STREAM_TYPE_REDIRECT,
155 };
156
157 enum IPAddressAction {
158     IP_ALLOW = 1,
159     IP_DENY,
160 };
161
162 typedef struct IPAddressACL {
163     struct IPAddressACL *next;
164     enum IPAddressAction action;
165     struct in_addr first;
166     struct in_addr last;
167 } IPAddressACL;
168
169 /* description of each stream of the ffserver.conf file */
170 typedef struct FFStream {
171     enum StreamType stream_type;
172     char filename[1024];     /* stream filename */
173     struct FFStream *feed;   /* feed we are using (can be null if
174                                 coming from file) */
175     AVOutputFormat *fmt;
176     IPAddressACL *acl;
177     int nb_streams;
178     int prebuffer;      /* Number of millseconds early to start */
179     long max_time;      /* Number of milliseconds to run */
180     int send_on_key;
181     AVStream *streams[MAX_STREAMS];
182     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
183     char feed_filename[1024]; /* file name of the feed storage, or
184                                  input file name for a stream */
185     char author[512];
186     char title[512];
187     char copyright[512];
188     char comment[512];
189     pid_t pid;  /* Of ffmpeg process */
190     time_t pid_start;  /* Of ffmpeg process */
191     char **child_argv;
192     struct FFStream *next;
193     /* RTSP options */
194     char *rtsp_option;
195     /* feed specific */
196     int feed_opened;     /* true if someone is writing to the feed */
197     int is_feed;         /* true if it is a feed */
198     int conns_served;
199     INT64 bytes_served;
200     INT64 feed_max_size;      /* maximum storage size */
201     INT64 feed_write_index;   /* current write position in feed (it wraps round) */
202     INT64 feed_size;          /* current size of feed */
203     struct FFStream *next_feed;
204 } FFStream;
205
206 typedef struct FeedData {
207     long long data_count;
208     float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
209 } FeedData;
210
211 struct sockaddr_in my_http_addr;
212 struct sockaddr_in my_rtsp_addr;
213
214 char logfilename[1024];
215 HTTPContext *first_http_ctx;
216 FFStream *first_feed;   /* contains only feeds */
217 FFStream *first_stream; /* contains all streams, including feeds */
218
219 static void new_connection(int server_fd, int is_rtsp);
220 static void close_connection(HTTPContext *c);
221
222 /* HTTP handling */
223 static int handle_connection(HTTPContext *c);
224 static int http_parse_request(HTTPContext *c);
225 static int http_send_data(HTTPContext *c);
226 static void compute_stats(HTTPContext *c);
227 static int open_input_stream(HTTPContext *c, const char *info);
228 static int http_start_receive_data(HTTPContext *c);
229 static int http_receive_data(HTTPContext *c);
230 static int compute_send_delay(HTTPContext *c);
231
232 /* RTSP handling */
233 static int rtsp_parse_request(HTTPContext *c);
234 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
235 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
236 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
237 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
238 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
239
240 /* RTP handling */
241 static HTTPContext *rtp_new_connection(HTTPContext *rtsp_c, 
242                                        FFStream *stream, const char *session_id);
243 static int rtp_new_av_stream(HTTPContext *c, 
244                              int stream_index, struct sockaddr_in *dest_addr);
245
246 static const char *my_program_name;
247 static const char *my_program_dir;
248
249 static int ffserver_debug;
250 static int ffserver_daemon;
251 static int no_launch;
252 static int need_to_start_children;
253
254 int nb_max_connections;
255 int nb_connections;
256
257 int nb_max_bandwidth;
258 int nb_bandwidth;
259
260 static long cur_time;           // Making this global saves on passing it around everywhere
261
262 static long gettime_ms(void)
263 {
264     struct timeval tv;
265
266     gettimeofday(&tv,NULL);
267     return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
268 }
269
270 static FILE *logfile = NULL;
271
272 static void http_log(char *fmt, ...)
273 {
274     va_list ap;
275     va_start(ap, fmt);
276     
277     if (logfile) {
278         vfprintf(logfile, fmt, ap);
279         fflush(logfile);
280     }
281     va_end(ap);
282 }
283
284 static void log_connection(HTTPContext *c)
285 {
286     char buf1[32], buf2[32], *p;
287     time_t ti;
288
289     if (c->suppress_log) 
290         return;
291
292     /* XXX: reentrant function ? */
293     p = inet_ntoa(c->from_addr.sin_addr);
294     strcpy(buf1, p);
295     ti = time(NULL);
296     p = ctime(&ti);
297     strcpy(buf2, p);
298     p = buf2 + strlen(p) - 1;
299     if (*p == '\n')
300         *p = '\0';
301     http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
302              buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
303 }
304
305 static void update_datarate(DataRateData *drd, INT64 count)
306 {
307     if (!drd->time1 && !drd->count1) {
308         drd->time1 = drd->time2 = cur_time;
309         drd->count1 = drd->count2 = count;
310     } else {
311         if (cur_time - drd->time2 > 5000) {
312             drd->time1 = drd->time2;
313             drd->count1 = drd->count2;
314             drd->time2 = cur_time;
315             drd->count2 = count;
316         }
317     }
318 }
319
320 /* In bytes per second */
321 static int compute_datarate(DataRateData *drd, INT64 count)
322 {
323     if (cur_time == drd->time1)
324         return 0;
325
326     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
327 }
328
329 static int get_longterm_datarate(DataRateData *drd, INT64 count)
330 {
331     /* You get the first 3 seconds flat out */
332     if (cur_time - drd->time1 < 3000)
333         return 0;
334
335     return compute_datarate(drd, count);
336 }
337
338
339 static void start_children(FFStream *feed)
340 {
341     if (no_launch)
342         return;
343
344     for (; feed; feed = feed->next) {
345         if (feed->child_argv && !feed->pid) {
346             feed->pid_start = time(0);
347
348             feed->pid = fork();
349
350             if (feed->pid < 0) {
351                 fprintf(stderr, "Unable to create children\n");
352                 exit(1);
353             }
354             if (!feed->pid) {
355                 /* In child */
356                 char pathname[1024];
357                 char *slash;
358                 int i;
359
360                 for (i = 3; i < 256; i++) {
361                     close(i);
362                 }
363
364                 if (!ffserver_debug) {
365                     i = open("/dev/null", O_RDWR);
366                     if (i)
367                         dup2(i, 0);
368                     dup2(i, 1);
369                     dup2(i, 2);
370                     if (i)
371                         close(i);
372                 }
373
374                 pstrcpy(pathname, sizeof(pathname), my_program_name);
375
376                 slash = strrchr(pathname, '/');
377                 if (!slash) {
378                     slash = pathname;
379                 } else {
380                     slash++;
381                 }
382                 strcpy(slash, "ffmpeg");
383
384                 /* This is needed to make relative pathnames work */
385                 chdir(my_program_dir);
386
387                 execvp(pathname, feed->child_argv);
388
389                 _exit(1);
390             }
391         }
392     }
393 }
394
395 /* open a listening socket */
396 static int socket_open_listen(struct sockaddr_in *my_addr)
397 {
398     int server_fd, tmp;
399
400     server_fd = socket(AF_INET,SOCK_STREAM,0);
401     if (server_fd < 0) {
402         perror ("socket");
403         return -1;
404     }
405         
406     tmp = 1;
407     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
408
409     if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
410         perror ("bind");
411         close(server_fd);
412         return -1;
413     }
414   
415     if (listen (server_fd, 5) < 0) {
416         perror ("listen");
417         close(server_fd);
418         return -1;
419     }
420     fcntl(server_fd, F_SETFL, O_NONBLOCK);
421
422     return server_fd;
423 }
424
425
426 /* main loop of the http server */
427 static int http_server(void)
428 {
429     int server_fd, ret, rtsp_server_fd, delay, delay1;
430     struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
431     HTTPContext *c, *c_next;
432
433     server_fd = socket_open_listen(&my_http_addr);
434     if (server_fd < 0)
435         return -1;
436
437     rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
438     if (rtsp_server_fd < 0)
439         return -1;
440     
441     http_log("ffserver started.\n");
442
443     start_children(first_feed);
444
445     first_http_ctx = NULL;
446     nb_connections = 0;
447     first_http_ctx = NULL;
448     for(;;) {
449         poll_entry = poll_table;
450         poll_entry->fd = server_fd;
451         poll_entry->events = POLLIN;
452         poll_entry++;
453
454         poll_entry->fd = rtsp_server_fd;
455         poll_entry->events = POLLIN;
456         poll_entry++;
457
458         /* wait for events on each HTTP handle */
459         c = first_http_ctx;
460         delay = 1000;
461         while (c != NULL) {
462             int fd;
463             fd = c->fd;
464             switch(c->state) {
465             case HTTPSTATE_SEND_HEADER:
466             case RTSPSTATE_SEND_REPLY:
467                 c->poll_entry = poll_entry;
468                 poll_entry->fd = fd;
469                 poll_entry->events = POLLOUT;
470                 poll_entry++;
471                 break;
472             case HTTPSTATE_SEND_DATA_HEADER:
473             case HTTPSTATE_SEND_DATA:
474             case HTTPSTATE_SEND_DATA_TRAILER:
475                 if (!c->is_packetized) {
476                     /* for TCP, we output as much as we can (may need to put a limit) */
477                     c->poll_entry = poll_entry;
478                     poll_entry->fd = fd;
479                     poll_entry->events = POLLOUT;
480                     poll_entry++;
481                 } else {
482                     /* not strictly correct, but currently cannot add
483                        more than one fd in poll entry */
484                     delay = 0;
485                 }
486                 break;
487             case HTTPSTATE_WAIT_REQUEST:
488             case HTTPSTATE_RECEIVE_DATA:
489             case HTTPSTATE_WAIT_FEED:
490             case RTSPSTATE_WAIT_REQUEST:
491                 /* need to catch errors */
492                 c->poll_entry = poll_entry;
493                 poll_entry->fd = fd;
494                 poll_entry->events = POLLIN;/* Maybe this will work */
495                 poll_entry++;
496                 break;
497             case HTTPSTATE_WAIT:
498                 c->poll_entry = NULL;
499                 delay1 = compute_send_delay(c);
500                 if (delay1 < delay)
501                     delay = delay1;
502                 break;
503             case HTTPSTATE_WAIT_SHORT:
504                 c->poll_entry = NULL;
505                 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
506                 if (delay1 < delay)
507                     delay = delay1;
508                 break;
509             default:
510                 c->poll_entry = NULL;
511                 break;
512             }
513             c = c->next;
514         }
515
516         /* wait for an event on one connection. We poll at least every
517            second to handle timeouts */
518         do {
519             ret = poll(poll_table, poll_entry - poll_table, delay);
520         } while (ret == -1);
521         
522         cur_time = gettime_ms();
523
524         if (need_to_start_children) {
525             need_to_start_children = 0;
526             start_children(first_feed);
527         }
528
529         /* now handle the events */
530         for(c = first_http_ctx; c != NULL; c = c_next) {
531             c_next = c->next;
532             if (handle_connection(c) < 0) {
533                 /* close and free the connection */
534                 log_connection(c);
535                 close_connection(c);
536             }
537         }
538
539         poll_entry = poll_table;
540         /* new HTTP connection request ? */
541         if (poll_entry->revents & POLLIN) {
542             new_connection(server_fd, 0);
543         }
544         poll_entry++;
545         /* new RTSP connection request ? */
546         if (poll_entry->revents & POLLIN) {
547             new_connection(rtsp_server_fd, 1);
548         }
549     }
550 }
551
552 /* start waiting for a new HTTP/RTSP request */
553 static void start_wait_request(HTTPContext *c, int is_rtsp)
554 {
555     c->buffer_ptr = c->buffer;
556     c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
557
558     if (is_rtsp) {
559         c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
560         c->state = RTSPSTATE_WAIT_REQUEST;
561     } else {
562         c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
563         c->state = HTTPSTATE_WAIT_REQUEST;
564     }
565 }
566
567 static void new_connection(int server_fd, int is_rtsp)
568 {
569     struct sockaddr_in from_addr;
570     int fd, len;
571     HTTPContext *c = NULL;
572
573     len = sizeof(from_addr);
574     fd = accept(server_fd, (struct sockaddr *)&from_addr, 
575                 &len);
576     if (fd < 0)
577         return;
578     fcntl(fd, F_SETFL, O_NONBLOCK);
579
580     /* XXX: should output a warning page when coming
581        close to the connection limit */
582     if (nb_connections >= nb_max_connections)
583         goto fail;
584     
585     /* add a new connection */
586     c = av_mallocz(sizeof(HTTPContext));
587     if (!c)
588         goto fail;
589     
590     c->next = first_http_ctx;
591     first_http_ctx = c;
592     c->fd = fd;
593     c->poll_entry = NULL;
594     c->from_addr = from_addr;
595     c->buffer_size = IOBUFFER_INIT_SIZE;
596     c->buffer = av_malloc(c->buffer_size);
597     if (!c->buffer)
598         goto fail;
599     nb_connections++;
600     
601     start_wait_request(c, is_rtsp);
602
603     return;
604
605  fail:
606     if (c) {
607         av_free(c->buffer);
608         av_free(c);
609     }
610     close(fd);
611 }
612
613 static void close_connection(HTTPContext *c)
614 {
615     HTTPContext **cp, *c1;
616     int i, nb_streams;
617     AVFormatContext *ctx;
618     URLContext *h;
619     AVStream *st;
620
621     /* remove connection from list */
622     cp = &first_http_ctx;
623     while ((*cp) != NULL) {
624         c1 = *cp;
625         if (c1 == c) {
626             *cp = c->next;
627         } else {
628             cp = &c1->next;
629         }
630     }
631
632     /* remove connection associated resources */
633     if (c->fd >= 0)
634         close(c->fd);
635     if (c->fmt_in) {
636         /* close each frame parser */
637         for(i=0;i<c->fmt_in->nb_streams;i++) {
638             st = c->fmt_in->streams[i];
639             if (st->codec.codec) {
640                 avcodec_close(&st->codec);
641             }
642         }
643         av_close_input_file(c->fmt_in);
644     }
645
646     /* free RTP output streams if any */
647     nb_streams = 0;
648     if (c->stream) 
649         nb_streams = c->stream->nb_streams;
650     
651     for(i=0;i<nb_streams;i++) {
652         ctx = c->rtp_ctx[i];
653         if (ctx) {
654             av_write_trailer(ctx);
655             av_free(ctx);
656         }
657         h = c->rtp_handles[i];
658         if (h) {
659             url_close(h);
660         }
661     }
662
663     nb_bandwidth -= c->bandwidth;
664     av_freep(&c->pb_buffer);
665     av_free(c->buffer);
666     av_free(c);
667     nb_connections--;
668 }
669
670 static int handle_connection(HTTPContext *c)
671 {
672     int len, ret;
673     
674     switch(c->state) {
675     case HTTPSTATE_WAIT_REQUEST:
676     case RTSPSTATE_WAIT_REQUEST:
677         /* timeout ? */
678         if ((c->timeout - cur_time) < 0)
679             return -1;
680         if (c->poll_entry->revents & (POLLERR | POLLHUP))
681             return -1;
682
683         /* no need to read if no events */
684         if (!(c->poll_entry->revents & POLLIN))
685             return 0;
686         /* read the data */
687         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
688         if (len < 0) {
689             if (errno != EAGAIN && errno != EINTR)
690                 return -1;
691         } else if (len == 0) {
692             return -1;
693         } else {
694             /* search for end of request. XXX: not fully correct since garbage could come after the end */
695             UINT8 *ptr;
696             c->buffer_ptr += len;
697             ptr = c->buffer_ptr;
698             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
699                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
700                 /* request found : parse it and reply */
701                 if (c->state == HTTPSTATE_WAIT_REQUEST) {
702                     ret = http_parse_request(c);
703                 } else {
704                     ret = rtsp_parse_request(c);
705                 }
706                 if (ret < 0)
707                     return -1;
708             } else if (ptr >= c->buffer_end) {
709                 /* request too long: cannot do anything */
710                 return -1;
711             }
712         }
713         break;
714
715     case HTTPSTATE_SEND_HEADER:
716         if (c->poll_entry->revents & (POLLERR | POLLHUP))
717             return -1;
718
719         /* no need to write if no events */
720         if (!(c->poll_entry->revents & POLLOUT))
721             return 0;
722         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
723         if (len < 0) {
724             if (errno != EAGAIN && errno != EINTR) {
725                 /* error : close connection */
726                 av_freep(&c->pb_buffer);
727                 return -1;
728             }
729         } else {
730             c->buffer_ptr += len;
731             if (c->stream)
732                 c->stream->bytes_served += len;
733             c->data_count += len;
734             if (c->buffer_ptr >= c->buffer_end) {
735                 av_freep(&c->pb_buffer);
736                 /* if error, exit */
737                 if (c->http_error) {
738                     return -1;
739                 }
740                 /* all the buffer was sent : synchronize to the incoming stream */
741                 c->state = HTTPSTATE_SEND_DATA_HEADER;
742                 c->buffer_ptr = c->buffer_end = c->buffer;
743             }
744         }
745         break;
746
747     case HTTPSTATE_SEND_DATA:
748     case HTTPSTATE_SEND_DATA_HEADER:
749     case HTTPSTATE_SEND_DATA_TRAILER:
750         /* for packetized output, we consider we can always write (the
751            input streams sets the speed). It may be better to verify
752            that we do not rely too much on the kernel queues */
753         if (!c->is_packetized) {
754             if (c->poll_entry->revents & (POLLERR | POLLHUP))
755                 return -1;
756             
757             /* no need to read if no events */
758             if (!(c->poll_entry->revents & POLLOUT))
759                 return 0;
760         }
761         if (http_send_data(c) < 0)
762             return -1;
763         break;
764     case HTTPSTATE_RECEIVE_DATA:
765         /* no need to read if no events */
766         if (c->poll_entry->revents & (POLLERR | POLLHUP))
767             return -1;
768         if (!(c->poll_entry->revents & POLLIN))
769             return 0;
770         if (http_receive_data(c) < 0)
771             return -1;
772         break;
773     case HTTPSTATE_WAIT_FEED:
774         /* no need to read if no events */
775         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
776             return -1;
777
778         /* nothing to do, we'll be waken up by incoming feed packets */
779         break;
780
781     case HTTPSTATE_WAIT:
782         /* if the delay expired, we can send new packets */
783         if (compute_send_delay(c) <= 0)
784             c->state = HTTPSTATE_SEND_DATA;
785         break;
786     case HTTPSTATE_WAIT_SHORT:
787         /* just return back to send data */
788         c->state = HTTPSTATE_SEND_DATA;
789         break;
790
791     case RTSPSTATE_SEND_REPLY:
792         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
793             av_freep(&c->pb_buffer);
794             return -1;
795         }
796         /* no need to write if no events */
797         if (!(c->poll_entry->revents & POLLOUT))
798             return 0;
799         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
800         if (len < 0) {
801             if (errno != EAGAIN && errno != EINTR) {
802                 /* error : close connection */
803                 av_freep(&c->pb_buffer);
804                 return -1;
805             }
806         } else {
807             c->buffer_ptr += len;
808             c->data_count += len;
809             if (c->buffer_ptr >= c->buffer_end) {
810                 /* all the buffer was sent : wait for a new request */
811                 av_freep(&c->pb_buffer);
812                 start_wait_request(c, 1);
813             }
814         }
815         break;
816     case HTTPSTATE_READY:
817         /* nothing to do */
818         break;
819     default:
820         return -1;
821     }
822     return 0;
823 }
824
825 static int extract_rates(char *rates, int ratelen, const char *request)
826 {
827     const char *p;
828
829     for (p = request; *p && *p != '\r' && *p != '\n'; ) {
830         if (strncasecmp(p, "Pragma:", 7) == 0) {
831             const char *q = p + 7;
832
833             while (*q && *q != '\n' && isspace(*q))
834                 q++;
835
836             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
837                 int stream_no;
838                 int rate_no;
839
840                 q += 20;
841
842                 memset(rates, 0xff, ratelen);
843
844                 while (1) {
845                     while (*q && *q != '\n' && *q != ':')
846                         q++;
847
848                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
849                         break;
850                     }
851                     stream_no--;
852                     if (stream_no < ratelen && stream_no >= 0) {
853                         rates[stream_no] = rate_no;
854                     }
855
856                     while (*q && *q != '\n' && !isspace(*q))
857                         q++;
858                 }
859
860                 return 1;
861             }
862         }
863         p = strchr(p, '\n');
864         if (!p)
865             break;
866
867         p++;
868     }
869
870     return 0;
871 }
872
873 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
874 {
875     int i;
876     int best_bitrate = 100000000;
877     int best = -1;
878
879     for (i = 0; i < feed->nb_streams; i++) {
880         AVCodecContext *feed_codec = &feed->streams[i]->codec;
881
882         if (feed_codec->codec_id != codec->codec_id ||
883             feed_codec->sample_rate != codec->sample_rate ||
884             feed_codec->width != codec->width ||
885             feed_codec->height != codec->height) {
886             continue;
887         }
888
889         /* Potential stream */
890
891         /* We want the fastest stream less than bit_rate, or the slowest 
892          * faster than bit_rate
893          */
894
895         if (feed_codec->bit_rate <= bit_rate) {
896             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
897                 best_bitrate = feed_codec->bit_rate;
898                 best = i;
899             }
900         } else {
901             if (feed_codec->bit_rate < best_bitrate) {
902                 best_bitrate = feed_codec->bit_rate;
903                 best = i;
904             }
905         }
906     }
907
908     return best;
909 }
910
911 static int modify_current_stream(HTTPContext *c, char *rates)
912 {
913     int i;
914     FFStream *req = c->stream;
915     int action_required = 0;
916
917     for (i = 0; i < req->nb_streams; i++) {
918         AVCodecContext *codec = &req->streams[i]->codec;
919
920         switch(rates[i]) {
921             case 0:
922                 c->switch_feed_streams[i] = req->feed_streams[i];
923                 break;
924             case 1:
925                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
926                 break;
927             case 2:
928                 /* Wants off or slow */
929                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
930 #ifdef WANTS_OFF
931                 /* This doesn't work well when it turns off the only stream! */
932                 c->switch_feed_streams[i] = -2;
933                 c->feed_streams[i] = -2;
934 #endif
935                 break;
936         }
937
938         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
939             action_required = 1;
940     }
941
942     return action_required;
943 }
944
945
946 static void do_switch_stream(HTTPContext *c, int i)
947 {
948     if (c->switch_feed_streams[i] >= 0) {
949 #ifdef PHILIP        
950         c->feed_streams[i] = c->switch_feed_streams[i];
951 #endif
952
953         /* Now update the stream */
954     }
955     c->switch_feed_streams[i] = -1;
956 }
957
958 /* XXX: factorize in utils.c ? */
959 /* XXX: take care with different space meaning */
960 static void skip_spaces(const char **pp)
961 {
962     const char *p;
963     p = *pp;
964     while (*p == ' ' || *p == '\t')
965         p++;
966     *pp = p;
967 }
968
969 static void get_word(char *buf, int buf_size, const char **pp)
970 {
971     const char *p;
972     char *q;
973
974     p = *pp;
975     skip_spaces(&p);
976     q = buf;
977     while (!isspace(*p) && *p != '\0') {
978         if ((q - buf) < buf_size - 1)
979             *q++ = *p;
980         p++;
981     }
982     if (buf_size > 0)
983         *q = '\0';
984     *pp = p;
985 }
986
987 static int validate_acl(FFStream *stream, HTTPContext *c)
988 {
989     enum IPAddressAction last_action = IP_DENY;
990     IPAddressACL *acl;
991     struct in_addr *src = &c->from_addr.sin_addr;
992
993     for (acl = stream->acl; acl; acl = acl->next) {
994         if (src->s_addr >= acl->first.s_addr && src->s_addr <= acl->last.s_addr) {
995             return (acl->action == IP_ALLOW) ? 1 : 0;
996         }
997         last_action = acl->action;
998     }
999
1000     /* Nothing matched, so return not the last action */
1001     return (last_action == IP_DENY) ? 1 : 0;
1002 }
1003
1004 /* parse http request and prepare header */
1005 static int http_parse_request(HTTPContext *c)
1006 {
1007     char *p;
1008     int post;
1009     int doing_asx;
1010     int doing_asf_redirector;
1011     int doing_ram;
1012     int doing_rtsp_redirector;
1013     char cmd[32];
1014     char info[1024], *filename;
1015     char url[1024], *q;
1016     char protocol[32];
1017     char msg[1024];
1018     const char *mime_type;
1019     FFStream *stream;
1020     int i;
1021     char ratebuf[32];
1022     char *useragent = 0;
1023
1024     p = c->buffer;
1025     get_word(cmd, sizeof(cmd), (const char **)&p);
1026     pstrcpy(c->method, sizeof(c->method), cmd);
1027
1028     if (!strcmp(cmd, "GET"))
1029         post = 0;
1030     else if (!strcmp(cmd, "POST"))
1031         post = 1;
1032     else
1033         return -1;
1034
1035     get_word(url, sizeof(url), (const char **)&p);
1036     pstrcpy(c->url, sizeof(c->url), url);
1037
1038     get_word(protocol, sizeof(protocol), (const char **)&p);
1039     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1040         return -1;
1041
1042     pstrcpy(c->protocol, sizeof(c->protocol), protocol);
1043     
1044     /* find the filename and the optional info string in the request */
1045     p = url;
1046     if (*p == '/')
1047         p++;
1048     filename = p;
1049     p = strchr(p, '?');
1050     if (p) {
1051         pstrcpy(info, sizeof(info), p);
1052         *p = '\0';
1053     } else {
1054         info[0] = '\0';
1055     }
1056
1057     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1058         if (strncasecmp(p, "User-Agent:", 11) == 0) {
1059             useragent = p + 11;
1060             if (*useragent && *useragent != '\n' && isspace(*useragent))
1061                 useragent++;
1062             break;
1063         }
1064         p = strchr(p, '\n');
1065         if (!p)
1066             break;
1067
1068         p++;
1069     }
1070
1071     if (strlen(filename) > 4 && strcmp(".asx", filename + strlen(filename) - 4) == 0) {
1072         doing_asx = 1;
1073         filename[strlen(filename)-1] = 'f';
1074     } else {
1075         doing_asx = 0;
1076     }
1077
1078     if (strlen(filename) > 4 && strcmp(".asf", filename + strlen(filename) - 4) == 0 &&
1079         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1080         /* if this isn't WMP or lookalike, return the redirector file */
1081         doing_asf_redirector = 1;
1082     } else {
1083         doing_asf_redirector = 0;
1084     }
1085
1086     if (strlen(filename) > 4 && 
1087         (strcmp(".rpm", filename + strlen(filename) - 4) == 0 ||
1088          strcmp(".ram", filename + strlen(filename) - 4) == 0)) {
1089         doing_ram = 1;
1090         strcpy(filename + strlen(filename)-2, "m");
1091     } else {
1092         doing_ram = 0;
1093     }
1094
1095     if (strlen(filename) > 5 && 
1096         strcmp(".rtsp", filename + strlen(filename) - 5) == 0) {
1097         char file1[1024];
1098         char file2[1024];
1099         char *p;
1100
1101         doing_rtsp_redirector = 1;
1102         /* compute filename by matching without the file extensions */
1103         pstrcpy(file1, sizeof(file1), filename);
1104         p = strrchr(file1, '.');
1105         if (p)
1106             *p = '\0';
1107         for(stream = first_stream; stream != NULL; stream = stream->next) {
1108             pstrcpy(file2, sizeof(file2), stream->filename);
1109             p = strrchr(file2, '.');
1110             if (p)
1111                 *p = '\0';
1112             if (!strcmp(file1, file2)) {
1113                 pstrcpy(url, sizeof(url), stream->filename);
1114                 filename = url;
1115                 break;
1116             }
1117         }
1118     } else {
1119         doing_rtsp_redirector = 0;
1120     }
1121
1122     stream = first_stream;
1123     while (stream != NULL) {
1124         if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1125             break;
1126         stream = stream->next;
1127     }
1128     if (stream == NULL) {
1129         sprintf(msg, "File '%s' not found", url);
1130         goto send_error;
1131     }
1132
1133     c->stream = stream;
1134     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1135     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1136
1137     if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1138         c->http_error = 301;
1139         q = c->buffer;
1140         q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
1141         q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
1142         q += sprintf(q, "Content-type: text/html\r\n");
1143         q += sprintf(q, "\r\n");
1144         q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
1145         q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1146         q += sprintf(q, "</body></html>\r\n");
1147
1148         /* prepare output buffer */
1149         c->buffer_ptr = c->buffer;
1150         c->buffer_end = q;
1151         c->state = HTTPSTATE_SEND_HEADER;
1152         return 0;
1153     }
1154
1155     /* If this is WMP, get the rate information */
1156     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1157         if (modify_current_stream(c, ratebuf)) {
1158             for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1159                 if (c->switch_feed_streams[i] >= 0)
1160                     do_switch_stream(c, i);
1161             }
1162         }
1163     }
1164
1165     if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1166         /* See if we meet the bandwidth requirements */
1167         for(i=0;i<stream->nb_streams;i++) {
1168             AVStream *st = stream->streams[i];
1169             switch(st->codec.codec_type) {
1170             case CODEC_TYPE_AUDIO:
1171                 c->bandwidth += st->codec.bit_rate;
1172                 break;
1173             case CODEC_TYPE_VIDEO:
1174                 c->bandwidth += st->codec.bit_rate;
1175                 break;
1176             default:
1177                 av_abort();
1178             }
1179         }
1180     }
1181
1182     c->bandwidth /= 1000;
1183     nb_bandwidth += c->bandwidth;
1184
1185     if (post == 0 && nb_max_bandwidth < nb_bandwidth) {
1186         c->http_error = 200;
1187         q = c->buffer;
1188         q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
1189         q += sprintf(q, "Content-type: text/html\r\n");
1190         q += sprintf(q, "\r\n");
1191         q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
1192         q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
1193         q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
1194             nb_bandwidth, nb_max_bandwidth);
1195         q += sprintf(q, "</body></html>\r\n");
1196
1197         /* prepare output buffer */
1198         c->buffer_ptr = c->buffer;
1199         c->buffer_end = q;
1200         c->state = HTTPSTATE_SEND_HEADER;
1201         return 0;
1202     }
1203     
1204     if (doing_asx || doing_ram || doing_asf_redirector || 
1205         doing_rtsp_redirector) {
1206         char *hostinfo = 0;
1207         
1208         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1209             if (strncasecmp(p, "Host:", 5) == 0) {
1210                 hostinfo = p + 5;
1211                 break;
1212             }
1213             p = strchr(p, '\n');
1214             if (!p)
1215                 break;
1216
1217             p++;
1218         }
1219
1220         if (hostinfo) {
1221             char *eoh;
1222             char hostbuf[260];
1223
1224             while (isspace(*hostinfo))
1225                 hostinfo++;
1226
1227             eoh = strchr(hostinfo, '\n');
1228             if (eoh) {
1229                 if (eoh[-1] == '\r')
1230                     eoh--;
1231
1232                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1233                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
1234                     hostbuf[eoh - hostinfo] = 0;
1235
1236                     c->http_error = 200;
1237                     q = c->buffer;
1238                     if (doing_asx) {
1239                         q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
1240                         q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1241                         q += sprintf(q, "\r\n");
1242                         q += sprintf(q, "<ASX Version=\"3\">\r\n");
1243                         q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
1244                         q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", 
1245                                 hostbuf, filename, info);
1246                         q += sprintf(q, "</ASX>\r\n");
1247                     } else if (doing_ram) {
1248                         q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
1249                         q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
1250                         q += sprintf(q, "\r\n");
1251                         q += sprintf(q, "# Autogenerated by ffserver\r\n");
1252                         q += sprintf(q, "http://%s/%s%s\r\n", 
1253                                 hostbuf, filename, info);
1254                     } else if (doing_asf_redirector) {
1255                         q += sprintf(q, "HTTP/1.0 200 ASF Redirect follows\r\n");
1256                         q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
1257                         q += sprintf(q, "\r\n");
1258                         q += sprintf(q, "[Reference]\r\n");
1259                         q += sprintf(q, "Ref1=http://%s/%s%s\r\n", 
1260                                 hostbuf, filename, info);
1261                     } else if (doing_rtsp_redirector) {
1262                         char hostname[256], *p;
1263                         /* extract only hostname */
1264                         pstrcpy(hostname, sizeof(hostname), hostbuf);
1265                         p = strrchr(hostname, ':');
1266                         if (p)
1267                             *p = '\0';
1268                         q += sprintf(q, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1269                         /* XXX: incorrect mime type ? */
1270                         q += sprintf(q, "Content-type: application/x-rtsp\r\n");
1271                         q += sprintf(q, "\r\n");
1272                         q += sprintf(q, "rtsp://%s:%d/%s\r\n", 
1273                                      hostname, ntohs(my_rtsp_addr.sin_port), 
1274                                      filename);
1275                     } else {
1276                         av_abort();
1277                     }
1278
1279                     /* prepare output buffer */
1280                     c->buffer_ptr = c->buffer;
1281                     c->buffer_end = q;
1282                     c->state = HTTPSTATE_SEND_HEADER;
1283                     return 0;
1284                 }
1285             }
1286         }
1287
1288         sprintf(msg, "ASX/RAM file not handled");
1289         goto send_error;
1290     }
1291
1292     stream->conns_served++;
1293
1294     /* XXX: add there authenticate and IP match */
1295
1296     if (post) {
1297         /* if post, it means a feed is being sent */
1298         if (!stream->is_feed) {
1299             /* However it might be a status report from WMP! Lets log the data
1300              * as it might come in handy one day
1301              */
1302             char *logline = 0;
1303             int client_id = 0;
1304             
1305             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1306                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1307                     logline = p;
1308                     break;
1309                 }
1310                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
1311                     client_id = strtol(p + 18, 0, 10);
1312                 }
1313                 p = strchr(p, '\n');
1314                 if (!p)
1315                     break;
1316
1317                 p++;
1318             }
1319
1320             if (logline) {
1321                 char *eol = strchr(logline, '\n');
1322
1323                 logline += 17;
1324
1325                 if (eol) {
1326                     if (eol[-1] == '\r')
1327                         eol--;
1328                     http_log("%.*s\n", eol - logline, logline);
1329                     c->suppress_log = 1;
1330                 }
1331             }
1332
1333 #ifdef DEBUG_WMP
1334             http_log("\nGot request:\n%s\n", c->buffer);
1335 #endif
1336
1337             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1338                 HTTPContext *wmpc;
1339
1340                 /* Now we have to find the client_id */
1341                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1342                     if (wmpc->wmp_client_id == client_id)
1343                         break;
1344                 }
1345
1346                 if (wmpc) {
1347                     if (modify_current_stream(wmpc, ratebuf)) {
1348                         wmpc->switch_pending = 1;
1349                     }
1350                 }
1351             }
1352             
1353             sprintf(msg, "POST command not handled");
1354             goto send_error;
1355         }
1356         if (http_start_receive_data(c) < 0) {
1357             sprintf(msg, "could not open feed");
1358             goto send_error;
1359         }
1360         c->http_error = 0;
1361         c->state = HTTPSTATE_RECEIVE_DATA;
1362         return 0;
1363     }
1364
1365 #ifdef DEBUG_WMP
1366     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
1367         http_log("\nGot request:\n%s\n", c->buffer);
1368     }
1369 #endif
1370
1371     if (c->stream->stream_type == STREAM_TYPE_STATUS)
1372         goto send_stats;
1373
1374     /* open input stream */
1375     if (open_input_stream(c, info) < 0) {
1376         sprintf(msg, "Input stream corresponding to '%s' not found", url);
1377         goto send_error;
1378     }
1379
1380     /* prepare http header */
1381     q = c->buffer;
1382     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
1383     mime_type = c->stream->fmt->mime_type;
1384     if (!mime_type)
1385         mime_type = "application/x-octet_stream";
1386     q += sprintf(q, "Pragma: no-cache\r\n");
1387
1388     /* for asf, we need extra headers */
1389     if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1390         /* Need to allocate a client id */
1391
1392         c->wmp_client_id = random() & 0x7fffffff;
1393
1394         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);
1395         mime_type = "application/octet-stream"; 
1396     }
1397     q += sprintf(q, "Content-Type: %s\r\n", mime_type);
1398     q += sprintf(q, "\r\n");
1399     
1400     /* prepare output buffer */
1401     c->http_error = 0;
1402     c->buffer_ptr = c->buffer;
1403     c->buffer_end = q;
1404     c->state = HTTPSTATE_SEND_HEADER;
1405     return 0;
1406  send_error:
1407     c->http_error = 404;
1408     q = c->buffer;
1409     q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
1410     q += sprintf(q, "Content-type: %s\r\n", "text/html");
1411     q += sprintf(q, "\r\n");
1412     q += sprintf(q, "<HTML>\n");
1413     q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1414     q += sprintf(q, "<BODY>%s</BODY>\n", msg);
1415     q += sprintf(q, "</HTML>\n");
1416
1417     /* prepare output buffer */
1418     c->buffer_ptr = c->buffer;
1419     c->buffer_end = q;
1420     c->state = HTTPSTATE_SEND_HEADER;
1421     return 0;
1422  send_stats:
1423     compute_stats(c);
1424     c->http_error = 200; /* horrible : we use this value to avoid
1425                             going to the send data state */
1426     c->state = HTTPSTATE_SEND_HEADER;
1427     return 0;
1428 }
1429
1430 static void fmt_bytecount(ByteIOContext *pb, INT64 count)
1431 {
1432     static const char *suffix = " kMGTP";
1433     const char *s;
1434
1435     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
1436     }
1437
1438     url_fprintf(pb, "%lld%c", count, *s);
1439 }
1440
1441 static void compute_stats(HTTPContext *c)
1442 {
1443     HTTPContext *c1;
1444     FFStream *stream;
1445     char *p;
1446     time_t ti;
1447     int i, len;
1448     ByteIOContext pb1, *pb = &pb1;
1449
1450     if (url_open_dyn_buf(pb) < 0) {
1451         /* XXX: return an error ? */
1452         c->buffer_ptr = c->buffer;
1453         c->buffer_end = c->buffer;
1454         return;
1455     }
1456
1457     url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1458     url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1459     url_fprintf(pb, "Pragma: no-cache\r\n");
1460     url_fprintf(pb, "\r\n");
1461     
1462     url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1463     if (c->stream->feed_filename) {
1464         url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1465     }
1466     url_fprintf(pb, "</HEAD>\n<BODY>");
1467     url_fprintf(pb, "<H1>FFServer Status</H1>\n");
1468     /* format status */
1469     url_fprintf(pb, "<H2>Available Streams</H2>\n");
1470     url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1471     url_fprintf(pb, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>bytes<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");
1472     stream = first_stream;
1473     while (stream != NULL) {
1474         char sfilename[1024];
1475         char *eosf;
1476
1477         if (stream->feed != stream) {
1478             pstrcpy(sfilename, sizeof(sfilename) - 10, stream->filename);
1479             eosf = sfilename + strlen(sfilename);
1480             if (eosf - sfilename >= 4) {
1481                 if (strcmp(eosf - 4, ".asf") == 0) {
1482                     strcpy(eosf - 4, ".asx");
1483                 } else if (strcmp(eosf - 3, ".rm") == 0) {
1484                     strcpy(eosf - 3, ".ram");
1485                 } else if (stream->fmt == &rtp_mux) {
1486                     /* generate a sample RTSP director - maybe should
1487                        generate a .sdp file ? */
1488                     eosf = strrchr(sfilename, '.');
1489                     if (!eosf)
1490                         eosf = sfilename + strlen(sfilename);
1491                     strcpy(eosf, ".rtsp");
1492                 }
1493             }
1494             
1495             url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
1496                          sfilename, stream->filename);
1497             url_fprintf(pb, "<td align=right> %d <td align=right> ",
1498                         stream->conns_served);
1499             fmt_bytecount(pb, stream->bytes_served);
1500             switch(stream->stream_type) {
1501             case STREAM_TYPE_LIVE:
1502                 {
1503                     int audio_bit_rate = 0;
1504                     int video_bit_rate = 0;
1505                     const char *audio_codec_name = "";
1506                     const char *video_codec_name = "";
1507                     const char *audio_codec_name_extra = "";
1508                     const char *video_codec_name_extra = "";
1509
1510                     for(i=0;i<stream->nb_streams;i++) {
1511                         AVStream *st = stream->streams[i];
1512                         AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1513                         switch(st->codec.codec_type) {
1514                         case CODEC_TYPE_AUDIO:
1515                             audio_bit_rate += st->codec.bit_rate;
1516                             if (codec) {
1517                                 if (*audio_codec_name)
1518                                     audio_codec_name_extra = "...";
1519                                 audio_codec_name = codec->name;
1520                             }
1521                             break;
1522                         case CODEC_TYPE_VIDEO:
1523                             video_bit_rate += st->codec.bit_rate;
1524                             if (codec) {
1525                                 if (*video_codec_name)
1526                                     video_codec_name_extra = "...";
1527                                 video_codec_name = codec->name;
1528                             }
1529                             break;
1530                         default:
1531                             av_abort();
1532                         }
1533                     }
1534                     url_fprintf(pb, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s", 
1535                                  stream->fmt->name,
1536                                  (audio_bit_rate + video_bit_rate) / 1000,
1537                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1538                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1539                     if (stream->feed) {
1540                         url_fprintf(pb, "<TD>%s", stream->feed->filename);
1541                     } else {
1542                         url_fprintf(pb, "<TD>%s", stream->feed_filename);
1543                     }
1544                     url_fprintf(pb, "\n");
1545                 }
1546                 break;
1547             default:
1548                 url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1549                 break;
1550             }
1551         }
1552         stream = stream->next;
1553     }
1554     url_fprintf(pb, "</TABLE>\n");
1555
1556     stream = first_stream;
1557     while (stream != NULL) {
1558         if (stream->feed == stream) {
1559             url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1560             if (stream->pid) {
1561                 url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1562
1563 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1564                 {
1565                     FILE *pid_stat;
1566                     char ps_cmd[64];
1567
1568                     /* This is somewhat linux specific I guess */
1569                     snprintf(ps_cmd, sizeof(ps_cmd), 
1570                              "ps -o \"%%cpu,cputime\" --no-headers %d", 
1571                              stream->pid);
1572                     
1573                     pid_stat = popen(ps_cmd, "r");
1574                     if (pid_stat) {
1575                         char cpuperc[10];
1576                         char cpuused[64];
1577                         
1578                         if (fscanf(pid_stat, "%10s %64s", cpuperc, 
1579                                    cpuused) == 2) {
1580                             url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1581                                          cpuperc, cpuused);
1582                         }
1583                         fclose(pid_stat);
1584                     }
1585                 }
1586 #endif
1587
1588                 url_fprintf(pb, "<p>");
1589             }
1590             url_fprintf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1591
1592             for (i = 0; i < stream->nb_streams; i++) {
1593                 AVStream *st = stream->streams[i];
1594                 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
1595                 char *type = "unknown";
1596                 char parameters[64];
1597
1598                 parameters[0] = 0;
1599
1600                 switch(st->codec.codec_type) {
1601                 case CODEC_TYPE_AUDIO:
1602                     type = "audio";
1603                     break;
1604                 case CODEC_TYPE_VIDEO:
1605                     type = "video";
1606                     sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
1607                                 st->codec.qmin, st->codec.qmax, st->codec.frame_rate / FRAME_RATE_BASE);
1608                     break;
1609                 default:
1610                     av_abort();
1611                 }
1612                 url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1613                         i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
1614             }
1615             url_fprintf(pb, "</table>\n");
1616
1617         }       
1618         stream = stream->next;
1619     }
1620     
1621 #if 0
1622     {
1623         float avg;
1624         AVCodecContext *enc;
1625         char buf[1024];
1626         
1627         /* feed status */
1628         stream = first_feed;
1629         while (stream != NULL) {
1630             url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1631             url_fprintf(pb, "<TABLE>\n");
1632             url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1633             for(i=0;i<stream->nb_streams;i++) {
1634                 AVStream *st = stream->streams[i];
1635                 FeedData *fdata = st->priv_data;
1636                 enc = &st->codec;
1637             
1638                 avcodec_string(buf, sizeof(buf), enc);
1639                 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1640                 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1641                     avg /= enc->frame_size;
1642                 url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
1643                              buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1644             }
1645             url_fprintf(pb, "</TABLE>\n");
1646             stream = stream->next_feed;
1647         }
1648     }
1649 #endif
1650
1651     /* connection status */
1652     url_fprintf(pb, "<H2>Connection Status</H2>\n");
1653
1654     url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
1655                  nb_connections, nb_max_connections);
1656
1657     url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
1658                  nb_bandwidth, nb_max_bandwidth);
1659
1660     url_fprintf(pb, "<TABLE>\n");
1661     url_fprintf(pb, "<TR><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1662     c1 = first_http_ctx;
1663     i = 0;
1664     while (c1 != NULL) {
1665         int bitrate;
1666         int j;
1667
1668         bitrate = 0;
1669         if (c1->stream) {
1670             for (j = 0; j < c1->stream->nb_streams; j++) {
1671                 if (!c1->stream->feed) {
1672                     bitrate += c1->stream->streams[j]->codec.bit_rate;
1673                 } else {
1674                     if (c1->feed_streams[j] >= 0) {
1675                         bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec.bit_rate;
1676                     }
1677                 }
1678             }
1679         }
1680
1681         i++;
1682         p = inet_ntoa(c1->from_addr.sin_addr);
1683         url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>", 
1684                     i, 
1685                     c1->stream ? c1->stream->filename : "", 
1686                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1687                     p, 
1688                     c1->protocol,
1689                     http_state[c1->state]);
1690         fmt_bytecount(pb, bitrate);
1691         url_fprintf(pb, "<td align=right>");
1692         fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1693         url_fprintf(pb, "<td align=right>");
1694         fmt_bytecount(pb, c1->data_count);
1695         url_fprintf(pb, "\n");
1696         c1 = c1->next;
1697     }
1698     url_fprintf(pb, "</TABLE>\n");
1699     
1700     /* date */
1701     ti = time(NULL);
1702     p = ctime(&ti);
1703     url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1704     url_fprintf(pb, "</BODY>\n</HTML>\n");
1705
1706     len = url_close_dyn_buf(pb, &c->pb_buffer);
1707     c->buffer_ptr = c->pb_buffer;
1708     c->buffer_end = c->pb_buffer + len;
1709 }
1710
1711 /* check if the parser needs to be opened for stream i */
1712 static void open_parser(AVFormatContext *s, int i)
1713 {
1714     AVStream *st = s->streams[i];
1715     AVCodec *codec;
1716
1717     if (!st->codec.codec) {
1718         codec = avcodec_find_decoder(st->codec.codec_id);
1719         if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1720             st->codec.parse_only = 1;
1721             if (avcodec_open(&st->codec, codec) < 0) {
1722                 st->codec.parse_only = 0;
1723             }
1724         }
1725     }
1726 }
1727
1728 static int open_input_stream(HTTPContext *c, const char *info)
1729 {
1730     char buf[128];
1731     char input_filename[1024];
1732     AVFormatContext *s;
1733     int buf_size, i;
1734     INT64 stream_pos;
1735
1736     /* find file name */
1737     if (c->stream->feed) {
1738         strcpy(input_filename, c->stream->feed->feed_filename);
1739         buf_size = FFM_PACKET_SIZE;
1740         /* compute position (absolute time) */
1741         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1742             stream_pos = parse_date(buf, 0);
1743         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1744             int prebuffer = strtol(buf, 0, 10);
1745             stream_pos = av_gettime() - prebuffer * (INT64)1000000;
1746         } else {
1747             stream_pos = av_gettime() - c->stream->prebuffer * (INT64)1000;
1748         }
1749     } else {
1750         strcpy(input_filename, c->stream->feed_filename);
1751         buf_size = 0;
1752         /* compute position (relative time) */
1753         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1754             stream_pos = parse_date(buf, 1);
1755         } else {
1756             stream_pos = 0;
1757         }
1758     }
1759     if (input_filename[0] == '\0')
1760         return -1;
1761
1762 #if 0
1763     { time_t when = stream_pos / 1000000;
1764     http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when));
1765     }
1766 #endif
1767
1768     /* open stream */
1769     if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) {
1770         http_log("%s not found", input_filename);
1771         return -1;
1772     }
1773     c->fmt_in = s;
1774     
1775     /* open each parser */
1776     for(i=0;i<s->nb_streams;i++)
1777         open_parser(s, i);
1778
1779     /* choose stream as clock source (we favorize video stream if
1780        present) for packet sending */
1781     c->pts_stream_index = 0;
1782     for(i=0;i<c->stream->nb_streams;i++) {
1783         if (c->pts_stream_index == 0 && 
1784             c->stream->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) {
1785             c->pts_stream_index = i;
1786         }
1787     }
1788
1789     if (c->fmt_in->iformat->read_seek) {
1790         c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
1791     }
1792     /* set the start time (needed for maxtime and RTP packet timing) */
1793     c->start_time = cur_time;
1794     c->first_pts = AV_NOPTS_VALUE;
1795     return 0;
1796 }
1797
1798 /* currently desactivated because the new PTS handling is not
1799    satisfactory yet */
1800 //#define AV_READ_FRAME
1801 #ifdef AV_READ_FRAME
1802
1803 /* XXX: generalize that in ffmpeg for picture/audio/data. Currently
1804    the return packet MUST NOT be freed */
1805 int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1806 {
1807     AVStream *st;
1808     int len, ret, old_nb_streams, i;
1809
1810     /* see if remaining frames must be parsed */
1811     for(;;) {
1812         if (s->cur_len > 0) {
1813             st = s->streams[s->cur_pkt.stream_index];
1814             len = avcodec_parse_frame(&st->codec, &pkt->data, &pkt->size, 
1815                                       s->cur_ptr, s->cur_len);
1816             if (len < 0) {
1817                 /* error: get next packet */
1818                 s->cur_len = 0;
1819             } else {
1820                 s->cur_ptr += len;
1821                 s->cur_len -= len;
1822                 if (pkt->size) {
1823                     /* init pts counter if not done */
1824                     if (st->pts.den == 0) {
1825                         switch(st->codec.codec_type) {
1826                         case CODEC_TYPE_AUDIO:
1827                             st->pts_incr = (INT64)s->pts_den;
1828                             av_frac_init(&st->pts, st->pts.val, 0, 
1829                                          (INT64)s->pts_num * st->codec.sample_rate);
1830                             break;
1831                         case CODEC_TYPE_VIDEO:
1832                             st->pts_incr = (INT64)s->pts_den * FRAME_RATE_BASE;
1833                             av_frac_init(&st->pts, st->pts.val, 0,
1834                                          (INT64)s->pts_num * st->codec.frame_rate);
1835                             break;
1836                         default:
1837                             av_abort();
1838                         }
1839                     }
1840                     
1841                     /* a frame was read: return it */
1842                     pkt->pts = st->pts.val;
1843 #if 0
1844                     printf("add pts=%Lx num=%Lx den=%Lx incr=%Lx\n",
1845                            st->pts.val, st->pts.num, st->pts.den, st->pts_incr);
1846 #endif
1847                     switch(st->codec.codec_type) {
1848                     case CODEC_TYPE_AUDIO:
1849                         av_frac_add(&st->pts, st->pts_incr * st->codec.frame_size);
1850                         break;
1851                     case CODEC_TYPE_VIDEO:
1852                         av_frac_add(&st->pts, st->pts_incr);
1853                         break;
1854                     default:
1855                         av_abort();
1856                     }
1857                     pkt->stream_index = s->cur_pkt.stream_index;
1858                     /* we use the codec indication because it is
1859                        more accurate than the demux flags */
1860                     pkt->flags = 0;
1861                     if (st->codec.key_frame) 
1862                         pkt->flags |= PKT_FLAG_KEY;
1863                     return 0;
1864                 }
1865             }
1866         } else {
1867             /* free previous packet */
1868             av_free_packet(&s->cur_pkt); 
1869
1870             old_nb_streams = s->nb_streams;
1871             ret = av_read_packet(s, &s->cur_pkt);
1872             if (ret)
1873                 return ret;
1874             /* open parsers for each new streams */
1875             for(i = old_nb_streams; i < s->nb_streams; i++)
1876                 open_parser(s, i);
1877             st = s->streams[s->cur_pkt.stream_index];
1878
1879             /* update current pts (XXX: dts handling) from packet, or
1880                use current pts if none given */
1881             if (s->cur_pkt.pts != AV_NOPTS_VALUE) {
1882                 av_frac_set(&st->pts, s->cur_pkt.pts);
1883             } else {
1884                 s->cur_pkt.pts = st->pts.val;
1885             }
1886             if (!st->codec.codec) {
1887                 /* no codec opened: just return the raw packet */
1888                 *pkt = s->cur_pkt;
1889
1890                 /* no codec opened: just update the pts by considering we
1891                    have one frame and free the packet */
1892                 if (st->pts.den == 0) {
1893                     switch(st->codec.codec_type) {
1894                     case CODEC_TYPE_AUDIO:
1895                         st->pts_incr = (INT64)s->pts_den * st->codec.frame_size;
1896                         av_frac_init(&st->pts, st->pts.val, 0, 
1897                                      (INT64)s->pts_num * st->codec.sample_rate);
1898                         break;
1899                     case CODEC_TYPE_VIDEO:
1900                         st->pts_incr = (INT64)s->pts_den * FRAME_RATE_BASE;
1901                         av_frac_init(&st->pts, st->pts.val, 0,
1902                                      (INT64)s->pts_num * st->codec.frame_rate);
1903                         break;
1904                     default:
1905                         av_abort();
1906                     }
1907                 }
1908                 av_frac_add(&st->pts, st->pts_incr);
1909                 return 0;
1910             } else {
1911                 s->cur_ptr = s->cur_pkt.data;
1912                 s->cur_len = s->cur_pkt.size;
1913             }
1914         }
1915     }
1916 }
1917
1918 static int compute_send_delay(HTTPContext *c)
1919 {
1920     INT64 cur_pts, delta_pts, next_pts;
1921     int delay1;
1922     
1923     /* compute current pts value from system time */
1924     cur_pts = ((INT64)(cur_time - c->start_time) * c->fmt_in->pts_den) / 
1925         (c->fmt_in->pts_num * 1000LL);
1926     /* compute the delta from the stream we choose as
1927        main clock (we do that to avoid using explicit
1928        buffers to do exact packet reordering for each
1929        stream */
1930     /* XXX: really need to fix the number of streams */
1931     if (c->pts_stream_index >= c->fmt_in->nb_streams)
1932         next_pts = cur_pts;
1933     else
1934         next_pts = c->fmt_in->streams[c->pts_stream_index]->pts.val;
1935     delta_pts = next_pts - cur_pts;
1936     if (delta_pts <= 0) {
1937         delay1 = 0;
1938     } else {
1939         delay1 = (delta_pts * 1000 * c->fmt_in->pts_num) / c->fmt_in->pts_den;
1940     }
1941     return delay1;
1942 }
1943 #else
1944
1945 /* just fall backs */
1946 int av_read_frame(AVFormatContext *s, AVPacket *pkt)
1947 {
1948     return av_read_packet(s, pkt);
1949 }
1950
1951 static int compute_send_delay(HTTPContext *c)
1952 {
1953     int datarate = 8 * get_longterm_datarate(&c->datarate, c->data_count); 
1954
1955     if (datarate > c->bandwidth * 2000) {
1956         return 1000;
1957     }
1958     return 0;
1959 }
1960
1961 #endif
1962     
1963 static int http_prepare_data(HTTPContext *c)
1964 {
1965     int i, len, ret;
1966     AVFormatContext *ctx;
1967
1968     switch(c->state) {
1969     case HTTPSTATE_SEND_DATA_HEADER:
1970         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
1971         pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), 
1972                 c->stream->author);
1973         pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), 
1974                 c->stream->comment);
1975         pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), 
1976                 c->stream->copyright);
1977         pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), 
1978                 c->stream->title);
1979
1980         /* open output stream by using specified codecs */
1981         c->fmt_ctx.oformat = c->stream->fmt;
1982         c->fmt_ctx.nb_streams = c->stream->nb_streams;
1983         for(i=0;i<c->fmt_ctx.nb_streams;i++) {
1984             AVStream *st;
1985             st = av_mallocz(sizeof(AVStream));
1986             c->fmt_ctx.streams[i] = st;
1987             /* if file or feed, then just take streams from FFStream struct */
1988             if (!c->stream->feed || 
1989                 c->stream->feed == c->stream)
1990                 memcpy(st, c->stream->streams[i], sizeof(AVStream));
1991             else
1992                 memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]],
1993                            sizeof(AVStream));
1994             st->codec.frame_number = 0; /* XXX: should be done in
1995                                            AVStream, not in codec */
1996         }
1997         c->got_key_frame = 0;
1998
1999         /* prepare header and save header data in a stream */
2000         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2001             /* XXX: potential leak */
2002             return -1;
2003         }
2004         c->fmt_ctx.pb.is_streamed = 1;
2005
2006         av_write_header(&c->fmt_ctx);
2007
2008         len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2009         c->buffer_ptr = c->pb_buffer;
2010         c->buffer_end = c->pb_buffer + len;
2011
2012         c->state = HTTPSTATE_SEND_DATA;
2013         c->last_packet_sent = 0;
2014         break;
2015     case HTTPSTATE_SEND_DATA:
2016         /* find a new packet */
2017         {
2018             AVPacket pkt;
2019             
2020             /* read a packet from the input stream */
2021             if (c->stream->feed) {
2022                 ffm_set_write_index(c->fmt_in, 
2023                                     c->stream->feed->feed_write_index,
2024                                     c->stream->feed->feed_size);
2025             }
2026
2027             if (c->stream->max_time && 
2028                 c->stream->max_time + c->start_time - cur_time < 0) {
2029                 /* We have timed out */
2030                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2031             } else {
2032                 if (1 || c->is_packetized) {
2033                     if (compute_send_delay(c) > 0) {
2034                         c->state = HTTPSTATE_WAIT;
2035                         return 1; /* state changed */
2036                     }
2037                 }
2038                 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2039                     if (c->stream->feed && c->stream->feed->feed_opened) {
2040                         /* if coming from feed, it means we reached the end of the
2041                            ffm file, so must wait for more data */
2042                         c->state = HTTPSTATE_WAIT_FEED;
2043                         return 1; /* state changed */
2044                     } else {
2045                         /* must send trailer now because eof or error */
2046                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
2047                     }
2048                 } else {
2049                     /* update first pts if needed */
2050                     if (c->first_pts == AV_NOPTS_VALUE)
2051                         c->first_pts = pkt.pts;
2052                     
2053                     /* send it to the appropriate stream */
2054                     if (c->stream->feed) {
2055                         /* if coming from a feed, select the right stream */
2056                         if (c->switch_pending) {
2057                             c->switch_pending = 0;
2058                             for(i=0;i<c->stream->nb_streams;i++) {
2059                                 if (c->switch_feed_streams[i] == pkt.stream_index) {
2060                                     if (pkt.flags & PKT_FLAG_KEY) {
2061                                         do_switch_stream(c, i);
2062                                     }
2063                                 }
2064                                 if (c->switch_feed_streams[i] >= 0) {
2065                                     c->switch_pending = 1;
2066                                 }
2067                             }
2068                         }
2069                         for(i=0;i<c->stream->nb_streams;i++) {
2070                             if (c->feed_streams[i] == pkt.stream_index) {
2071                                 pkt.stream_index = i;
2072                                 if (pkt.flags & PKT_FLAG_KEY) {
2073                                     c->got_key_frame |= 1 << i;
2074                                 }
2075                                 /* See if we have all the key frames, then 
2076                                  * we start to send. This logic is not quite
2077                                  * right, but it works for the case of a 
2078                                  * single video stream with one or more
2079                                  * audio streams (for which every frame is 
2080                                  * typically a key frame). 
2081                                  */
2082                                 if (!c->stream->send_on_key || 
2083                                     ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2084                                     goto send_it;
2085                                 }
2086                             }
2087                         }
2088                     } else {
2089                         AVCodecContext *codec;
2090                         
2091                     send_it:
2092                         /* specific handling for RTP: we use several
2093                            output stream (one for each RTP
2094                            connection). XXX: need more abstract handling */
2095                         if (c->is_packetized) {
2096                             c->packet_stream_index = pkt.stream_index;
2097                             ctx = c->rtp_ctx[c->packet_stream_index];
2098                             codec = &ctx->streams[0]->codec;
2099                         } else {
2100                             ctx = &c->fmt_ctx;
2101                             /* Fudge here */
2102                             codec = &ctx->streams[pkt.stream_index]->codec;
2103                         }
2104                         
2105                         codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2106                         
2107 #ifdef PJSG
2108                         if (codec->codec_type == CODEC_TYPE_AUDIO) {
2109                             codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
2110                             /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
2111                         }
2112 #endif
2113                         
2114                         if (c->is_packetized) {
2115                             ret = url_open_dyn_packet_buf(&ctx->pb, 
2116                                                           url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]));
2117                             c->packet_byte_count = 0;
2118                             c->packet_start_time_us = av_gettime();
2119                         } else {
2120                             ret = url_open_dyn_buf(&ctx->pb);
2121                         }
2122                         if (ret < 0) {
2123                             /* XXX: potential leak */
2124                             return -1;
2125                         }
2126                         if (av_write_frame(ctx, pkt.stream_index, pkt.data, pkt.size)) {
2127                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2128                         }
2129                         
2130                         len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2131                         c->buffer_ptr = c->pb_buffer;
2132                         c->buffer_end = c->pb_buffer + len;
2133                         
2134                         codec->frame_number++;
2135                     }
2136 #ifndef AV_READ_FRAME
2137                     av_free_packet(&pkt);
2138 #endif
2139                 }
2140             }
2141         }
2142         break;
2143     default:
2144     case HTTPSTATE_SEND_DATA_TRAILER:
2145         /* last packet test ? */
2146         if (c->last_packet_sent || c->is_packetized)
2147             return -1;
2148         ctx = &c->fmt_ctx;
2149         /* prepare header */
2150         if (url_open_dyn_buf(&ctx->pb) < 0) {
2151             /* XXX: potential leak */
2152             return -1;
2153         }
2154         av_write_trailer(ctx);
2155         len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2156         c->buffer_ptr = c->pb_buffer;
2157         c->buffer_end = c->pb_buffer + len;
2158
2159         c->last_packet_sent = 1;
2160         break;
2161     }
2162     return 0;
2163 }
2164
2165 /* in bit/s */
2166 #define SHORT_TERM_BANDWIDTH 8000000
2167
2168 /* should convert the format at the same time */
2169 static int http_send_data(HTTPContext *c)
2170 {
2171     int len, ret, dt;
2172     
2173     while (c->buffer_ptr >= c->buffer_end) {
2174         av_freep(&c->pb_buffer);
2175         ret = http_prepare_data(c);
2176         if (ret < 0)
2177             return -1;
2178         else if (ret == 0) {
2179             continue;
2180         } else {
2181             /* state change requested */
2182             return 0;
2183         }
2184     }
2185
2186     if (c->buffer_ptr < c->buffer_end) {
2187         if (c->is_packetized) {
2188             /* RTP/UDP data output */
2189             len = c->buffer_end - c->buffer_ptr;
2190             if (len < 4) {
2191                 /* fail safe - should never happen */
2192             fail1:
2193                 c->buffer_ptr = c->buffer_end;
2194                 return 0;
2195             }
2196             len = (c->buffer_ptr[0] << 24) |
2197                 (c->buffer_ptr[1] << 16) |
2198                 (c->buffer_ptr[2] << 8) |
2199                 (c->buffer_ptr[3]);
2200             if (len > (c->buffer_end - c->buffer_ptr))
2201                 goto fail1;
2202             
2203             /* short term bandwidth limitation */
2204             dt = av_gettime() - c->packet_start_time_us;
2205             if (dt < 1)
2206                 dt = 1;
2207
2208             if ((c->packet_byte_count + len) * (INT64)1000000 >= 
2209                 (SHORT_TERM_BANDWIDTH / 8) * (INT64)dt) {
2210                 /* bandwidth overflow : wait at most one tick and retry */
2211                 c->state = HTTPSTATE_WAIT_SHORT;
2212                 return 0;
2213             }
2214
2215             c->buffer_ptr += 4;
2216             url_write(c->rtp_handles[c->packet_stream_index], 
2217                       c->buffer_ptr, len);
2218             c->buffer_ptr += len;
2219             c->packet_byte_count += len;
2220         } else {
2221             /* TCP data output */
2222             len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2223             if (len < 0) {
2224                 if (errno != EAGAIN && errno != EINTR) {
2225                     /* error : close connection */
2226                     return -1;
2227                 } else {
2228                     return 0;
2229                 }
2230             } else {
2231                 c->buffer_ptr += len;
2232             }
2233         }
2234         c->data_count += len;
2235         update_datarate(&c->datarate, c->data_count);
2236         if (c->stream)
2237             c->stream->bytes_served += len;
2238     }
2239     return 0;
2240 }
2241
2242 static int http_start_receive_data(HTTPContext *c)
2243 {
2244     int fd;
2245
2246     if (c->stream->feed_opened)
2247         return -1;
2248
2249     /* open feed */
2250     fd = open(c->stream->feed_filename, O_RDWR);
2251     if (fd < 0)
2252         return -1;
2253     c->feed_fd = fd;
2254     
2255     c->stream->feed_write_index = ffm_read_write_index(fd);
2256     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2257     lseek(fd, 0, SEEK_SET);
2258
2259     /* init buffer input */
2260     c->buffer_ptr = c->buffer;
2261     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2262     c->stream->feed_opened = 1;
2263     return 0;
2264 }
2265     
2266 static int http_receive_data(HTTPContext *c)
2267 {
2268     HTTPContext *c1;
2269
2270     if (c->buffer_end > c->buffer_ptr) {
2271         int len;
2272
2273         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2274         if (len < 0) {
2275             if (errno != EAGAIN && errno != EINTR) {
2276                 /* error : close connection */
2277                 goto fail;
2278             }
2279         } else if (len == 0) {
2280             /* end of connection : close it */
2281             goto fail;
2282         } else {
2283             c->buffer_ptr += len;
2284             c->data_count += len;
2285             update_datarate(&c->datarate, c->data_count);
2286         }
2287     }
2288
2289     if (c->buffer_ptr >= c->buffer_end) {
2290         FFStream *feed = c->stream;
2291         /* a packet has been received : write it in the store, except
2292            if header */
2293         if (c->data_count > FFM_PACKET_SIZE) {
2294             
2295             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2296             /* XXX: use llseek or url_seek */
2297             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2298             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2299             
2300             feed->feed_write_index += FFM_PACKET_SIZE;
2301             /* update file size */
2302             if (feed->feed_write_index > c->stream->feed_size)
2303                 feed->feed_size = feed->feed_write_index;
2304
2305             /* handle wrap around if max file size reached */
2306             if (feed->feed_write_index >= c->stream->feed_max_size)
2307                 feed->feed_write_index = FFM_PACKET_SIZE;
2308
2309             /* write index */
2310             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2311
2312             /* wake up any waiting connections */
2313             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2314                 if (c1->state == HTTPSTATE_WAIT_FEED && 
2315                     c1->stream->feed == c->stream->feed) {
2316                     c1->state = HTTPSTATE_SEND_DATA;
2317                 }
2318             }
2319         } else {
2320             /* We have a header in our hands that contains useful data */
2321             AVFormatContext s;
2322             AVInputFormat *fmt_in;
2323             ByteIOContext *pb = &s.pb;
2324             int i;
2325
2326             memset(&s, 0, sizeof(s));
2327
2328             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2329             pb->buf_end = c->buffer_end;        /* ?? */
2330             pb->is_streamed = 1;
2331
2332             /* use feed output format name to find corresponding input format */
2333             fmt_in = av_find_input_format(feed->fmt->name);
2334             if (!fmt_in)
2335                 goto fail;
2336
2337             s.priv_data = av_mallocz(fmt_in->priv_data_size);
2338             if (!s.priv_data)
2339                 goto fail;
2340
2341             if (fmt_in->read_header(&s, 0) < 0) {
2342                 av_freep(&s.priv_data);
2343                 goto fail;
2344             }
2345
2346             /* Now we have the actual streams */
2347             if (s.nb_streams != feed->nb_streams) {
2348                 av_freep(&s.priv_data);
2349                 goto fail;
2350             }
2351             for (i = 0; i < s.nb_streams; i++) {
2352                 memcpy(&feed->streams[i]->codec, 
2353                        &s.streams[i]->codec, sizeof(AVCodecContext));
2354             } 
2355             av_freep(&s.priv_data);
2356         }
2357         c->buffer_ptr = c->buffer;
2358     }
2359
2360     return 0;
2361  fail:
2362     c->stream->feed_opened = 0;
2363     close(c->feed_fd);
2364     return -1;
2365 }
2366
2367 /********************************************************************/
2368 /* RTSP handling */
2369
2370 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2371 {
2372     const char *str;
2373     time_t ti;
2374     char *p;
2375     char buf2[32];
2376
2377     switch(error_number) {
2378 #define DEF(n, c, s) case c: str = s; break; 
2379 #include "rtspcodes.h"
2380 #undef DEF
2381     default:
2382         str = "Unknown Error";
2383         break;
2384     }
2385      
2386     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2387     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2388
2389     /* output GMT time */
2390     ti = time(NULL);
2391     p = ctime(&ti);
2392     strcpy(buf2, p);
2393     p = buf2 + strlen(p) - 1;
2394     if (*p == '\n')
2395         *p = '\0';
2396     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2397 }
2398
2399 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2400 {
2401     rtsp_reply_header(c, error_number);
2402     url_fprintf(c->pb, "\r\n");
2403 }
2404
2405 static int rtsp_parse_request(HTTPContext *c)
2406 {
2407     const char *p, *p1, *p2;
2408     char cmd[32];
2409     char url[1024];
2410     char protocol[32];
2411     char line[1024];
2412     ByteIOContext pb1;
2413     int len;
2414     RTSPHeader header1, *header = &header1;
2415     
2416     c->buffer_ptr[0] = '\0';
2417     p = c->buffer;
2418     
2419     get_word(cmd, sizeof(cmd), &p);
2420     get_word(url, sizeof(url), &p);
2421     get_word(protocol, sizeof(protocol), &p);
2422
2423     pstrcpy(c->method, sizeof(c->method), cmd);
2424     pstrcpy(c->url, sizeof(c->url), url);
2425     pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2426
2427     c->pb = &pb1;
2428     if (url_open_dyn_buf(c->pb) < 0) {
2429         /* XXX: cannot do more */
2430         c->pb = NULL; /* safety */
2431         return -1;
2432     }
2433
2434     /* check version name */
2435     if (strcmp(protocol, "RTSP/1.0") != 0) {
2436         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2437         goto the_end;
2438     }
2439
2440     /* parse each header line */
2441     memset(header, 0, sizeof(RTSPHeader));
2442     /* skip to next line */
2443     while (*p != '\n' && *p != '\0')
2444         p++;
2445     if (*p == '\n')
2446         p++;
2447     while (*p != '\0') {
2448         p1 = strchr(p, '\n');
2449         if (!p1)
2450             break;
2451         p2 = p1;
2452         if (p2 > p && p2[-1] == '\r')
2453             p2--;
2454         /* skip empty line */
2455         if (p2 == p)
2456             break;
2457         len = p2 - p;
2458         if (len > sizeof(line) - 1)
2459             len = sizeof(line) - 1;
2460         memcpy(line, p, len);
2461         line[len] = '\0';
2462         rtsp_parse_line(header, line);
2463         p = p1 + 1;
2464     }
2465
2466     /* handle sequence number */
2467     c->seq = header->seq;
2468
2469     if (!strcmp(cmd, "DESCRIBE")) {
2470         rtsp_cmd_describe(c, url);
2471     } else if (!strcmp(cmd, "SETUP")) {
2472         rtsp_cmd_setup(c, url, header);
2473     } else if (!strcmp(cmd, "PLAY")) {
2474         rtsp_cmd_play(c, url, header);
2475     } else if (!strcmp(cmd, "PAUSE")) {
2476         rtsp_cmd_pause(c, url, header);
2477     } else if (!strcmp(cmd, "TEARDOWN")) {
2478         rtsp_cmd_teardown(c, url, header);
2479     } else {
2480         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2481     }
2482  the_end:
2483     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2484     c->pb = NULL; /* safety */
2485     if (len < 0) {
2486         /* XXX: cannot do more */
2487         return -1;
2488     }
2489     c->buffer_ptr = c->pb_buffer;
2490     c->buffer_end = c->pb_buffer + len;
2491     c->state = RTSPSTATE_SEND_REPLY;
2492     return 0;
2493 }
2494
2495 static int prepare_sdp_description(HTTPContext *c, 
2496                                    FFStream *stream, UINT8 **pbuffer)
2497 {
2498     ByteIOContext pb1, *pb = &pb1;
2499     struct sockaddr_in my_addr;
2500     int len, i, payload_type;
2501     const char *ipstr, *title, *mediatype;
2502     AVStream *st;
2503     
2504     len = sizeof(my_addr);
2505     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2506     ipstr = inet_ntoa(my_addr.sin_addr);
2507
2508     if (url_open_dyn_buf(pb) < 0)
2509         return -1;
2510     
2511     /* general media info */
2512
2513     url_fprintf(pb, "v=0\n");
2514     url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2515     title = stream->title;
2516     if (title[0] == '\0')
2517         title = "No Title";
2518     url_fprintf(pb, "s=%s\n", title);
2519     if (stream->comment[0] != '\0')
2520         url_fprintf(pb, "i=%s\n", stream->comment);
2521     
2522     /* for each stream, we output the necessary info */
2523     for(i = 0; i < stream->nb_streams; i++) {
2524         st = stream->streams[i];
2525         switch(st->codec.codec_type) {
2526         case CODEC_TYPE_AUDIO:
2527             mediatype = "audio";
2528             break;
2529         case CODEC_TYPE_VIDEO:
2530             mediatype = "video";
2531             break;
2532         default:
2533             mediatype = "application";
2534             break;
2535         }
2536         /* XXX: the port indication is not correct (but should be correct
2537            for broadcast) */
2538         payload_type = rtp_get_payload_type(&st->codec);
2539
2540         url_fprintf(pb, "m=%s %d RTP/AVP %d\n", 
2541                     mediatype, 0, payload_type);
2542         url_fprintf(pb, "a=control:streamid=%d\n", i);
2543     }
2544     return url_close_dyn_buf(pb, pbuffer);
2545 }
2546
2547 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2548 {
2549     FFStream *stream;
2550     char path1[1024];
2551     const char *path;
2552     UINT8 *content;
2553     int content_length;
2554     
2555     /* find which url is asked */
2556     url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2557     path = path1;
2558     if (*path == '/')
2559         path++;
2560
2561     for(stream = first_stream; stream != NULL; stream = stream->next) {
2562         if (!stream->is_feed && stream->fmt == &rtp_mux &&
2563             !strcmp(path, stream->filename)) {
2564             goto found;
2565         }
2566     }
2567     /* no stream found */
2568     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2569     return;
2570
2571  found:
2572     /* prepare the media description in sdp format */
2573     content_length = prepare_sdp_description(c, stream, &content);
2574     if (content_length < 0) {
2575         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2576         return;
2577     }
2578     rtsp_reply_header(c, RTSP_STATUS_OK);
2579     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2580     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2581     url_fprintf(c->pb, "\r\n");
2582     put_buffer(c->pb, content, content_length);
2583 }
2584
2585 static HTTPContext *find_rtp_session(const char *session_id)
2586 {
2587     HTTPContext *c;
2588
2589     if (session_id[0] == '\0')
2590         return NULL;
2591
2592     for(c = first_http_ctx; c != NULL; c = c->next) {
2593         if (!strcmp(c->session_id, session_id))
2594             return c;
2595     }
2596     return NULL;
2597 }
2598
2599 RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2600 {
2601     RTSPTransportField *th;
2602     int i;
2603
2604     for(i=0;i<h->nb_transports;i++) {
2605         th = &h->transports[i];
2606         if (th->protocol == protocol)
2607             return th;
2608     }
2609     return NULL;
2610 }
2611
2612 static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2613                            RTSPHeader *h)
2614 {
2615     FFStream *stream;
2616     int stream_index, port;
2617     char buf[1024];
2618     char path1[1024];
2619     const char *path;
2620     HTTPContext *rtp_c;
2621     RTSPTransportField *th;
2622     struct sockaddr_in dest_addr;
2623     RTSPActionServerSetup setup;
2624     
2625     /* find which url is asked */
2626     url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2627     path = path1;
2628     if (*path == '/')
2629         path++;
2630
2631     /* now check each stream */
2632     for(stream = first_stream; stream != NULL; stream = stream->next) {
2633         if (!stream->is_feed && stream->fmt == &rtp_mux) {
2634             /* accept aggregate filenames only if single stream */
2635             if (!strcmp(path, stream->filename)) {
2636                 if (stream->nb_streams != 1) {
2637                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2638                     return;
2639                 }
2640                 stream_index = 0;
2641                 goto found;
2642             }
2643                 
2644             for(stream_index = 0; stream_index < stream->nb_streams;
2645                 stream_index++) {
2646                 snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2647                          stream->filename, stream_index);
2648                 if (!strcmp(path, buf))
2649                     goto found;
2650             }
2651         }
2652     }
2653     /* no stream found */
2654     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2655     return;
2656  found:
2657
2658     /* generate session id if needed */
2659     if (h->session_id[0] == '\0') {
2660         snprintf(h->session_id, sizeof(h->session_id), 
2661                  "%08x%08x", (int)random(), (int)random());
2662     }
2663
2664     /* find rtp session, and create it if none found */
2665     rtp_c = find_rtp_session(h->session_id);
2666     if (!rtp_c) {
2667         rtp_c = rtp_new_connection(c, stream, h->session_id);
2668         if (!rtp_c) {
2669             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2670             return;
2671         }
2672
2673         /* open input stream */
2674         if (open_input_stream(rtp_c, "") < 0) {
2675             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2676             return;
2677         }
2678
2679         /* always prefer UDP */
2680         th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2681         if (!th) {
2682             th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2683             if (!th) {
2684                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2685                 return;
2686             }
2687         }
2688         rtp_c->rtp_protocol = th->protocol;
2689     }
2690     
2691     /* test if stream is OK (test needed because several SETUP needs
2692        to be done for a given file) */
2693     if (rtp_c->stream != stream) {
2694         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2695         return;
2696     }
2697     
2698     /* test if stream is already set up */
2699     if (rtp_c->rtp_ctx[stream_index]) {
2700         rtsp_reply_error(c, RTSP_STATUS_STATE);
2701         return;
2702     }
2703
2704     /* check transport */
2705     th = find_transport(h, rtp_c->rtp_protocol);
2706     if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP && 
2707                 th->client_port_min <= 0)) {
2708         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2709         return;
2710     }
2711
2712     /* setup default options */
2713     setup.transport_option[0] = '\0';
2714     dest_addr = rtp_c->from_addr;
2715     dest_addr.sin_port = htons(th->client_port_min);
2716     
2717     /* add transport option if needed */
2718     if (ff_rtsp_callback) {
2719         setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2720         if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
2721                              (char *)&setup, sizeof(setup),
2722                              stream->rtsp_option) < 0) {
2723             rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2724             return;
2725         }
2726         dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2727     }
2728     
2729     /* setup stream */
2730     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr) < 0) {
2731         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2732         return;
2733     }
2734
2735     /* now everything is OK, so we can send the connection parameters */
2736     rtsp_reply_header(c, RTSP_STATUS_OK);
2737     /* session ID */
2738     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2739
2740     switch(rtp_c->rtp_protocol) {
2741     case RTSP_PROTOCOL_RTP_UDP:
2742         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2743         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2744                     "client_port=%d-%d;server_port=%d-%d",
2745                     th->client_port_min, th->client_port_min + 1,
2746                     port, port + 1);
2747         break;
2748     case RTSP_PROTOCOL_RTP_TCP:
2749         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2750                     stream_index * 2, stream_index * 2 + 1);
2751         break;
2752     default:
2753         break;
2754     }
2755     if (setup.transport_option[0] != '\0') {
2756         url_fprintf(c->pb, ";%s", setup.transport_option);
2757     }
2758     url_fprintf(c->pb, "\r\n");
2759     
2760
2761     url_fprintf(c->pb, "\r\n");
2762 }
2763
2764
2765 /* find an rtp connection by using the session ID. Check consistency
2766    with filename */
2767 static HTTPContext *find_rtp_session_with_url(const char *url, 
2768                                               const char *session_id)
2769 {
2770     HTTPContext *rtp_c;
2771     char path1[1024];
2772     const char *path;
2773
2774     rtp_c = find_rtp_session(session_id);
2775     if (!rtp_c)
2776         return NULL;
2777
2778     /* find which url is asked */
2779     url_split(NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2780     path = path1;
2781     if (*path == '/')
2782         path++;
2783     if (strcmp(path, rtp_c->stream->filename) != 0)
2784         return NULL;
2785     return rtp_c;
2786 }
2787
2788 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2789 {
2790     HTTPContext *rtp_c;
2791
2792     rtp_c = find_rtp_session_with_url(url, h->session_id);
2793     if (!rtp_c) {
2794         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2795         return;
2796     }
2797     
2798     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2799         rtp_c->state != HTTPSTATE_WAIT_FEED &&
2800         rtp_c->state != HTTPSTATE_READY) {
2801         rtsp_reply_error(c, RTSP_STATUS_STATE);
2802         return;
2803     }
2804
2805     rtp_c->state = HTTPSTATE_SEND_DATA;
2806     
2807     /* now everything is OK, so we can send the connection parameters */
2808     rtsp_reply_header(c, RTSP_STATUS_OK);
2809     /* session ID */
2810     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2811     url_fprintf(c->pb, "\r\n");
2812 }
2813
2814 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2815 {
2816     HTTPContext *rtp_c;
2817
2818     rtp_c = find_rtp_session_with_url(url, h->session_id);
2819     if (!rtp_c) {
2820         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2821         return;
2822     }
2823     
2824     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2825         rtp_c->state != HTTPSTATE_WAIT_FEED) {
2826         rtsp_reply_error(c, RTSP_STATUS_STATE);
2827         return;
2828     }
2829     
2830     rtp_c->state = HTTPSTATE_READY;
2831     
2832     /* now everything is OK, so we can send the connection parameters */
2833     rtsp_reply_header(c, RTSP_STATUS_OK);
2834     /* session ID */
2835     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2836     url_fprintf(c->pb, "\r\n");
2837 }
2838
2839 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2840 {
2841     HTTPContext *rtp_c;
2842
2843     rtp_c = find_rtp_session_with_url(url, h->session_id);
2844     if (!rtp_c) {
2845         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2846         return;
2847     }
2848     
2849     /* abort the session */
2850     close_connection(rtp_c);
2851
2852     if (ff_rtsp_callback) {
2853         ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, 
2854                          NULL, 0,
2855                          rtp_c->stream->rtsp_option);
2856     }
2857
2858     /* now everything is OK, so we can send the connection parameters */
2859     rtsp_reply_header(c, RTSP_STATUS_OK);
2860     /* session ID */
2861     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2862     url_fprintf(c->pb, "\r\n");
2863 }
2864
2865
2866 /********************************************************************/
2867 /* RTP handling */
2868
2869 static HTTPContext *rtp_new_connection(HTTPContext *rtsp_c, 
2870                                        FFStream *stream, const char *session_id)
2871 {
2872     HTTPContext *c = NULL;
2873
2874     /* XXX: should output a warning page when coming
2875        close to the connection limit */
2876     if (nb_connections >= nb_max_connections)
2877         goto fail;
2878     
2879     /* add a new connection */
2880     c = av_mallocz(sizeof(HTTPContext));
2881     if (!c)
2882         goto fail;
2883     
2884     c->fd = -1;
2885     c->poll_entry = NULL;
2886     c->from_addr = rtsp_c->from_addr;
2887     c->buffer_size = IOBUFFER_INIT_SIZE;
2888     c->buffer = av_malloc(c->buffer_size);
2889     if (!c->buffer)
2890         goto fail;
2891     nb_connections++;
2892     c->stream = stream;
2893     pstrcpy(c->session_id, sizeof(c->session_id), session_id);
2894     c->state = HTTPSTATE_READY;
2895     c->is_packetized = 1;
2896     /* protocol is shown in statistics */
2897     pstrcpy(c->protocol, sizeof(c->protocol), "RTP");
2898
2899     c->next = first_http_ctx;
2900     first_http_ctx = c;
2901     return c;
2902         
2903  fail:
2904     if (c) {
2905         av_free(c->buffer);
2906         av_free(c);
2907     }
2908     return NULL;
2909 }
2910
2911 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
2912    command). if dest_addr is NULL, then TCP tunneling in RTSP is
2913    used. */
2914 static int rtp_new_av_stream(HTTPContext *c, 
2915                              int stream_index, struct sockaddr_in *dest_addr)
2916 {
2917     AVFormatContext *ctx;
2918     AVStream *st;
2919     char *ipaddr;
2920     URLContext *h;
2921     UINT8 *dummy_buf;
2922
2923     /* now we can open the relevant output stream */
2924     ctx = av_mallocz(sizeof(AVFormatContext));
2925     if (!ctx)
2926         return -1;
2927     ctx->oformat = &rtp_mux;
2928
2929     st = av_mallocz(sizeof(AVStream));
2930     if (!st)
2931         goto fail;
2932     ctx->nb_streams = 1;
2933     ctx->streams[0] = st;
2934
2935     if (!c->stream->feed || 
2936         c->stream->feed == c->stream) {
2937         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
2938     } else {
2939         memcpy(st, 
2940                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
2941                sizeof(AVStream));
2942     }
2943     
2944     if (dest_addr) {
2945         /* build destination RTP address */
2946         ipaddr = inet_ntoa(dest_addr->sin_addr);
2947         
2948         snprintf(ctx->filename, sizeof(ctx->filename),
2949                  "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
2950         
2951         printf("open %s\n", ctx->filename);
2952
2953         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
2954             goto fail;
2955         c->rtp_handles[stream_index] = h;
2956     } else {
2957         goto fail;
2958     }
2959
2960     /* normally, no packets should be output here, but the packet size may be checked */
2961     if (url_open_dyn_packet_buf(&ctx->pb, 
2962                                 url_get_max_packet_size(h)) < 0) {
2963         /* XXX: close stream */
2964         goto fail;
2965     }
2966     if (av_write_header(ctx) < 0) {
2967     fail:
2968         if (h)
2969             url_close(h);
2970         av_free(ctx);
2971         return -1;
2972     }
2973     url_close_dyn_buf(&ctx->pb, &dummy_buf);
2974     av_free(dummy_buf);
2975     
2976     c->rtp_ctx[stream_index] = ctx;
2977     return 0;
2978 }
2979
2980 /********************************************************************/
2981 /* ffserver initialization */
2982
2983 AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
2984 {
2985     AVStream *fst;
2986
2987     fst = av_mallocz(sizeof(AVStream));
2988     if (!fst)
2989         return NULL;
2990     fst->priv_data = av_mallocz(sizeof(FeedData));
2991     memcpy(&fst->codec, codec, sizeof(AVCodecContext));
2992     stream->streams[stream->nb_streams++] = fst;
2993     return fst;
2994 }
2995
2996 /* return the stream number in the feed */
2997 int add_av_stream(FFStream *feed,
2998                   AVStream *st)
2999 {
3000     AVStream *fst;
3001     AVCodecContext *av, *av1;
3002     int i;
3003
3004     av = &st->codec;
3005     for(i=0;i<feed->nb_streams;i++) {
3006         st = feed->streams[i];
3007         av1 = &st->codec;
3008         if (av1->codec_id == av->codec_id &&
3009             av1->codec_type == av->codec_type &&
3010             av1->bit_rate == av->bit_rate) {
3011
3012             switch(av->codec_type) {
3013             case CODEC_TYPE_AUDIO:
3014                 if (av1->channels == av->channels &&
3015                     av1->sample_rate == av->sample_rate)
3016                     goto found;
3017                 break;
3018             case CODEC_TYPE_VIDEO:
3019                 if (av1->width == av->width &&
3020                     av1->height == av->height &&
3021                     av1->frame_rate == av->frame_rate &&
3022                     av1->gop_size == av->gop_size)
3023                     goto found;
3024                 break;
3025             default:
3026                 av_abort();
3027             }
3028         }
3029     }
3030     
3031     fst = add_av_stream1(feed, av);
3032     if (!fst)
3033         return -1;
3034     return feed->nb_streams - 1;
3035  found:
3036     return i;
3037 }
3038
3039 void remove_stream(FFStream *stream)
3040 {
3041     FFStream **ps;
3042     ps = &first_stream;
3043     while (*ps != NULL) {
3044         if (*ps == stream) {
3045             *ps = (*ps)->next;
3046         } else {
3047             ps = &(*ps)->next;
3048         }
3049     }
3050 }
3051
3052 /* compute the needed AVStream for each file */
3053 void build_file_streams(void)
3054 {
3055     FFStream *stream, *stream_next;
3056     AVFormatContext *infile;
3057     int i;
3058
3059     /* gather all streams */
3060     for(stream = first_stream; stream != NULL; stream = stream_next) {
3061         stream_next = stream->next;
3062         if (stream->stream_type == STREAM_TYPE_LIVE &&
3063             !stream->feed) {
3064             /* the stream comes from a file */
3065             /* try to open the file */
3066             /* open stream */
3067             if (av_open_input_file(&infile, stream->feed_filename, 
3068                                    NULL, 0, NULL) < 0) {
3069                 http_log("%s not found", stream->feed_filename);
3070                 /* remove stream (no need to spend more time on it) */
3071             fail:
3072                 remove_stream(stream);
3073             } else {
3074                 /* find all the AVStreams inside and reference them in
3075                    'stream' */
3076                 if (av_find_stream_info(infile) < 0) {
3077                     http_log("Could not find codec parameters from '%s'", 
3078                              stream->feed_filename);
3079                     av_close_input_file(infile);
3080                     goto fail;
3081                 }
3082                 for(i=0;i<infile->nb_streams;i++) {
3083                     add_av_stream1(stream, &infile->streams[i]->codec);
3084                 }
3085                 av_close_input_file(infile);
3086             }
3087         }
3088     }
3089 }
3090
3091 /* compute the needed AVStream for each feed */
3092 void build_feed_streams(void)
3093 {
3094     FFStream *stream, *feed;
3095     int i;
3096
3097     /* gather all streams */
3098     for(stream = first_stream; stream != NULL; stream = stream->next) {
3099         feed = stream->feed;
3100         if (feed) {
3101             if (!stream->is_feed) {
3102                 /* we handle a stream coming from a feed */
3103                 for(i=0;i<stream->nb_streams;i++) {
3104                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3105                 }
3106             }
3107         }
3108     }
3109
3110     /* gather all streams */
3111     for(stream = first_stream; stream != NULL; stream = stream->next) {
3112         feed = stream->feed;
3113         if (feed) {
3114             if (stream->is_feed) {
3115                 for(i=0;i<stream->nb_streams;i++) {
3116                     stream->feed_streams[i] = i;
3117                 }
3118             }
3119         }
3120     }
3121
3122     /* create feed files if needed */
3123     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3124         int fd;
3125
3126         if (url_exist(feed->feed_filename)) {
3127             /* See if it matches */
3128             AVFormatContext *s;
3129             int matches = 0;
3130
3131             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3132                 /* Now see if it matches */
3133                 if (s->nb_streams == feed->nb_streams) {
3134                     matches = 1;
3135                     for(i=0;i<s->nb_streams;i++) {
3136                         AVStream *sf, *ss;
3137                         sf = feed->streams[i];
3138                         ss = s->streams[i];
3139
3140                         if (sf->index != ss->index ||
3141                             sf->id != ss->id) {
3142                             printf("Index & Id do not match for stream %d\n", i);
3143                             matches = 0;
3144                         } else {
3145                             AVCodecContext *ccf, *ccs;
3146
3147                             ccf = &sf->codec;
3148                             ccs = &ss->codec;
3149 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3150
3151                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3152                                 printf("Codecs do not match for stream %d\n", i);
3153                                 matches = 0;
3154                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3155                                 printf("Codec bitrates do not match for stream %d\n", i);
3156                                 matches = 0;
3157                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3158                                 if (CHECK_CODEC(frame_rate) ||
3159                                     CHECK_CODEC(width) ||
3160                                     CHECK_CODEC(height)) {
3161                                     printf("Codec width, height and framerate do not match for stream %d\n", i);
3162                                     matches = 0;
3163                                 }
3164                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3165                                 if (CHECK_CODEC(sample_rate) ||
3166                                     CHECK_CODEC(channels) ||
3167                                     CHECK_CODEC(frame_size)) {
3168                                     printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3169                                     matches = 0;
3170                                 }
3171                             } else {
3172                                 printf("Unknown codec type\n");
3173                                 matches = 0;
3174                             }
3175                         }
3176                         if (!matches) {
3177                             break;
3178                         }
3179                     }
3180                 } else {
3181                     printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3182                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3183                 }
3184
3185                 av_close_input_file(s);
3186             } else {
3187                 printf("Deleting feed file '%s' as it appears to be corrupt\n",
3188                         feed->feed_filename);
3189             }
3190             if (!matches)
3191                 unlink(feed->feed_filename);
3192         }
3193         if (!url_exist(feed->feed_filename)) {
3194             AVFormatContext s1, *s = &s1;
3195
3196             /* only write the header of the ffm file */
3197             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3198                 fprintf(stderr, "Could not open output feed file '%s'\n",
3199                         feed->feed_filename);
3200                 exit(1);
3201             }
3202             s->oformat = feed->fmt;
3203             s->nb_streams = feed->nb_streams;
3204             for(i=0;i<s->nb_streams;i++) {
3205                 AVStream *st;
3206                 st = feed->streams[i];
3207                 s->streams[i] = st;
3208             }
3209             av_write_header(s);
3210             /* XXX: need better api */
3211             av_freep(&s->priv_data);
3212             url_fclose(&s->pb);
3213         }
3214         /* get feed size and write index */
3215         fd = open(feed->feed_filename, O_RDONLY);
3216         if (fd < 0) {
3217             fprintf(stderr, "Could not open output feed file '%s'\n",
3218                     feed->feed_filename);
3219             exit(1);
3220         }
3221
3222         feed->feed_write_index = ffm_read_write_index(fd);
3223         feed->feed_size = lseek(fd, 0, SEEK_END);
3224         /* ensure that we do not wrap before the end of file */
3225         if (feed->feed_max_size < feed->feed_size)
3226             feed->feed_max_size = feed->feed_size;
3227
3228         close(fd);
3229     }
3230 }
3231
3232 static void get_arg(char *buf, int buf_size, const char **pp)
3233 {
3234     const char *p;
3235     char *q;
3236     int quote;
3237
3238     p = *pp;
3239     while (isspace(*p)) p++;
3240     q = buf;
3241     quote = 0;
3242     if (*p == '\"' || *p == '\'')
3243         quote = *p++;
3244     for(;;) {
3245         if (quote) {
3246             if (*p == quote)
3247                 break;
3248         } else {
3249             if (isspace(*p))
3250                 break;
3251         }
3252         if (*p == '\0')
3253             break;
3254         if ((q - buf) < buf_size - 1)
3255             *q++ = *p;
3256         p++;
3257     }
3258     *q = '\0';
3259     if (quote && *p == quote)
3260         p++;
3261     *pp = p;
3262 }
3263
3264 /* add a codec and set the default parameters */
3265 void add_codec(FFStream *stream, AVCodecContext *av)
3266 {
3267     AVStream *st;
3268
3269     /* compute default parameters */
3270     switch(av->codec_type) {
3271     case CODEC_TYPE_AUDIO:
3272         if (av->bit_rate == 0)
3273             av->bit_rate = 64000;
3274         if (av->sample_rate == 0)
3275             av->sample_rate = 22050;
3276         if (av->channels == 0)
3277             av->channels = 1;
3278         break;
3279     case CODEC_TYPE_VIDEO:
3280         if (av->bit_rate == 0)
3281             av->bit_rate = 64000;
3282         if (av->frame_rate == 0)
3283             av->frame_rate = 5 * FRAME_RATE_BASE;
3284         if (av->width == 0 || av->height == 0) {
3285             av->width = 160;
3286             av->height = 128;
3287         }
3288         /* Bitrate tolerance is less for streaming */
3289         if (av->bit_rate_tolerance == 0)
3290             av->bit_rate_tolerance = av->bit_rate / 4;
3291         if (av->qmin == 0)
3292             av->qmin = 3;
3293         if (av->qmax == 0)
3294             av->qmax = 31;
3295         if (av->max_qdiff == 0)
3296             av->max_qdiff = 3;
3297         av->qcompress = 0.5;
3298         av->qblur = 0.5;
3299
3300         if (!av->rc_eq)
3301             av->rc_eq = "tex^qComp";
3302         if (!av->i_quant_factor)
3303             av->i_quant_factor = -0.8;
3304         if (!av->b_quant_factor)
3305             av->b_quant_factor = 1.25;
3306         if (!av->b_quant_offset)
3307             av->b_quant_offset = 1.25;
3308         if (!av->rc_min_rate)
3309             av->rc_min_rate = av->bit_rate / 2;
3310         if (!av->rc_max_rate)
3311             av->rc_max_rate = av->bit_rate * 2;
3312
3313         break;
3314     default:
3315         av_abort();
3316     }
3317
3318     st = av_mallocz(sizeof(AVStream));
3319     if (!st)
3320         return;
3321     stream->streams[stream->nb_streams++] = st;
3322     memcpy(&st->codec, av, sizeof(AVCodecContext));
3323 }
3324
3325 int opt_audio_codec(const char *arg)
3326 {
3327     AVCodec *p;
3328
3329     p = first_avcodec;
3330     while (p) {
3331         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3332             break;
3333         p = p->next;
3334     }
3335     if (p == NULL) {
3336         return CODEC_ID_NONE;
3337     }
3338
3339     return p->id;
3340 }
3341
3342 int opt_video_codec(const char *arg)
3343 {
3344     AVCodec *p;
3345
3346     p = first_avcodec;
3347     while (p) {
3348         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3349             break;
3350         p = p->next;
3351     }
3352     if (p == NULL) {
3353         return CODEC_ID_NONE;
3354     }
3355
3356     return p->id;
3357 }
3358
3359 /* simplistic plugin support */
3360
3361 void load_module(const char *filename)
3362 {
3363     void *dll;
3364     void (*init_func)(void);
3365     dll = dlopen(filename, RTLD_NOW);
3366     if (!dll) {
3367         fprintf(stderr, "Could not load module '%s' - %s\n",
3368                 filename, dlerror());
3369         return;
3370     }
3371     
3372     init_func = dlsym(dll, "ffserver_module_init");
3373     if (!init_func) {
3374         fprintf(stderr, 
3375                 "%s: init function 'ffserver_module_init()' not found\n",
3376                 filename);
3377         dlclose(dll);
3378     }
3379
3380     init_func();
3381 }
3382
3383 int parse_ffconfig(const char *filename)
3384 {
3385     FILE *f;
3386     char line[1024];
3387     char cmd[64];
3388     char arg[1024];
3389     const char *p;
3390     int val, errors, line_num;
3391     FFStream **last_stream, *stream, *redirect;
3392     FFStream **last_feed, *feed;
3393     AVCodecContext audio_enc, video_enc;
3394     int audio_id, video_id;
3395
3396     f = fopen(filename, "r");
3397     if (!f) {
3398         perror(filename);
3399         return -1;
3400     }
3401     
3402     errors = 0;
3403     line_num = 0;
3404     first_stream = NULL;
3405     last_stream = &first_stream;
3406     first_feed = NULL;
3407     last_feed = &first_feed;
3408     stream = NULL;
3409     feed = NULL;
3410     redirect = NULL;
3411     audio_id = CODEC_ID_NONE;
3412     video_id = CODEC_ID_NONE;
3413     for(;;) {
3414         if (fgets(line, sizeof(line), f) == NULL)
3415             break;
3416         line_num++;
3417         p = line;
3418         while (isspace(*p)) 
3419             p++;
3420         if (*p == '\0' || *p == '#')
3421             continue;
3422
3423         get_arg(cmd, sizeof(cmd), &p);
3424         
3425         if (!strcasecmp(cmd, "Port")) {
3426             get_arg(arg, sizeof(arg), &p);
3427             my_http_addr.sin_port = htons (atoi(arg));
3428         } else if (!strcasecmp(cmd, "BindAddress")) {
3429             get_arg(arg, sizeof(arg), &p);
3430             if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3431                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3432                         filename, line_num, arg);
3433                 errors++;
3434             }
3435         } else if (!strcasecmp(cmd, "NoDaemon")) {
3436             ffserver_daemon = 0;
3437         } else if (!strcasecmp(cmd, "RTSPPort")) {
3438             get_arg(arg, sizeof(arg), &p);
3439             my_rtsp_addr.sin_port = htons (atoi(arg));
3440         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3441             get_arg(arg, sizeof(arg), &p);
3442             if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3443                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3444                         filename, line_num, arg);
3445                 errors++;
3446             }
3447         } else if (!strcasecmp(cmd, "MaxClients")) {
3448             get_arg(arg, sizeof(arg), &p);
3449             val = atoi(arg);
3450             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3451                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
3452                         filename, line_num, arg);
3453                 errors++;
3454             } else {
3455                 nb_max_connections = val;
3456             }
3457         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3458             get_arg(arg, sizeof(arg), &p);
3459             val = atoi(arg);
3460             if (val < 10 || val > 100000) {
3461                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
3462                         filename, line_num, arg);
3463                 errors++;
3464             } else {
3465                 nb_max_bandwidth = val;
3466             }
3467         } else if (!strcasecmp(cmd, "CustomLog")) {
3468             get_arg(logfilename, sizeof(logfilename), &p);
3469         } else if (!strcasecmp(cmd, "<Feed")) {
3470             /*********************************************/
3471             /* Feed related options */
3472             char *q;
3473             if (stream || feed) {
3474                 fprintf(stderr, "%s:%d: Already in a tag\n",
3475                         filename, line_num);
3476             } else {
3477                 feed = av_mallocz(sizeof(FFStream));
3478                 /* add in stream list */
3479                 *last_stream = feed;
3480                 last_stream = &feed->next;
3481                 /* add in feed list */
3482                 *last_feed = feed;
3483                 last_feed = &feed->next_feed;
3484                 
3485                 get_arg(feed->filename, sizeof(feed->filename), &p);
3486                 q = strrchr(feed->filename, '>');
3487                 if (*q)
3488                     *q = '\0';
3489                 feed->fmt = guess_format("ffm", NULL, NULL);
3490                 /* defaut feed file */
3491                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3492                          "/tmp/%s.ffm", feed->filename);
3493                 feed->feed_max_size = 5 * 1024 * 1024;
3494                 feed->is_feed = 1;
3495                 feed->feed = feed; /* self feeding :-) */
3496             }
3497         } else if (!strcasecmp(cmd, "Launch")) {
3498             if (feed) {
3499                 int i;
3500
3501                 feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3502
3503                 feed->child_argv[0] = av_malloc(7);
3504                 strcpy(feed->child_argv[0], "ffmpeg");
3505
3506                 for (i = 1; i < 62; i++) {
3507                     char argbuf[256];
3508
3509                     get_arg(argbuf, sizeof(argbuf), &p);
3510                     if (!argbuf[0])
3511                         break;
3512
3513                     feed->child_argv[i] = av_malloc(strlen(argbuf + 1));
3514                     strcpy(feed->child_argv[i], argbuf);
3515                 }
3516
3517                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3518
3519                 snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
3520                     ntohs(my_http_addr.sin_port), feed->filename);
3521             }
3522         } else if (!strcasecmp(cmd, "File")) {
3523             if (feed) {
3524                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3525             } else if (stream) {
3526                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3527             }
3528         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3529             if (feed) {
3530                 const char *p1;
3531                 double fsize;
3532
3533                 get_arg(arg, sizeof(arg), &p);
3534                 p1 = arg;
3535                 fsize = strtod(p1, (char **)&p1);
3536                 switch(toupper(*p1)) {
3537                 case 'K':
3538                     fsize *= 1024;
3539                     break;
3540                 case 'M':
3541                     fsize *= 1024 * 1024;
3542                     break;
3543                 case 'G':
3544                     fsize *= 1024 * 1024 * 1024;
3545                     break;
3546                 }
3547                 feed->feed_max_size = (INT64)fsize;
3548             }
3549         } else if (!strcasecmp(cmd, "</Feed>")) {
3550             if (!feed) {
3551                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3552                         filename, line_num);
3553                 errors++;
3554 #if 0
3555             } else {
3556                 /* Make sure that we start out clean */
3557                 if (unlink(feed->feed_filename) < 0 
3558                     && errno != ENOENT) {
3559                     fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3560                         filename, line_num, feed->feed_filename, strerror(errno));
3561                     errors++;
3562                 }
3563 #endif
3564             }
3565             feed = NULL;
3566         } else if (!strcasecmp(cmd, "<Stream")) {
3567             /*********************************************/
3568             /* Stream related options */
3569             char *q;
3570             if (stream || feed) {
3571                 fprintf(stderr, "%s:%d: Already in a tag\n",
3572                         filename, line_num);
3573             } else {
3574                 stream = av_mallocz(sizeof(FFStream));
3575                 *last_stream = stream;
3576                 last_stream = &stream->next;
3577
3578                 get_arg(stream->filename, sizeof(stream->filename), &p);
3579                 q = strrchr(stream->filename, '>');
3580                 if (*q)
3581                     *q = '\0';
3582                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3583                 memset(&audio_enc, 0, sizeof(AVCodecContext));
3584                 memset(&video_enc, 0, sizeof(AVCodecContext));
3585                 audio_id = CODEC_ID_NONE;
3586                 video_id = CODEC_ID_NONE;
3587                 if (stream->fmt) {
3588                     audio_id = stream->fmt->audio_codec;
3589                     video_id = stream->fmt->video_codec;
3590                 }
3591             }
3592         } else if (!strcasecmp(cmd, "Feed")) {
3593             get_arg(arg, sizeof(arg), &p);
3594             if (stream) {
3595                 FFStream *sfeed;
3596                 
3597                 sfeed = first_feed;
3598                 while (sfeed != NULL) {
3599                     if (!strcmp(sfeed->filename, arg))
3600                         break;
3601                     sfeed = sfeed->next_feed;
3602                 }
3603                 if (!sfeed) {
3604                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3605                             filename, line_num, arg);
3606                 } else {
3607                     stream->feed = sfeed;
3608                 }
3609             }
3610         } else if (!strcasecmp(cmd, "Format")) {
3611             get_arg(arg, sizeof(arg), &p);
3612             if (!strcmp(arg, "status")) {
3613                 stream->stream_type = STREAM_TYPE_STATUS;
3614                 stream->fmt = NULL;
3615             } else {
3616                 stream->stream_type = STREAM_TYPE_LIVE;
3617                 /* jpeg cannot be used here, so use single frame jpeg */
3618                 if (!strcmp(arg, "jpeg"))
3619                     strcpy(arg, "singlejpeg");
3620                 stream->fmt = guess_stream_format(arg, NULL, NULL);
3621                 if (!stream->fmt) {
3622                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
3623                             filename, line_num, arg);
3624                     errors++;
3625                 }
3626             }
3627             if (stream->fmt) {
3628                 audio_id = stream->fmt->audio_codec;
3629                 video_id = stream->fmt->video_codec;
3630             }
3631         } else if (!strcasecmp(cmd, "FaviconURL")) {
3632             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3633                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3634             } else {
3635                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
3636                             filename, line_num);
3637                 errors++;
3638             }
3639         } else if (!strcasecmp(cmd, "Author")) {
3640             if (stream) {
3641                 get_arg(stream->author, sizeof(stream->author), &p);
3642             }
3643         } else if (!strcasecmp(cmd, "Comment")) {
3644             if (stream) {
3645                 get_arg(stream->comment, sizeof(stream->comment), &p);
3646             }
3647         } else if (!strcasecmp(cmd, "Copyright")) {
3648             if (stream) {
3649                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
3650             }
3651         } else if (!strcasecmp(cmd, "Title")) {
3652             if (stream) {
3653                 get_arg(stream->title, sizeof(stream->title), &p);
3654             }
3655         } else if (!strcasecmp(cmd, "Preroll")) {
3656             get_arg(arg, sizeof(arg), &p);
3657             if (stream) {
3658                 stream->prebuffer = atof(arg) * 1000;
3659             }
3660         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
3661             if (stream) {
3662                 stream->send_on_key = 1;
3663             }
3664         } else if (!strcasecmp(cmd, "AudioCodec")) {
3665             get_arg(arg, sizeof(arg), &p);
3666             audio_id = opt_audio_codec(arg);
3667             if (audio_id == CODEC_ID_NONE) {
3668                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
3669                         filename, line_num, arg);
3670                 errors++;
3671             }
3672         } else if (!strcasecmp(cmd, "VideoCodec")) {
3673             get_arg(arg, sizeof(arg), &p);
3674             video_id = opt_video_codec(arg);
3675             if (video_id == CODEC_ID_NONE) {
3676                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
3677                         filename, line_num, arg);
3678                 errors++;
3679             }
3680         } else if (!strcasecmp(cmd, "MaxTime")) {
3681             get_arg(arg, sizeof(arg), &p);
3682             if (stream) {
3683                 stream->max_time = atof(arg) * 1000;
3684             }
3685         } else if (!strcasecmp(cmd, "AudioBitRate")) {
3686             get_arg(arg, sizeof(arg), &p);
3687             if (stream) {
3688                 audio_enc.bit_rate = atoi(arg) * 1000;
3689             }
3690         } else if (!strcasecmp(cmd, "AudioChannels")) {
3691             get_arg(arg, sizeof(arg), &p);
3692             if (stream) {
3693                 audio_enc.channels = atoi(arg);
3694             }
3695         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
3696             get_arg(arg, sizeof(arg), &p);
3697             if (stream) {
3698                 audio_enc.sample_rate = atoi(arg);
3699             }
3700         } else if (!strcasecmp(cmd, "AudioQuality")) {
3701             get_arg(arg, sizeof(arg), &p);
3702             if (stream) {
3703                 audio_enc.quality = atof(arg) * 1000;
3704             }
3705         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
3706             if (stream) {
3707                 int minrate, maxrate;
3708
3709                 get_arg(arg, sizeof(arg), &p);
3710
3711                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
3712                     video_enc.rc_min_rate = minrate * 1000;
3713                     video_enc.rc_max_rate = maxrate * 1000;
3714                 } else {
3715                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", 
3716                             filename, line_num, arg);
3717                     errors++;
3718                 }
3719             }
3720         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
3721             if (stream) {
3722                 get_arg(arg, sizeof(arg), &p);
3723                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
3724             }
3725         } else if (!strcasecmp(cmd, "VideoBitRate")) {
3726             get_arg(arg, sizeof(arg), &p);
3727             if (stream) {
3728                 video_enc.bit_rate = atoi(arg) * 1000;
3729             }
3730         } else if (!strcasecmp(cmd, "VideoSize")) {
3731             get_arg(arg, sizeof(arg), &p);
3732             if (stream) {
3733                 parse_image_size(&video_enc.width, &video_enc.height, arg);
3734                 if ((video_enc.width % 16) != 0 ||
3735                     (video_enc.height % 16) != 0) {
3736                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
3737                             filename, line_num);
3738                     errors++;
3739                 }
3740             }
3741         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
3742             get_arg(arg, sizeof(arg), &p);
3743             if (stream) {
3744                 video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
3745             }
3746         } else if (!strcasecmp(cmd, "VideoGopSize")) {
3747             get_arg(arg, sizeof(arg), &p);
3748             if (stream) {
3749                 video_enc.gop_size = atoi(arg);
3750             }
3751         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
3752             if (stream) {
3753                 video_enc.gop_size = 1;
3754             }
3755         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
3756             if (stream) {
3757                 video_enc.flags |= CODEC_FLAG_HQ;
3758             }
3759         } else if (!strcasecmp(cmd, "VideoQDiff")) {
3760             get_arg(arg, sizeof(arg), &p);
3761             if (stream) {
3762                 video_enc.max_qdiff = atoi(arg);
3763                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
3764                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
3765                             filename, line_num);
3766                     errors++;
3767                 }
3768             }
3769         } else if (!strcasecmp(cmd, "VideoQMax")) {
3770             get_arg(arg, sizeof(arg), &p);
3771             if (stream) {
3772                 video_enc.qmax = atoi(arg);
3773                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
3774                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
3775                             filename, line_num);
3776                     errors++;
3777                 }
3778             }
3779         } else if (!strcasecmp(cmd, "VideoQMin")) {
3780             get_arg(arg, sizeof(arg), &p);
3781             if (stream) {
3782                 video_enc.qmin = atoi(arg);
3783                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
3784                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
3785                             filename, line_num);
3786                     errors++;
3787                 }
3788             }
3789         } else if (!strcasecmp(cmd, "LumaElim")) {
3790             get_arg(arg, sizeof(arg), &p);
3791             if (stream) {
3792                 video_enc.luma_elim_threshold = atoi(arg);
3793             }
3794         } else if (!strcasecmp(cmd, "ChromaElim")) {
3795             get_arg(arg, sizeof(arg), &p);
3796             if (stream) {
3797                 video_enc.chroma_elim_threshold = atoi(arg);
3798             }
3799         } else if (!strcasecmp(cmd, "LumiMask")) {
3800             get_arg(arg, sizeof(arg), &p);
3801             if (stream) {
3802                 video_enc.lumi_masking = atof(arg);
3803             }
3804         } else if (!strcasecmp(cmd, "DarkMask")) {
3805             get_arg(arg, sizeof(arg), &p);
3806             if (stream) {
3807                 video_enc.dark_masking = atof(arg);
3808             }
3809         } else if (!strcasecmp(cmd, "NoVideo")) {
3810             video_id = CODEC_ID_NONE;
3811         } else if (!strcasecmp(cmd, "NoAudio")) {
3812             audio_id = CODEC_ID_NONE;
3813         } else if (!strcasecmp(cmd, "ACL")) {
3814             IPAddressACL acl;
3815             struct hostent *he;
3816
3817             get_arg(arg, sizeof(arg), &p);
3818             if (strcasecmp(arg, "allow") == 0) {
3819                 acl.action = IP_ALLOW;
3820             } else if (strcasecmp(arg, "deny") == 0) {
3821                 acl.action = IP_DENY;
3822             } else {
3823                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
3824                         filename, line_num, arg);
3825                 errors++;
3826             }
3827
3828             get_arg(arg, sizeof(arg), &p);
3829
3830             he = gethostbyname(arg);
3831             if (!he) {
3832                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
3833                         filename, line_num, arg);
3834                 errors++;
3835             } else {
3836                 /* Only take the first */
3837                 acl.first = *(struct in_addr *) he->h_addr_list[0];
3838                 acl.last = acl.first;
3839             }
3840
3841             get_arg(arg, sizeof(arg), &p);
3842
3843             if (arg[0]) {
3844                 he = gethostbyname(arg);
3845                 if (!he) {
3846                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
3847                             filename, line_num, arg);
3848                     errors++;
3849                 } else {
3850                     /* Only take the first */
3851                     acl.last = *(struct in_addr *) he->h_addr_list[0];
3852                 }
3853             }
3854
3855             if (!errors) {
3856                 IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
3857                 IPAddressACL **naclp = 0;
3858
3859                 *nacl = acl;
3860                 nacl->next = 0;
3861
3862                 if (stream) {
3863                     naclp = &stream->acl;
3864                 } else if (feed) {
3865                     naclp = &feed->acl;
3866                 } else {
3867                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
3868                             filename, line_num);
3869                     errors++;
3870                 }
3871
3872                 if (naclp) {
3873                     while (*naclp)
3874                         naclp = &(*naclp)->next;
3875
3876                     *naclp = nacl;
3877                 }
3878             }
3879         } else if (!strcasecmp(cmd, "RTSPOption")) {
3880             get_arg(arg, sizeof(arg), &p);
3881             if (stream) {
3882                 av_freep(&stream->rtsp_option);
3883                 /* XXX: av_strdup ? */
3884                 stream->rtsp_option = av_malloc(strlen(arg) + 1);
3885                 if (stream->rtsp_option) {
3886                     strcpy(stream->rtsp_option, arg);
3887                 }
3888             }
3889         } else if (!strcasecmp(cmd, "</Stream>")) {
3890             if (!stream) {
3891                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
3892                         filename, line_num);
3893                 errors++;
3894             }
3895             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
3896                 if (audio_id != CODEC_ID_NONE) {
3897                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
3898                     audio_enc.codec_id = audio_id;
3899                     add_codec(stream, &audio_enc);
3900                 }
3901                 if (video_id != CODEC_ID_NONE) {
3902                     video_enc.codec_type = CODEC_TYPE_VIDEO;
3903                     video_enc.codec_id = video_id;
3904                     add_codec(stream, &video_enc);
3905                 }
3906             }
3907             stream = NULL;
3908         } else if (!strcasecmp(cmd, "<Redirect")) {
3909             /*********************************************/
3910             char *q;
3911             if (stream || feed || redirect) {
3912                 fprintf(stderr, "%s:%d: Already in a tag\n",
3913                         filename, line_num);
3914                 errors++;
3915             } else {
3916                 redirect = av_mallocz(sizeof(FFStream));
3917                 *last_stream = redirect;
3918                 last_stream = &redirect->next;
3919
3920                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
3921                 q = strrchr(redirect->filename, '>');
3922                 if (*q)
3923                     *q = '\0';
3924                 redirect->stream_type = STREAM_TYPE_REDIRECT;
3925             }
3926         } else if (!strcasecmp(cmd, "URL")) {
3927             if (redirect) {
3928                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
3929             }
3930         } else if (!strcasecmp(cmd, "</Redirect>")) {
3931             if (!redirect) {
3932                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
3933                         filename, line_num);
3934                 errors++;
3935             }
3936             if (!redirect->feed_filename[0]) {
3937                 fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
3938                         filename, line_num);
3939                 errors++;
3940             }
3941             redirect = NULL;
3942         } else if (!strcasecmp(cmd, "LoadModule")) {
3943             get_arg(arg, sizeof(arg), &p);
3944             load_module(arg);
3945         } else {
3946             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
3947                     filename, line_num, cmd);
3948             errors++;
3949         }
3950     }
3951
3952     fclose(f);
3953     if (errors)
3954         return -1;
3955     else
3956         return 0;
3957 }
3958
3959
3960 #if 0
3961 static void write_packet(FFCodec *ffenc,
3962                          UINT8 *buf, int size)
3963 {
3964     PacketHeader hdr;
3965     AVCodecContext *enc = &ffenc->enc;
3966     UINT8 *wptr;
3967     mk_header(&hdr, enc, size);
3968     wptr = http_fifo.wptr;
3969     fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
3970     fifo_write(&http_fifo, buf, size, &wptr);
3971     /* atomic modification of wptr */
3972     http_fifo.wptr = wptr;
3973     ffenc->data_count += size;
3974     ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
3975 }
3976 #endif
3977
3978 void help(void)
3979 {
3980     printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
3981            "usage: ffserver [-L] [-h] [-f configfile]\n"
3982            "Hyper fast multi format Audio/Video streaming server\n"
3983            "\n"
3984            "-L            : print the LICENCE\n"
3985            "-h            : this help\n"
3986            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
3987            );
3988 }
3989
3990 void licence(void)
3991 {
3992     printf(
3993     "ffserver version " FFMPEG_VERSION "\n"
3994     "Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
3995     "This library is free software; you can redistribute it and/or\n"
3996     "modify it under the terms of the GNU Lesser General Public\n"
3997     "License as published by the Free Software Foundation; either\n"
3998     "version 2 of the License, or (at your option) any later version.\n"
3999     "\n"
4000     "This library is distributed in the hope that it will be useful,\n"
4001     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4002     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4003     "Lesser General Public License for more details.\n"
4004     "\n"
4005     "You should have received a copy of the GNU Lesser General Public\n"
4006     "License along with this library; if not, write to the Free Software\n"
4007     "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4008     );
4009 }
4010
4011 static void handle_child_exit(int sig)
4012 {
4013     pid_t pid;
4014     int status;
4015
4016     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4017         FFStream *feed;
4018
4019         for (feed = first_feed; feed; feed = feed->next) {
4020             if (feed->pid == pid) {
4021                 int uptime = time(0) - feed->pid_start;
4022
4023                 feed->pid = 0;
4024                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4025
4026                 if (uptime < 30) {
4027                     /* Turn off any more restarts */
4028                     feed->child_argv = 0;
4029                 }    
4030             }
4031         }
4032     }
4033
4034     need_to_start_children = 1;
4035 }
4036
4037 int main(int argc, char **argv)
4038 {
4039     const char *config_filename;
4040     int c;
4041     struct sigaction sigact;
4042
4043     av_register_all();
4044
4045     config_filename = "/etc/ffserver.conf";
4046
4047     my_program_name = argv[0];
4048     my_program_dir = getcwd(0, 0);
4049     ffserver_daemon = 1;
4050     
4051     for(;;) {
4052         c = getopt(argc, argv, "ndLh?f:");
4053         if (c == -1)
4054             break;
4055         switch(c) {
4056         case 'L':
4057             licence();
4058             exit(1);
4059         case '?':
4060         case 'h':
4061             help();
4062             exit(1);
4063         case 'n':
4064             no_launch = 1;
4065             break;
4066         case 'd':
4067             ffserver_debug = 1;
4068             ffserver_daemon = 0;
4069             break;
4070         case 'f':
4071             config_filename = optarg;
4072             break;
4073         default:
4074             exit(2);
4075         }
4076     }
4077
4078     putenv("http_proxy");               /* Kill the http_proxy */
4079
4080     srandom(gettime_ms() + (getpid() << 16));
4081
4082     /* address on which the server will handle HTTP connections */
4083     my_http_addr.sin_family = AF_INET;
4084     my_http_addr.sin_port = htons (8080);
4085     my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4086
4087     /* address on which the server will handle RTSP connections */
4088     my_rtsp_addr.sin_family = AF_INET;
4089     my_rtsp_addr.sin_port = htons (5454);
4090     my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4091     
4092     nb_max_connections = 5;
4093     nb_max_bandwidth = 1000;
4094     first_stream = NULL;
4095     logfilename[0] = '\0';
4096
4097     memset(&sigact, 0, sizeof(sigact));
4098     sigact.sa_handler = handle_child_exit;
4099     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4100     sigaction(SIGCHLD, &sigact, 0);
4101
4102     if (parse_ffconfig(config_filename) < 0) {
4103         fprintf(stderr, "Incorrect config file - exiting.\n");
4104         exit(1);
4105     }
4106
4107     build_file_streams();
4108
4109     build_feed_streams();
4110
4111     /* put the process in background and detach it from its TTY */
4112     if (ffserver_daemon) {
4113         int pid;
4114
4115         pid = fork();
4116         if (pid < 0) {
4117             perror("fork");
4118             exit(1);
4119         } else if (pid > 0) {
4120             /* parent : exit */
4121             exit(0);
4122         } else {
4123             /* child */
4124             setsid();
4125             chdir("/");
4126             close(0);
4127             open("/dev/null", O_RDWR);
4128             if (strcmp(logfilename, "-") != 0) {
4129                 close(1);
4130                 dup(0);
4131             }
4132             close(2);
4133             dup(0);
4134         }
4135     }
4136
4137     /* signal init */
4138     signal(SIGPIPE, SIG_IGN);
4139
4140     /* open log file if needed */
4141     if (logfilename[0] != '\0') {
4142         if (!strcmp(logfilename, "-"))
4143             logfile = stdout;
4144         else
4145             logfile = fopen(logfilename, "w");
4146     }
4147
4148     if (http_server() < 0) {
4149         fprintf(stderr, "Could not start server\n");
4150         exit(1);
4151     }
4152
4153     return 0;
4154 }