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