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