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