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