]> git.sesse.net Git - ffmpeg/blob - ffserver.c
fix ac3 and dts detection (patch by Joakim Plate <joakim.plate at ecce.se>)
[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     struct HTTPContext *next;
104     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
105     int64_t data_count;
106     /* feed input */
107     int feed_fd;
108     /* input format handling */
109     AVFormatContext *fmt_in;
110     long start_time;            /* In milliseconds - this wraps fairly often */
111     int64_t first_pts;            /* initial pts value */
112     int64_t cur_pts;             /* current pts value from the stream in us */
113     int64_t cur_frame_duration;  /* duration of the current frame in us */
114     int cur_frame_bytes;       /* output frame size, needed to compute
115                                   the time at which we send each
116                                   packet */
117     int pts_stream_index;        /* stream we choose as clock reference */
118     int64_t cur_clock;           /* current clock reference value in us */
119     /* output format handling */
120     struct FFStream *stream;
121     /* -1 is invalid stream */
122     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
123     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
124     int switch_pending;
125     AVFormatContext fmt_ctx; /* instance of FFStream for one user */
126     int last_packet_sent; /* true if last data packet was sent */
127     int suppress_log;
128     DataRateData datarate;
129     int wmp_client_id;
130     char protocol[16];
131     char method[16];
132     char url[128];
133     int buffer_size;
134     uint8_t *buffer;
135     int is_packetized; /* if true, the stream is packetized */
136     int packet_stream_index; /* current stream for output in state machine */
137     
138     /* RTSP state specific */
139     uint8_t *pb_buffer; /* XXX: use that in all the code */
140     ByteIOContext *pb;
141     int seq; /* RTSP sequence number */
142     
143     /* RTP state specific */
144     enum RTSPProtocol rtp_protocol;
145     char session_id[32]; /* session id */
146     AVFormatContext *rtp_ctx[MAX_STREAMS];
147
148     /* RTP/UDP specific */
149     URLContext *rtp_handles[MAX_STREAMS];
150
151     /* RTP/TCP specific */
152     struct HTTPContext *rtsp_c;
153     uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
154 } HTTPContext;
155
156 static AVFrame dummy_frame;
157
158 /* each generated stream is described here */
159 enum StreamType {
160     STREAM_TYPE_LIVE,
161     STREAM_TYPE_STATUS,
162     STREAM_TYPE_REDIRECT,
163 };
164
165 enum IPAddressAction {
166     IP_ALLOW = 1,
167     IP_DENY,
168 };
169
170 typedef struct IPAddressACL {
171     struct IPAddressACL *next;
172     enum IPAddressAction action;
173     /* These are in host order */
174     struct in_addr first;
175     struct in_addr last;
176 } IPAddressACL;
177
178 /* description of each stream of the ffserver.conf file */
179 typedef struct FFStream {
180     enum StreamType stream_type;
181     char filename[1024];     /* stream filename */
182     struct FFStream *feed;   /* feed we are using (can be null if
183                                 coming from file) */
184     AVFormatParameters *ap_in; /* input parameters */
185     AVInputFormat *ifmt;       /* if non NULL, force input format */
186     AVOutputFormat *fmt;
187     IPAddressACL *acl;
188     int nb_streams;
189     int prebuffer;      /* Number of millseconds early to start */
190     long max_time;      /* Number of milliseconds to run */
191     int send_on_key;
192     AVStream *streams[MAX_STREAMS];
193     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
194     char feed_filename[1024]; /* file name of the feed storage, or
195                                  input file name for a stream */
196     char author[512];
197     char title[512];
198     char copyright[512];
199     char comment[512];
200     pid_t pid;  /* Of ffmpeg process */
201     time_t pid_start;  /* Of ffmpeg process */
202     char **child_argv;
203     struct FFStream *next;
204     int bandwidth; /* bandwidth, in kbits/s */
205     /* RTSP options */
206     char *rtsp_option;
207     /* multicast specific */
208     int is_multicast;
209     struct in_addr multicast_ip;
210     int multicast_port; /* first port used for multicast */
211     int multicast_ttl;
212     int loop; /* if true, send the stream in loops (only meaningful if file) */
213
214     /* feed specific */
215     int feed_opened;     /* true if someone is writing to the feed */
216     int is_feed;         /* true if it is a feed */
217     int readonly;        /* True if writing is prohibited to the file */
218     int conns_served;
219     int64_t bytes_served;
220     int64_t feed_max_size;      /* maximum storage size */
221     int64_t feed_write_index;   /* current write position in feed (it wraps round) */
222     int64_t feed_size;          /* current size of feed */
223     struct FFStream *next_feed;
224 } FFStream;
225
226 typedef struct FeedData {
227     long long data_count;
228     float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
229 } FeedData;
230
231 struct sockaddr_in my_http_addr;
232 struct sockaddr_in my_rtsp_addr;
233
234 char logfilename[1024];
235 HTTPContext *first_http_ctx;
236 FFStream *first_feed;   /* contains only feeds */
237 FFStream *first_stream; /* contains all streams, including feeds */
238
239 static void new_connection(int server_fd, int is_rtsp);
240 static void close_connection(HTTPContext *c);
241
242 /* HTTP handling */
243 static int handle_connection(HTTPContext *c);
244 static int http_parse_request(HTTPContext *c);
245 static int http_send_data(HTTPContext *c);
246 static void compute_stats(HTTPContext *c);
247 static int open_input_stream(HTTPContext *c, const char *info);
248 static int http_start_receive_data(HTTPContext *c);
249 static int http_receive_data(HTTPContext *c);
250
251 /* RTSP handling */
252 static int rtsp_parse_request(HTTPContext *c);
253 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
254 static void rtsp_cmd_options(HTTPContext *c, const char *url);
255 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
256 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
257 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
258 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
259
260 /* SDP handling */
261 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
262                                    struct in_addr my_ip);
263
264 /* RTP handling */
265 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
266                                        FFStream *stream, const char *session_id,
267                                        enum RTSPProtocol rtp_protocol);
268 static int rtp_new_av_stream(HTTPContext *c, 
269                              int stream_index, struct sockaddr_in *dest_addr,
270                              HTTPContext *rtsp_c);
271
272 static const char *my_program_name;
273 static const char *my_program_dir;
274
275 static int ffserver_debug;
276 static int ffserver_daemon;
277 static int no_launch;
278 static int need_to_start_children;
279
280 int nb_max_connections;
281 int nb_connections;
282
283 int max_bandwidth;
284 int current_bandwidth;
285
286 static long cur_time;           // Making this global saves on passing it around everywhere
287
288 static long gettime_ms(void)
289 {
290     struct timeval tv;
291
292     gettimeofday(&tv,NULL);
293     return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
294 }
295
296 static FILE *logfile = NULL;
297
298 static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...) 
299 {
300     va_list ap;
301     va_start(ap, fmt);
302     
303     if (logfile) {
304         vfprintf(logfile, fmt, ap);
305         fflush(logfile);
306     }
307     va_end(ap);
308 }
309
310 static char *ctime1(char *buf2)
311 {
312     time_t ti;
313     char *p;
314
315     ti = time(NULL);
316     p = ctime(&ti);
317     strcpy(buf2, p);
318     p = buf2 + strlen(p) - 1;
319     if (*p == '\n')
320         *p = '\0';
321     return buf2;
322 }
323
324 static void log_connection(HTTPContext *c)
325 {
326     char buf2[32];
327
328     if (c->suppress_log) 
329         return;
330
331     http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
332              inet_ntoa(c->from_addr.sin_addr), 
333              ctime1(buf2), c->method, c->url, 
334              c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
335 }
336
337 static void update_datarate(DataRateData *drd, int64_t count)
338 {
339     if (!drd->time1 && !drd->count1) {
340         drd->time1 = drd->time2 = cur_time;
341         drd->count1 = drd->count2 = count;
342     } else {
343         if (cur_time - drd->time2 > 5000) {
344             drd->time1 = drd->time2;
345             drd->count1 = drd->count2;
346             drd->time2 = cur_time;
347             drd->count2 = count;
348         }
349     }
350 }
351
352 /* In bytes per second */
353 static int compute_datarate(DataRateData *drd, int64_t count)
354 {
355     if (cur_time == drd->time1)
356         return 0;
357     
358     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
359 }
360
361 static int get_longterm_datarate(DataRateData *drd, int64_t count)
362 {
363     /* You get the first 3 seconds flat out */
364     if (cur_time - drd->time1 < 3000)
365         return 0;
366     return compute_datarate(drd, count);
367 }
368
369
370 static void start_children(FFStream *feed)
371 {
372     if (no_launch)
373         return;
374
375     for (; feed; feed = feed->next) {
376         if (feed->child_argv && !feed->pid) {
377             feed->pid_start = time(0);
378
379             feed->pid = fork();
380
381             if (feed->pid < 0) {
382                 fprintf(stderr, "Unable to create children\n");
383                 exit(1);
384             }
385             if (!feed->pid) {
386                 /* In child */
387                 char pathname[1024];
388                 char *slash;
389                 int i;
390
391                 for (i = 3; i < 256; i++) {
392                     close(i);
393                 }
394
395                 if (!ffserver_debug) {
396                     i = open("/dev/null", O_RDWR);
397                     if (i)
398                         dup2(i, 0);
399                     dup2(i, 1);
400                     dup2(i, 2);
401                     if (i)
402                         close(i);
403                 }
404
405                 pstrcpy(pathname, sizeof(pathname), my_program_name);
406
407                 slash = strrchr(pathname, '/');
408                 if (!slash) {
409                     slash = pathname;
410                 } else {
411                     slash++;
412                 }
413                 strcpy(slash, "ffmpeg");
414
415                 /* This is needed to make relative pathnames work */
416                 chdir(my_program_dir);
417
418                 signal(SIGPIPE, SIG_DFL);
419
420                 execvp(pathname, feed->child_argv);
421
422                 _exit(1);
423             }
424         }
425     }
426 }
427
428 /* open a listening socket */
429 static int socket_open_listen(struct sockaddr_in *my_addr)
430 {
431     int server_fd, tmp;
432
433     server_fd = socket(AF_INET,SOCK_STREAM,0);
434     if (server_fd < 0) {
435         perror ("socket");
436         return -1;
437     }
438         
439     tmp = 1;
440     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
441
442     if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
443         char bindmsg[32];
444         snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
445         perror (bindmsg);
446         close(server_fd);
447         return -1;
448     }
449   
450     if (listen (server_fd, 5) < 0) {
451         perror ("listen");
452         close(server_fd);
453         return -1;
454     }
455     fcntl(server_fd, F_SETFL, O_NONBLOCK);
456
457     return server_fd;
458 }
459
460 /* start all multicast streams */
461 static void start_multicast(void)
462 {
463     FFStream *stream;
464     char session_id[32];
465     HTTPContext *rtp_c;
466     struct sockaddr_in dest_addr;
467     int default_port, stream_index;
468
469     default_port = 6000;
470     for(stream = first_stream; stream != NULL; stream = stream->next) {
471         if (stream->is_multicast) {
472             /* open the RTP connection */
473             snprintf(session_id, sizeof(session_id), 
474                      "%08x%08x", (int)random(), (int)random());
475
476             /* choose a port if none given */
477             if (stream->multicast_port == 0) {
478                 stream->multicast_port = default_port;
479                 default_port += 100;
480             }
481
482             dest_addr.sin_family = AF_INET;
483             dest_addr.sin_addr = stream->multicast_ip;
484             dest_addr.sin_port = htons(stream->multicast_port);
485
486             rtp_c = rtp_new_connection(&dest_addr, stream, session_id, 
487                                        RTSP_PROTOCOL_RTP_UDP_MULTICAST);
488             if (!rtp_c) {
489                 continue;
490             }
491             if (open_input_stream(rtp_c, "") < 0) {
492                 fprintf(stderr, "Could not open input stream for stream '%s'\n", 
493                         stream->filename);
494                 continue;
495             }
496
497             /* open each RTP stream */
498             for(stream_index = 0; stream_index < stream->nb_streams; 
499                 stream_index++) {
500                 dest_addr.sin_port = htons(stream->multicast_port + 
501                                            2 * stream_index);
502                 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
503                     fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n", 
504                             stream->filename, stream_index);
505                     exit(1);
506                 }
507             }
508
509             /* change state to send data */
510             rtp_c->state = HTTPSTATE_SEND_DATA;
511         }
512     }
513 }
514
515 /* main loop of the http server */
516 static int http_server(void)
517 {
518     int server_fd, ret, rtsp_server_fd, delay, delay1;
519     struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
520     HTTPContext *c, *c_next;
521
522     server_fd = socket_open_listen(&my_http_addr);
523     if (server_fd < 0)
524         return -1;
525
526     rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
527     if (rtsp_server_fd < 0)
528         return -1;
529     
530     http_log("ffserver started.\n");
531
532     start_children(first_feed);
533
534     first_http_ctx = NULL;
535     nb_connections = 0;
536
537     start_multicast();
538
539     for(;;) {
540         poll_entry = poll_table;
541         poll_entry->fd = server_fd;
542         poll_entry->events = POLLIN;
543         poll_entry++;
544
545         poll_entry->fd = rtsp_server_fd;
546         poll_entry->events = POLLIN;
547         poll_entry++;
548
549         /* wait for events on each HTTP handle */
550         c = first_http_ctx;
551         delay = 1000;
552         while (c != NULL) {
553             int fd;
554             fd = c->fd;
555             switch(c->state) {
556             case HTTPSTATE_SEND_HEADER:
557             case RTSPSTATE_SEND_REPLY:
558             case RTSPSTATE_SEND_PACKET:
559                 c->poll_entry = poll_entry;
560                 poll_entry->fd = fd;
561                 poll_entry->events = POLLOUT;
562                 poll_entry++;
563                 break;
564             case HTTPSTATE_SEND_DATA_HEADER:
565             case HTTPSTATE_SEND_DATA:
566             case HTTPSTATE_SEND_DATA_TRAILER:
567                 if (!c->is_packetized) {
568                     /* for TCP, we output as much as we can (may need to put a limit) */
569                     c->poll_entry = poll_entry;
570                     poll_entry->fd = fd;
571                     poll_entry->events = POLLOUT;
572                     poll_entry++;
573                 } else {
574                     /* when ffserver is doing the timing, we work by
575                        looking at which packet need to be sent every
576                        10 ms */
577                     delay1 = 10; /* one tick wait XXX: 10 ms assumed */
578                     if (delay1 < delay)
579                         delay = delay1;
580                 }
581                 break;
582             case HTTPSTATE_WAIT_REQUEST:
583             case HTTPSTATE_RECEIVE_DATA:
584             case HTTPSTATE_WAIT_FEED:
585             case RTSPSTATE_WAIT_REQUEST:
586                 /* need to catch errors */
587                 c->poll_entry = poll_entry;
588                 poll_entry->fd = fd;
589                 poll_entry->events = POLLIN;/* Maybe this will work */
590                 poll_entry++;
591                 break;
592             default:
593                 c->poll_entry = NULL;
594                 break;
595             }
596             c = c->next;
597         }
598
599         /* wait for an event on one connection. We poll at least every
600            second to handle timeouts */
601         do {
602             ret = poll(poll_table, poll_entry - poll_table, delay);
603             if (ret < 0 && errno != EAGAIN && errno != EINTR)
604                 return -1;
605         } while (ret <= 0);
606         
607         cur_time = gettime_ms();
608
609         if (need_to_start_children) {
610             need_to_start_children = 0;
611             start_children(first_feed);
612         }
613
614         /* now handle the events */
615         for(c = first_http_ctx; c != NULL; c = c_next) {
616             c_next = c->next;
617             if (handle_connection(c) < 0) {
618                 /* close and free the connection */
619                 log_connection(c);
620                 close_connection(c);
621             }
622         }
623
624         poll_entry = poll_table;
625         /* new HTTP connection request ? */
626         if (poll_entry->revents & POLLIN) {
627             new_connection(server_fd, 0);
628         }
629         poll_entry++;
630         /* new RTSP connection request ? */
631         if (poll_entry->revents & POLLIN) {
632             new_connection(rtsp_server_fd, 1);
633         }
634     }
635 }
636
637 /* start waiting for a new HTTP/RTSP request */
638 static void start_wait_request(HTTPContext *c, int is_rtsp)
639 {
640     c->buffer_ptr = c->buffer;
641     c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
642
643     if (is_rtsp) {
644         c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
645         c->state = RTSPSTATE_WAIT_REQUEST;
646     } else {
647         c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
648         c->state = HTTPSTATE_WAIT_REQUEST;
649     }
650 }
651
652 static void new_connection(int server_fd, int is_rtsp)
653 {
654     struct sockaddr_in from_addr;
655     int fd, len;
656     HTTPContext *c = NULL;
657
658     len = sizeof(from_addr);
659     fd = accept(server_fd, (struct sockaddr *)&from_addr, 
660                 &len);
661     if (fd < 0)
662         return;
663     fcntl(fd, F_SETFL, O_NONBLOCK);
664
665     /* XXX: should output a warning page when coming
666        close to the connection limit */
667     if (nb_connections >= nb_max_connections)
668         goto fail;
669     
670     /* add a new connection */
671     c = av_mallocz(sizeof(HTTPContext));
672     if (!c)
673         goto fail;
674     
675     c->fd = fd;
676     c->poll_entry = NULL;
677     c->from_addr = from_addr;
678     c->buffer_size = IOBUFFER_INIT_SIZE;
679     c->buffer = av_malloc(c->buffer_size);
680     if (!c->buffer)
681         goto fail;
682
683     c->next = first_http_ctx;
684     first_http_ctx = c;
685     nb_connections++;
686     
687     start_wait_request(c, is_rtsp);
688
689     return;
690
691  fail:
692     if (c) {
693         av_free(c->buffer);
694         av_free(c);
695     }
696     close(fd);
697 }
698
699 static void close_connection(HTTPContext *c)
700 {
701     HTTPContext **cp, *c1;
702     int i, nb_streams;
703     AVFormatContext *ctx;
704     URLContext *h;
705     AVStream *st;
706
707     /* remove connection from list */
708     cp = &first_http_ctx;
709     while ((*cp) != NULL) {
710         c1 = *cp;
711         if (c1 == c) {
712             *cp = c->next;
713         } else {
714             cp = &c1->next;
715         }
716     }
717
718     /* remove references, if any (XXX: do it faster) */
719     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
720         if (c1->rtsp_c == c)
721             c1->rtsp_c = NULL;
722     }
723
724     /* remove connection associated resources */
725     if (c->fd >= 0)
726         close(c->fd);
727     if (c->fmt_in) {
728         /* close each frame parser */
729         for(i=0;i<c->fmt_in->nb_streams;i++) {
730             st = c->fmt_in->streams[i];
731             if (st->codec.codec) {
732                 avcodec_close(&st->codec);
733             }
734         }
735         av_close_input_file(c->fmt_in);
736     }
737
738     /* free RTP output streams if any */
739     nb_streams = 0;
740     if (c->stream) 
741         nb_streams = c->stream->nb_streams;
742     
743     for(i=0;i<nb_streams;i++) {
744         ctx = c->rtp_ctx[i];
745         if (ctx) {
746             av_write_trailer(ctx);
747             av_free(ctx);
748         }
749         h = c->rtp_handles[i];
750         if (h) {
751             url_close(h);
752         }
753     }
754     
755     ctx = &c->fmt_ctx;
756
757     if (!c->last_packet_sent) {
758         if (ctx->oformat) {
759             /* prepare header */
760             if (url_open_dyn_buf(&ctx->pb) >= 0) {
761                 av_write_trailer(ctx);
762                 url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
763             }
764         }
765     }
766
767     for(i=0; i<ctx->nb_streams; i++) 
768         av_free(ctx->streams[i]) ; 
769
770     if (c->stream)
771         current_bandwidth -= c->stream->bandwidth;
772     av_freep(&c->pb_buffer);
773     av_freep(&c->packet_buffer);
774     av_free(c->buffer);
775     av_free(c);
776     nb_connections--;
777 }
778
779 static int handle_connection(HTTPContext *c)
780 {
781     int len, ret;
782     
783     switch(c->state) {
784     case HTTPSTATE_WAIT_REQUEST:
785     case RTSPSTATE_WAIT_REQUEST:
786         /* timeout ? */
787         if ((c->timeout - cur_time) < 0)
788             return -1;
789         if (c->poll_entry->revents & (POLLERR | POLLHUP))
790             return -1;
791
792         /* no need to read if no events */
793         if (!(c->poll_entry->revents & POLLIN))
794             return 0;
795         /* read the data */
796     read_loop:
797         len = read(c->fd, c->buffer_ptr, 1);
798         if (len < 0) {
799             if (errno != EAGAIN && errno != EINTR)
800                 return -1;
801         } else if (len == 0) {
802             return -1;
803         } else {
804             /* search for end of request. */
805             uint8_t *ptr;
806             c->buffer_ptr += len;
807             ptr = c->buffer_ptr;
808             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
809                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
810                 /* request found : parse it and reply */
811                 if (c->state == HTTPSTATE_WAIT_REQUEST) {
812                     ret = http_parse_request(c);
813                 } else {
814                     ret = rtsp_parse_request(c);
815                 }
816                 if (ret < 0)
817                     return -1;
818             } else if (ptr >= c->buffer_end) {
819                 /* request too long: cannot do anything */
820                 return -1;
821             } else goto read_loop;
822         }
823         break;
824
825     case HTTPSTATE_SEND_HEADER:
826         if (c->poll_entry->revents & (POLLERR | POLLHUP))
827             return -1;
828
829         /* no need to write if no events */
830         if (!(c->poll_entry->revents & POLLOUT))
831             return 0;
832         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
833         if (len < 0) {
834             if (errno != EAGAIN && errno != EINTR) {
835                 /* error : close connection */
836                 av_freep(&c->pb_buffer);
837                 return -1;
838             }
839         } else {
840             c->buffer_ptr += len;
841             if (c->stream)
842                 c->stream->bytes_served += len;
843             c->data_count += len;
844             if (c->buffer_ptr >= c->buffer_end) {
845                 av_freep(&c->pb_buffer);
846                 /* if error, exit */
847                 if (c->http_error) {
848                     return -1;
849                 }
850                 /* all the buffer was sent : synchronize to the incoming stream */
851                 c->state = HTTPSTATE_SEND_DATA_HEADER;
852                 c->buffer_ptr = c->buffer_end = c->buffer;
853             }
854         }
855         break;
856
857     case HTTPSTATE_SEND_DATA:
858     case HTTPSTATE_SEND_DATA_HEADER:
859     case HTTPSTATE_SEND_DATA_TRAILER:
860         /* for packetized output, we consider we can always write (the
861            input streams sets the speed). It may be better to verify
862            that we do not rely too much on the kernel queues */
863         if (!c->is_packetized) {
864             if (c->poll_entry->revents & (POLLERR | POLLHUP))
865                 return -1;
866             
867             /* no need to read if no events */
868             if (!(c->poll_entry->revents & POLLOUT))
869                 return 0;
870         }
871         if (http_send_data(c) < 0)
872             return -1;
873         break;
874     case HTTPSTATE_RECEIVE_DATA:
875         /* no need to read if no events */
876         if (c->poll_entry->revents & (POLLERR | POLLHUP))
877             return -1;
878         if (!(c->poll_entry->revents & POLLIN))
879             return 0;
880         if (http_receive_data(c) < 0)
881             return -1;
882         break;
883     case HTTPSTATE_WAIT_FEED:
884         /* no need to read if no events */
885         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
886             return -1;
887
888         /* nothing to do, we'll be waken up by incoming feed packets */
889         break;
890
891     case RTSPSTATE_SEND_REPLY:
892         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
893             av_freep(&c->pb_buffer);
894             return -1;
895         }
896         /* no need to write if no events */
897         if (!(c->poll_entry->revents & POLLOUT))
898             return 0;
899         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
900         if (len < 0) {
901             if (errno != EAGAIN && errno != EINTR) {
902                 /* error : close connection */
903                 av_freep(&c->pb_buffer);
904                 return -1;
905             }
906         } else {
907             c->buffer_ptr += len;
908             c->data_count += len;
909             if (c->buffer_ptr >= c->buffer_end) {
910                 /* all the buffer was sent : wait for a new request */
911                 av_freep(&c->pb_buffer);
912                 start_wait_request(c, 1);
913             }
914         }
915         break;
916     case RTSPSTATE_SEND_PACKET:
917         if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
918             av_freep(&c->packet_buffer);
919             return -1;
920         }
921         /* no need to write if no events */
922         if (!(c->poll_entry->revents & POLLOUT))
923             return 0;
924         len = write(c->fd, c->packet_buffer_ptr, 
925                     c->packet_buffer_end - c->packet_buffer_ptr);
926         if (len < 0) {
927             if (errno != EAGAIN && errno != EINTR) {
928                 /* error : close connection */
929                 av_freep(&c->packet_buffer);
930                 return -1;
931             }
932         } else {
933             c->packet_buffer_ptr += len;
934             if (c->packet_buffer_ptr >= c->packet_buffer_end) {
935                 /* all the buffer was sent : wait for a new request */
936                 av_freep(&c->packet_buffer);
937                 c->state = RTSPSTATE_WAIT_REQUEST;
938             }
939         }
940         break;
941     case HTTPSTATE_READY:
942         /* nothing to do */
943         break;
944     default:
945         return -1;
946     }
947     return 0;
948 }
949
950 static int extract_rates(char *rates, int ratelen, const char *request)
951 {
952     const char *p;
953
954     for (p = request; *p && *p != '\r' && *p != '\n'; ) {
955         if (strncasecmp(p, "Pragma:", 7) == 0) {
956             const char *q = p + 7;
957
958             while (*q && *q != '\n' && isspace(*q))
959                 q++;
960
961             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
962                 int stream_no;
963                 int rate_no;
964
965                 q += 20;
966
967                 memset(rates, 0xff, ratelen);
968
969                 while (1) {
970                     while (*q && *q != '\n' && *q != ':')
971                         q++;
972
973                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
974                         break;
975                     }
976                     stream_no--;
977                     if (stream_no < ratelen && stream_no >= 0) {
978                         rates[stream_no] = rate_no;
979                     }
980
981                     while (*q && *q != '\n' && !isspace(*q))
982                         q++;
983                 }
984
985                 return 1;
986             }
987         }
988         p = strchr(p, '\n');
989         if (!p)
990             break;
991
992         p++;
993     }
994
995     return 0;
996 }
997
998 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
999 {
1000     int i;
1001     int best_bitrate = 100000000;
1002     int best = -1;
1003
1004     for (i = 0; i < feed->nb_streams; i++) {
1005         AVCodecContext *feed_codec = &feed->streams[i]->codec;
1006
1007         if (feed_codec->codec_id != codec->codec_id ||
1008             feed_codec->sample_rate != codec->sample_rate ||
1009             feed_codec->width != codec->width ||
1010             feed_codec->height != codec->height) {
1011             continue;
1012         }
1013
1014         /* Potential stream */
1015
1016         /* We want the fastest stream less than bit_rate, or the slowest 
1017          * faster than bit_rate
1018          */
1019
1020         if (feed_codec->bit_rate <= bit_rate) {
1021             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1022                 best_bitrate = feed_codec->bit_rate;
1023                 best = i;
1024             }
1025         } else {
1026             if (feed_codec->bit_rate < best_bitrate) {
1027                 best_bitrate = feed_codec->bit_rate;
1028                 best = i;
1029             }
1030         }
1031     }
1032
1033     return best;
1034 }
1035
1036 static int modify_current_stream(HTTPContext *c, char *rates)
1037 {
1038     int i;
1039     FFStream *req = c->stream;
1040     int action_required = 0;
1041
1042     /* Not much we can do for a feed */
1043     if (!req->feed)
1044         return 0;
1045
1046     for (i = 0; i < req->nb_streams; i++) {
1047         AVCodecContext *codec = &req->streams[i]->codec;
1048
1049         switch(rates[i]) {
1050             case 0:
1051                 c->switch_feed_streams[i] = req->feed_streams[i];
1052                 break;
1053             case 1:
1054                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1055                 break;
1056             case 2:
1057                 /* Wants off or slow */
1058                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1059 #ifdef WANTS_OFF
1060                 /* This doesn't work well when it turns off the only stream! */
1061                 c->switch_feed_streams[i] = -2;
1062                 c->feed_streams[i] = -2;
1063 #endif
1064                 break;
1065         }
1066
1067         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1068             action_required = 1;
1069     }
1070
1071     return action_required;
1072 }
1073
1074
1075 static void do_switch_stream(HTTPContext *c, int i)
1076 {
1077     if (c->switch_feed_streams[i] >= 0) {
1078 #ifdef PHILIP        
1079         c->feed_streams[i] = c->switch_feed_streams[i];
1080 #endif
1081
1082         /* Now update the stream */
1083     }
1084     c->switch_feed_streams[i] = -1;
1085 }
1086
1087 /* XXX: factorize in utils.c ? */
1088 /* XXX: take care with different space meaning */
1089 static void skip_spaces(const char **pp)
1090 {
1091     const char *p;
1092     p = *pp;
1093     while (*p == ' ' || *p == '\t')
1094         p++;
1095     *pp = p;
1096 }
1097
1098 static void get_word(char *buf, int buf_size, const char **pp)
1099 {
1100     const char *p;
1101     char *q;
1102
1103     p = *pp;
1104     skip_spaces(&p);
1105     q = buf;
1106     while (!isspace(*p) && *p != '\0') {
1107         if ((q - buf) < buf_size - 1)
1108             *q++ = *p;
1109         p++;
1110     }
1111     if (buf_size > 0)
1112         *q = '\0';
1113     *pp = p;
1114 }
1115
1116 static int validate_acl(FFStream *stream, HTTPContext *c)
1117 {
1118     enum IPAddressAction last_action = IP_DENY;
1119     IPAddressACL *acl;
1120     struct in_addr *src = &c->from_addr.sin_addr;
1121     unsigned long src_addr = ntohl(src->s_addr);
1122
1123     for (acl = stream->acl; acl; acl = acl->next) {
1124         if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) {
1125             return (acl->action == IP_ALLOW) ? 1 : 0;
1126         }
1127         last_action = acl->action;
1128     }
1129
1130     /* Nothing matched, so return not the last action */
1131     return (last_action == IP_DENY) ? 1 : 0;
1132 }
1133
1134 /* compute the real filename of a file by matching it without its
1135    extensions to all the stream filenames */
1136 static void compute_real_filename(char *filename, int max_size)
1137 {
1138     char file1[1024];
1139     char file2[1024];
1140     char *p;
1141     FFStream *stream;
1142
1143     /* compute filename by matching without the file extensions */
1144     pstrcpy(file1, sizeof(file1), filename);
1145     p = strrchr(file1, '.');
1146     if (p)
1147         *p = '\0';
1148     for(stream = first_stream; stream != NULL; stream = stream->next) {
1149         pstrcpy(file2, sizeof(file2), stream->filename);
1150         p = strrchr(file2, '.');
1151         if (p)
1152             *p = '\0';
1153         if (!strcmp(file1, file2)) {
1154             pstrcpy(filename, max_size, stream->filename);
1155             break;
1156         }
1157     }
1158 }
1159
1160 enum RedirType {
1161     REDIR_NONE,
1162     REDIR_ASX,
1163     REDIR_RAM,
1164     REDIR_ASF,
1165     REDIR_RTSP,
1166     REDIR_SDP,
1167 };
1168
1169 /* parse http request and prepare header */
1170 static int http_parse_request(HTTPContext *c)
1171 {
1172     char *p;
1173     int post;
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         post = 0;
1192     else if (!strcmp(cmd, "POST"))
1193         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 (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
1296         current_bandwidth += stream->bandwidth;
1297     }
1298     
1299     if (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 (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             c->fmt_ctx.streams[i] = st;
2004             /* if file or feed, then just take streams from FFStream struct */
2005             if (!c->stream->feed || 
2006                 c->stream->feed == c->stream)
2007                 src = c->stream->streams[i];
2008             else
2009                 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2010
2011             *st = *src;
2012             st->priv_data = 0;
2013             st->codec.frame_number = 0; /* XXX: should be done in
2014                                            AVStream, not in codec */
2015             /* I'm pretty sure that this is not correct...
2016              * However, without it, we crash
2017              */
2018             st->codec.coded_frame = &dummy_frame;
2019         }
2020         c->got_key_frame = 0;
2021
2022         /* prepare header and save header data in a stream */
2023         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2024             /* XXX: potential leak */
2025             return -1;
2026         }
2027         c->fmt_ctx.pb.is_streamed = 1;
2028
2029         av_set_parameters(&c->fmt_ctx, NULL);
2030         av_write_header(&c->fmt_ctx);
2031
2032         len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2033         c->buffer_ptr = c->pb_buffer;
2034         c->buffer_end = c->pb_buffer + len;
2035
2036         c->state = HTTPSTATE_SEND_DATA;
2037         c->last_packet_sent = 0;
2038         break;
2039     case HTTPSTATE_SEND_DATA:
2040         /* find a new packet */
2041         {
2042             AVPacket pkt;
2043             
2044             /* read a packet from the input stream */
2045             if (c->stream->feed) {
2046                 ffm_set_write_index(c->fmt_in, 
2047                                     c->stream->feed->feed_write_index,
2048                                     c->stream->feed->feed_size);
2049             }
2050
2051             if (c->stream->max_time && 
2052                 c->stream->max_time + c->start_time - cur_time < 0) {
2053                 /* We have timed out */
2054                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2055             } else {
2056             redo:
2057                 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2058                     if (c->stream->feed && c->stream->feed->feed_opened) {
2059                         /* if coming from feed, it means we reached the end of the
2060                            ffm file, so must wait for more data */
2061                         c->state = HTTPSTATE_WAIT_FEED;
2062                         return 1; /* state changed */
2063                     } else {
2064                         if (c->stream->loop) {
2065                             av_close_input_file(c->fmt_in);
2066                             c->fmt_in = NULL;
2067                             if (open_input_stream(c, "") < 0)
2068                                 goto no_loop;
2069                             goto redo;
2070                         } else {
2071                         no_loop:
2072                             /* must send trailer now because eof or error */
2073                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2074                         }
2075                     }
2076                 } else {
2077                     /* update first pts if needed */
2078                     if (c->first_pts == AV_NOPTS_VALUE) {
2079                         c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2080                         c->start_time = cur_time;
2081                     }
2082                     /* send it to the appropriate stream */
2083                     if (c->stream->feed) {
2084                         /* if coming from a feed, select the right stream */
2085                         if (c->switch_pending) {
2086                             c->switch_pending = 0;
2087                             for(i=0;i<c->stream->nb_streams;i++) {
2088                                 if (c->switch_feed_streams[i] == pkt.stream_index) {
2089                                     if (pkt.flags & PKT_FLAG_KEY) {
2090                                         do_switch_stream(c, i);
2091                                     }
2092                                 }
2093                                 if (c->switch_feed_streams[i] >= 0) {
2094                                     c->switch_pending = 1;
2095                                 }
2096                             }
2097                         }
2098                         for(i=0;i<c->stream->nb_streams;i++) {
2099                             if (c->feed_streams[i] == pkt.stream_index) {
2100                                 pkt.stream_index = i;
2101                                 if (pkt.flags & PKT_FLAG_KEY) {
2102                                     c->got_key_frame |= 1 << i;
2103                                 }
2104                                 /* See if we have all the key frames, then 
2105                                  * we start to send. This logic is not quite
2106                                  * right, but it works for the case of a 
2107                                  * single video stream with one or more
2108                                  * audio streams (for which every frame is 
2109                                  * typically a key frame). 
2110                                  */
2111                                 if (!c->stream->send_on_key || 
2112                                     ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2113                                     goto send_it;
2114                                 }
2115                             }
2116                         }
2117                     } else {
2118                         AVCodecContext *codec;
2119                         
2120                     send_it:
2121                         /* specific handling for RTP: we use several
2122                            output stream (one for each RTP
2123                            connection). XXX: need more abstract handling */
2124                         if (c->is_packetized) {
2125                             AVStream *st;
2126                             /* compute send time and duration */
2127                             st = c->fmt_in->streams[pkt.stream_index];
2128                             c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2129                             if (st->start_time != AV_NOPTS_VALUE)
2130                                 c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2131                             c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2132 #if 0
2133                             printf("index=%d pts=%0.3f duration=%0.6f\n",
2134                                    pkt.stream_index,
2135                                    (double)c->cur_pts / 
2136                                    AV_TIME_BASE,
2137                                    (double)c->cur_frame_duration / 
2138                                    AV_TIME_BASE);
2139 #endif
2140                             /* find RTP context */
2141                             c->packet_stream_index = pkt.stream_index;
2142                             ctx = c->rtp_ctx[c->packet_stream_index];
2143                             if(!ctx) {
2144                               av_free_packet(&pkt);
2145                               break;
2146                             }
2147                             codec = &ctx->streams[0]->codec;
2148                             /* only one stream per RTP connection */
2149                             pkt.stream_index = 0;
2150                         } else {
2151                             ctx = &c->fmt_ctx;
2152                             /* Fudge here */
2153                             codec = &ctx->streams[pkt.stream_index]->codec;
2154                         }
2155                         
2156                         codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2157                         if (c->is_packetized) {
2158                             int max_packet_size;
2159                             if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2160                                 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2161                             else
2162                                 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2163                             ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2164                         } else {
2165                             ret = url_open_dyn_buf(&ctx->pb);
2166                         }
2167                         if (ret < 0) {
2168                             /* XXX: potential leak */
2169                             return -1;
2170                         }
2171                         if (av_write_frame(ctx, &pkt)) {
2172                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2173                         }
2174                         
2175                         len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2176                         c->cur_frame_bytes = len;
2177                         c->buffer_ptr = c->pb_buffer;
2178                         c->buffer_end = c->pb_buffer + len;
2179                         
2180                         codec->frame_number++;
2181                         if (len == 0)
2182                             goto redo;
2183                     }
2184                     av_free_packet(&pkt);
2185                 }
2186             }
2187         }
2188         break;
2189     default:
2190     case HTTPSTATE_SEND_DATA_TRAILER:
2191         /* last packet test ? */
2192         if (c->last_packet_sent || c->is_packetized)
2193             return -1;
2194         ctx = &c->fmt_ctx;
2195         /* prepare header */
2196         if (url_open_dyn_buf(&ctx->pb) < 0) {
2197             /* XXX: potential leak */
2198             return -1;
2199         }
2200         av_write_trailer(ctx);
2201         len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2202         c->buffer_ptr = c->pb_buffer;
2203         c->buffer_end = c->pb_buffer + len;
2204
2205         c->last_packet_sent = 1;
2206         break;
2207     }
2208     return 0;
2209 }
2210
2211 /* in bit/s */
2212 #define SHORT_TERM_BANDWIDTH 8000000
2213
2214 /* should convert the format at the same time */
2215 /* send data starting at c->buffer_ptr to the output connection
2216    (either UDP or TCP connection) */
2217 static int http_send_data(HTTPContext *c)
2218 {
2219     int len, ret;
2220
2221     for(;;) {
2222         if (c->buffer_ptr >= c->buffer_end) {
2223             ret = http_prepare_data(c);
2224             if (ret < 0)
2225                 return -1;
2226             else if (ret != 0) {
2227                 /* state change requested */
2228                 break;
2229             }
2230         } else {
2231             if (c->is_packetized) {
2232                 /* RTP data output */
2233                 len = c->buffer_end - c->buffer_ptr;
2234                 if (len < 4) {
2235                     /* fail safe - should never happen */
2236                 fail1:
2237                     c->buffer_ptr = c->buffer_end;
2238                     return 0;
2239                 }
2240                 len = (c->buffer_ptr[0] << 24) |
2241                     (c->buffer_ptr[1] << 16) |
2242                     (c->buffer_ptr[2] << 8) |
2243                     (c->buffer_ptr[3]);
2244                 if (len > (c->buffer_end - c->buffer_ptr))
2245                     goto fail1;
2246                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2247                     /* nothing to send yet: we can wait */
2248                     return 0;
2249                 }
2250
2251                 c->data_count += len;
2252                 update_datarate(&c->datarate, c->data_count);
2253                 if (c->stream)
2254                     c->stream->bytes_served += len;
2255
2256                 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2257                     /* RTP packets are sent inside the RTSP TCP connection */
2258                     ByteIOContext pb1, *pb = &pb1;
2259                     int interleaved_index, size;
2260                     uint8_t header[4];
2261                     HTTPContext *rtsp_c;
2262                     
2263                     rtsp_c = c->rtsp_c;
2264                     /* if no RTSP connection left, error */
2265                     if (!rtsp_c)
2266                         return -1;
2267                     /* if already sending something, then wait. */
2268                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) {
2269                         break;
2270                     }
2271                     if (url_open_dyn_buf(pb) < 0)
2272                         goto fail1;
2273                     interleaved_index = c->packet_stream_index * 2;
2274                     /* RTCP packets are sent at odd indexes */
2275                     if (c->buffer_ptr[1] == 200)
2276                         interleaved_index++;
2277                     /* write RTSP TCP header */
2278                     header[0] = '$';
2279                     header[1] = interleaved_index;
2280                     header[2] = len >> 8;
2281                     header[3] = len;
2282                     put_buffer(pb, header, 4);
2283                     /* write RTP packet data */
2284                     c->buffer_ptr += 4;
2285                     put_buffer(pb, c->buffer_ptr, len);
2286                     size = url_close_dyn_buf(pb, &c->packet_buffer);
2287                     /* prepare asynchronous TCP sending */
2288                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
2289                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
2290                     c->buffer_ptr += len;
2291                     
2292                     /* send everything we can NOW */
2293                     len = write(rtsp_c->fd, rtsp_c->packet_buffer_ptr, 
2294                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr);
2295                     if (len > 0) {
2296                         rtsp_c->packet_buffer_ptr += len;
2297                     }
2298                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2299                         /* if we could not send all the data, we will
2300                            send it later, so a new state is needed to
2301                            "lock" the RTSP TCP connection */
2302                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
2303                         break;
2304                     } else {
2305                         /* all data has been sent */
2306                         av_freep(&c->packet_buffer);
2307                     }
2308                 } else {
2309                     /* send RTP packet directly in UDP */
2310                     c->buffer_ptr += 4;
2311                     url_write(c->rtp_handles[c->packet_stream_index], 
2312                               c->buffer_ptr, len);
2313                     c->buffer_ptr += len;
2314                     /* here we continue as we can send several packets per 10 ms slot */
2315                 }
2316             } else {
2317                 /* TCP data output */
2318                 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2319                 if (len < 0) {
2320                     if (errno != EAGAIN && errno != EINTR) {
2321                         /* error : close connection */
2322                         return -1;
2323                     } else {
2324                         return 0;
2325                     }
2326                 } else {
2327                     c->buffer_ptr += len;
2328                 }
2329                 c->data_count += len;
2330                 update_datarate(&c->datarate, c->data_count);
2331                 if (c->stream)
2332                     c->stream->bytes_served += len;
2333                 break;
2334             }
2335         }
2336     } /* for(;;) */
2337     return 0;
2338 }
2339
2340 static int http_start_receive_data(HTTPContext *c)
2341 {
2342     int fd;
2343
2344     if (c->stream->feed_opened)
2345         return -1;
2346
2347     /* Don't permit writing to this one */
2348     if (c->stream->readonly)
2349         return -1;
2350
2351     /* open feed */
2352     fd = open(c->stream->feed_filename, O_RDWR);
2353     if (fd < 0)
2354         return -1;
2355     c->feed_fd = fd;
2356     
2357     c->stream->feed_write_index = ffm_read_write_index(fd);
2358     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2359     lseek(fd, 0, SEEK_SET);
2360
2361     /* init buffer input */
2362     c->buffer_ptr = c->buffer;
2363     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2364     c->stream->feed_opened = 1;
2365     return 0;
2366 }
2367     
2368 static int http_receive_data(HTTPContext *c)
2369 {
2370     HTTPContext *c1;
2371
2372     if (c->buffer_end > c->buffer_ptr) {
2373         int len;
2374
2375         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2376         if (len < 0) {
2377             if (errno != EAGAIN && errno != EINTR) {
2378                 /* error : close connection */
2379                 goto fail;
2380             }
2381         } else if (len == 0) {
2382             /* end of connection : close it */
2383             goto fail;
2384         } else {
2385             c->buffer_ptr += len;
2386             c->data_count += len;
2387             update_datarate(&c->datarate, c->data_count);
2388         }
2389     }
2390
2391     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2392         if (c->buffer[0] != 'f' ||
2393             c->buffer[1] != 'm') {
2394             http_log("Feed stream has become desynchronized -- disconnecting\n");
2395             goto fail;
2396         }
2397     }
2398
2399     if (c->buffer_ptr >= c->buffer_end) {
2400         FFStream *feed = c->stream;
2401         /* a packet has been received : write it in the store, except
2402            if header */
2403         if (c->data_count > FFM_PACKET_SIZE) {
2404             
2405             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2406             /* XXX: use llseek or url_seek */
2407             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2408             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2409             
2410             feed->feed_write_index += FFM_PACKET_SIZE;
2411             /* update file size */
2412             if (feed->feed_write_index > c->stream->feed_size)
2413                 feed->feed_size = feed->feed_write_index;
2414
2415             /* handle wrap around if max file size reached */
2416             if (feed->feed_write_index >= c->stream->feed_max_size)
2417                 feed->feed_write_index = FFM_PACKET_SIZE;
2418
2419             /* write index */
2420             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2421
2422             /* wake up any waiting connections */
2423             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2424                 if (c1->state == HTTPSTATE_WAIT_FEED && 
2425                     c1->stream->feed == c->stream->feed) {
2426                     c1->state = HTTPSTATE_SEND_DATA;
2427                 }
2428             }
2429         } else {
2430             /* We have a header in our hands that contains useful data */
2431             AVFormatContext s;
2432             AVInputFormat *fmt_in;
2433             ByteIOContext *pb = &s.pb;
2434             int i;
2435
2436             memset(&s, 0, sizeof(s));
2437
2438             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2439             pb->buf_end = c->buffer_end;        /* ?? */
2440             pb->is_streamed = 1;
2441
2442             /* use feed output format name to find corresponding input format */
2443             fmt_in = av_find_input_format(feed->fmt->name);
2444             if (!fmt_in)
2445                 goto fail;
2446
2447             if (fmt_in->priv_data_size > 0) {
2448                 s.priv_data = av_mallocz(fmt_in->priv_data_size);
2449                 if (!s.priv_data)
2450                     goto fail;
2451             } else
2452                 s.priv_data = NULL;
2453
2454             if (fmt_in->read_header(&s, 0) < 0) {
2455                 av_freep(&s.priv_data);
2456                 goto fail;
2457             }
2458
2459             /* Now we have the actual streams */
2460             if (s.nb_streams != feed->nb_streams) {
2461                 av_freep(&s.priv_data);
2462                 goto fail;
2463             }
2464             for (i = 0; i < s.nb_streams; i++) {
2465                 memcpy(&feed->streams[i]->codec, 
2466                        &s.streams[i]->codec, sizeof(AVCodecContext));
2467             } 
2468             av_freep(&s.priv_data);
2469         }
2470         c->buffer_ptr = c->buffer;
2471     }
2472
2473     return 0;
2474  fail:
2475     c->stream->feed_opened = 0;
2476     close(c->feed_fd);
2477     return -1;
2478 }
2479
2480 /********************************************************************/
2481 /* RTSP handling */
2482
2483 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2484 {
2485     const char *str;
2486     time_t ti;
2487     char *p;
2488     char buf2[32];
2489
2490     switch(error_number) {
2491 #define DEF(n, c, s) case c: str = s; break; 
2492 #include "rtspcodes.h"
2493 #undef DEF
2494     default:
2495         str = "Unknown Error";
2496         break;
2497     }
2498      
2499     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2500     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2501
2502     /* output GMT time */
2503     ti = time(NULL);
2504     p = ctime(&ti);
2505     strcpy(buf2, p);
2506     p = buf2 + strlen(p) - 1;
2507     if (*p == '\n')
2508         *p = '\0';
2509     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2510 }
2511
2512 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2513 {
2514     rtsp_reply_header(c, error_number);
2515     url_fprintf(c->pb, "\r\n");
2516 }
2517
2518 static int rtsp_parse_request(HTTPContext *c)
2519 {
2520     const char *p, *p1, *p2;
2521     char cmd[32];
2522     char url[1024];
2523     char protocol[32];
2524     char line[1024];
2525     ByteIOContext pb1;
2526     int len;
2527     RTSPHeader header1, *header = &header1;
2528     
2529     c->buffer_ptr[0] = '\0';
2530     p = c->buffer;
2531     
2532     get_word(cmd, sizeof(cmd), &p);
2533     get_word(url, sizeof(url), &p);
2534     get_word(protocol, sizeof(protocol), &p);
2535
2536     pstrcpy(c->method, sizeof(c->method), cmd);
2537     pstrcpy(c->url, sizeof(c->url), url);
2538     pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2539
2540     c->pb = &pb1;
2541     if (url_open_dyn_buf(c->pb) < 0) {
2542         /* XXX: cannot do more */
2543         c->pb = NULL; /* safety */
2544         return -1;
2545     }
2546
2547     /* check version name */
2548     if (strcmp(protocol, "RTSP/1.0") != 0) {
2549         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2550         goto the_end;
2551     }
2552
2553     /* parse each header line */
2554     memset(header, 0, sizeof(RTSPHeader));
2555     /* skip to next line */
2556     while (*p != '\n' && *p != '\0')
2557         p++;
2558     if (*p == '\n')
2559         p++;
2560     while (*p != '\0') {
2561         p1 = strchr(p, '\n');
2562         if (!p1)
2563             break;
2564         p2 = p1;
2565         if (p2 > p && p2[-1] == '\r')
2566             p2--;
2567         /* skip empty line */
2568         if (p2 == p)
2569             break;
2570         len = p2 - p;
2571         if (len > sizeof(line) - 1)
2572             len = sizeof(line) - 1;
2573         memcpy(line, p, len);
2574         line[len] = '\0';
2575         rtsp_parse_line(header, line);
2576         p = p1 + 1;
2577     }
2578
2579     /* handle sequence number */
2580     c->seq = header->seq;
2581
2582     if (!strcmp(cmd, "DESCRIBE")) {
2583         rtsp_cmd_describe(c, url);
2584     } else if (!strcmp(cmd, "OPTIONS")) {
2585         rtsp_cmd_options(c, url);
2586     } else if (!strcmp(cmd, "SETUP")) {
2587         rtsp_cmd_setup(c, url, header);
2588     } else if (!strcmp(cmd, "PLAY")) {
2589         rtsp_cmd_play(c, url, header);
2590     } else if (!strcmp(cmd, "PAUSE")) {
2591         rtsp_cmd_pause(c, url, header);
2592     } else if (!strcmp(cmd, "TEARDOWN")) {
2593         rtsp_cmd_teardown(c, url, header);
2594     } else {
2595         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2596     }
2597  the_end:
2598     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2599     c->pb = NULL; /* safety */
2600     if (len < 0) {
2601         /* XXX: cannot do more */
2602         return -1;
2603     }
2604     c->buffer_ptr = c->pb_buffer;
2605     c->buffer_end = c->pb_buffer + len;
2606     c->state = RTSPSTATE_SEND_REPLY;
2607     return 0;
2608 }
2609
2610 /* XXX: move that to rtsp.c, but would need to replace FFStream by
2611    AVFormatContext */
2612 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
2613                                    struct in_addr my_ip)
2614 {
2615     ByteIOContext pb1, *pb = &pb1;
2616     int i, payload_type, port, private_payload_type, j;
2617     const char *ipstr, *title, *mediatype;
2618     AVStream *st;
2619     
2620     if (url_open_dyn_buf(pb) < 0)
2621         return -1;
2622     
2623     /* general media info */
2624
2625     url_fprintf(pb, "v=0\n");
2626     ipstr = inet_ntoa(my_ip);
2627     url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2628     title = stream->title;
2629     if (title[0] == '\0')
2630         title = "No Title";
2631     url_fprintf(pb, "s=%s\n", title);
2632     if (stream->comment[0] != '\0')
2633         url_fprintf(pb, "i=%s\n", stream->comment);
2634     if (stream->is_multicast) {
2635         url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2636     }
2637     /* for each stream, we output the necessary info */
2638     private_payload_type = RTP_PT_PRIVATE;
2639     for(i = 0; i < stream->nb_streams; i++) {
2640         st = stream->streams[i];
2641         if (st->codec.codec_id == CODEC_ID_MPEG2TS) {
2642             mediatype = "video";
2643         } else {
2644             switch(st->codec.codec_type) {
2645             case CODEC_TYPE_AUDIO:
2646                 mediatype = "audio";
2647                 break;
2648             case CODEC_TYPE_VIDEO:
2649                 mediatype = "video";
2650                 break;
2651             default:
2652                 mediatype = "application";
2653                 break;
2654             }
2655         }
2656         /* NOTE: the port indication is not correct in case of
2657            unicast. It is not an issue because RTSP gives it */
2658         payload_type = rtp_get_payload_type(&st->codec);
2659         if (payload_type < 0)
2660             payload_type = private_payload_type++;
2661         if (stream->is_multicast) {
2662             port = stream->multicast_port + 2 * i;
2663         } else {
2664             port = 0;
2665         }
2666         url_fprintf(pb, "m=%s %d RTP/AVP %d\n", 
2667                     mediatype, port, payload_type);
2668         if (payload_type >= RTP_PT_PRIVATE) {
2669             /* for private payload type, we need to give more info */
2670             switch(st->codec.codec_id) {
2671             case CODEC_ID_MPEG4:
2672                 {
2673                     uint8_t *data;
2674                     url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n", 
2675                                 payload_type, 90000);
2676                     /* we must also add the mpeg4 header */
2677                     data = st->codec.extradata;
2678                     if (data) {
2679                         url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2680                         for(j=0;j<st->codec.extradata_size;j++) {
2681                             url_fprintf(pb, "%02x", data[j]);
2682                         }
2683                         url_fprintf(pb, "\n");
2684                     }
2685                 }
2686                 break;
2687             default:
2688                 /* XXX: add other codecs ? */
2689                 goto fail;
2690             }
2691         }
2692         url_fprintf(pb, "a=control:streamid=%d\n", i);
2693     }
2694     return url_close_dyn_buf(pb, pbuffer);
2695  fail:
2696     url_close_dyn_buf(pb, pbuffer);
2697     av_free(*pbuffer);
2698     return -1;
2699 }
2700
2701 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2702 {
2703 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2704     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2705     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2706     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2707     url_fprintf(c->pb, "\r\n");
2708 }
2709
2710 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2711 {
2712     FFStream *stream;
2713     char path1[1024];
2714     const char *path;
2715     uint8_t *content;
2716     int content_length, len;
2717     struct sockaddr_in my_addr;
2718     
2719     /* find which url is asked */
2720     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2721     path = path1;
2722     if (*path == '/')
2723         path++;
2724
2725     for(stream = first_stream; stream != NULL; stream = stream->next) {
2726         if (!stream->is_feed && stream->fmt == &rtp_mux &&
2727             !strcmp(path, stream->filename)) {
2728             goto found;
2729         }
2730     }
2731     /* no stream found */
2732     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2733     return;
2734
2735  found:
2736     /* prepare the media description in sdp format */
2737
2738     /* get the host IP */
2739     len = sizeof(my_addr);
2740     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2741     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2742     if (content_length < 0) {
2743         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2744         return;
2745     }
2746     rtsp_reply_header(c, RTSP_STATUS_OK);
2747     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2748     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2749     url_fprintf(c->pb, "\r\n");
2750     put_buffer(c->pb, content, content_length);
2751 }
2752
2753 static HTTPContext *find_rtp_session(const char *session_id)
2754 {
2755     HTTPContext *c;
2756
2757     if (session_id[0] == '\0')
2758         return NULL;
2759
2760     for(c = first_http_ctx; c != NULL; c = c->next) {
2761         if (!strcmp(c->session_id, session_id))
2762             return c;
2763     }
2764     return NULL;
2765 }
2766
2767 static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2768 {
2769     RTSPTransportField *th;
2770     int i;
2771
2772     for(i=0;i<h->nb_transports;i++) {
2773         th = &h->transports[i];
2774         if (th->protocol == protocol)
2775             return th;
2776     }
2777     return NULL;
2778 }
2779
2780 static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2781                            RTSPHeader *h)
2782 {
2783     FFStream *stream;
2784     int stream_index, port;
2785     char buf[1024];
2786     char path1[1024];
2787     const char *path;
2788     HTTPContext *rtp_c;
2789     RTSPTransportField *th;
2790     struct sockaddr_in dest_addr;
2791     RTSPActionServerSetup setup;
2792     
2793     /* find which url is asked */
2794     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2795     path = path1;
2796     if (*path == '/')
2797         path++;
2798
2799     /* now check each stream */
2800     for(stream = first_stream; stream != NULL; stream = stream->next) {
2801         if (!stream->is_feed && stream->fmt == &rtp_mux) {
2802             /* accept aggregate filenames only if single stream */
2803             if (!strcmp(path, stream->filename)) {
2804                 if (stream->nb_streams != 1) {
2805                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2806                     return;
2807                 }
2808                 stream_index = 0;
2809                 goto found;
2810             }
2811                 
2812             for(stream_index = 0; stream_index < stream->nb_streams;
2813                 stream_index++) {
2814                 snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2815                          stream->filename, stream_index);
2816                 if (!strcmp(path, buf))
2817                     goto found;
2818             }
2819         }
2820     }
2821     /* no stream found */
2822     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2823     return;
2824  found:
2825
2826     /* generate session id if needed */
2827     if (h->session_id[0] == '\0') {
2828         snprintf(h->session_id, sizeof(h->session_id), 
2829                  "%08x%08x", (int)random(), (int)random());
2830     }
2831
2832     /* find rtp session, and create it if none found */
2833     rtp_c = find_rtp_session(h->session_id);
2834     if (!rtp_c) {
2835         /* always prefer UDP */
2836         th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2837         if (!th) {
2838             th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2839             if (!th) {
2840                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2841                 return;
2842             }
2843         }
2844
2845         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2846                                    th->protocol);
2847         if (!rtp_c) {
2848             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2849             return;
2850         }
2851
2852         /* open input stream */
2853         if (open_input_stream(rtp_c, "") < 0) {
2854             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2855             return;
2856         }
2857     }
2858     
2859     /* test if stream is OK (test needed because several SETUP needs
2860        to be done for a given file) */
2861     if (rtp_c->stream != stream) {
2862         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2863         return;
2864     }
2865     
2866     /* test if stream is already set up */
2867     if (rtp_c->rtp_ctx[stream_index]) {
2868         rtsp_reply_error(c, RTSP_STATUS_STATE);
2869         return;
2870     }
2871
2872     /* check transport */
2873     th = find_transport(h, rtp_c->rtp_protocol);
2874     if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP && 
2875                 th->client_port_min <= 0)) {
2876         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2877         return;
2878     }
2879
2880     /* setup default options */
2881     setup.transport_option[0] = '\0';
2882     dest_addr = rtp_c->from_addr;
2883     dest_addr.sin_port = htons(th->client_port_min);
2884     
2885     /* add transport option if needed */
2886     if (ff_rtsp_callback) {
2887         setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2888         if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
2889                              (char *)&setup, sizeof(setup),
2890                              stream->rtsp_option) < 0) {
2891             rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2892             return;
2893         }
2894         dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2895     }
2896     
2897     /* setup stream */
2898     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2899         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2900         return;
2901     }
2902
2903     /* now everything is OK, so we can send the connection parameters */
2904     rtsp_reply_header(c, RTSP_STATUS_OK);
2905     /* session ID */
2906     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2907
2908     switch(rtp_c->rtp_protocol) {
2909     case RTSP_PROTOCOL_RTP_UDP:
2910         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2911         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2912                     "client_port=%d-%d;server_port=%d-%d",
2913                     th->client_port_min, th->client_port_min + 1,
2914                     port, port + 1);
2915         break;
2916     case RTSP_PROTOCOL_RTP_TCP:
2917         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2918                     stream_index * 2, stream_index * 2 + 1);
2919         break;
2920     default:
2921         break;
2922     }
2923     if (setup.transport_option[0] != '\0') {
2924         url_fprintf(c->pb, ";%s", setup.transport_option);
2925     }
2926     url_fprintf(c->pb, "\r\n");
2927     
2928
2929     url_fprintf(c->pb, "\r\n");
2930 }
2931
2932
2933 /* find an rtp connection by using the session ID. Check consistency
2934    with filename */
2935 static HTTPContext *find_rtp_session_with_url(const char *url, 
2936                                               const char *session_id)
2937 {
2938     HTTPContext *rtp_c;
2939     char path1[1024];
2940     const char *path;
2941     char buf[1024];
2942     int s;
2943
2944     rtp_c = find_rtp_session(session_id);
2945     if (!rtp_c)
2946         return NULL;
2947
2948     /* find which url is asked */
2949     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2950     path = path1;
2951     if (*path == '/')
2952         path++;
2953     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2954     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2955       snprintf(buf, sizeof(buf), "%s/streamid=%d",
2956         rtp_c->stream->filename, s);
2957       if(!strncmp(path, buf, sizeof(buf))) {
2958     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2959         return rtp_c;
2960       }
2961     }
2962     return NULL;
2963 }
2964
2965 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2966 {
2967     HTTPContext *rtp_c;
2968
2969     rtp_c = find_rtp_session_with_url(url, h->session_id);
2970     if (!rtp_c) {
2971         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2972         return;
2973     }
2974     
2975     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2976         rtp_c->state != HTTPSTATE_WAIT_FEED &&
2977         rtp_c->state != HTTPSTATE_READY) {
2978         rtsp_reply_error(c, RTSP_STATUS_STATE);
2979         return;
2980     }
2981
2982 #if 0
2983     /* XXX: seek in stream */
2984     if (h->range_start != AV_NOPTS_VALUE) {
2985         printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2986         av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2987     }
2988 #endif
2989
2990     rtp_c->state = HTTPSTATE_SEND_DATA;
2991     
2992     /* now everything is OK, so we can send the connection parameters */
2993     rtsp_reply_header(c, RTSP_STATUS_OK);
2994     /* session ID */
2995     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2996     url_fprintf(c->pb, "\r\n");
2997 }
2998
2999 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3000 {
3001     HTTPContext *rtp_c;
3002
3003     rtp_c = find_rtp_session_with_url(url, h->session_id);
3004     if (!rtp_c) {
3005         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3006         return;
3007     }
3008     
3009     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3010         rtp_c->state != HTTPSTATE_WAIT_FEED) {
3011         rtsp_reply_error(c, RTSP_STATUS_STATE);
3012         return;
3013     }
3014     
3015     rtp_c->state = HTTPSTATE_READY;
3016     rtp_c->first_pts = AV_NOPTS_VALUE;
3017     /* now everything is OK, so we can send the connection parameters */
3018     rtsp_reply_header(c, RTSP_STATUS_OK);
3019     /* session ID */
3020     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3021     url_fprintf(c->pb, "\r\n");
3022 }
3023
3024 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3025 {
3026     HTTPContext *rtp_c;
3027
3028     rtp_c = find_rtp_session_with_url(url, h->session_id);
3029     if (!rtp_c) {
3030         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3031         return;
3032     }
3033     
3034     /* abort the session */
3035     close_connection(rtp_c);
3036
3037     if (ff_rtsp_callback) {
3038         ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, 
3039                          NULL, 0,
3040                          rtp_c->stream->rtsp_option);
3041     }
3042
3043     /* now everything is OK, so we can send the connection parameters */
3044     rtsp_reply_header(c, RTSP_STATUS_OK);
3045     /* session ID */
3046     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3047     url_fprintf(c->pb, "\r\n");
3048 }
3049
3050
3051 /********************************************************************/
3052 /* RTP handling */
3053
3054 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
3055                                        FFStream *stream, const char *session_id,
3056                                        enum RTSPProtocol rtp_protocol)
3057 {
3058     HTTPContext *c = NULL;
3059     const char *proto_str;
3060     
3061     /* XXX: should output a warning page when coming
3062        close to the connection limit */
3063     if (nb_connections >= nb_max_connections)
3064         goto fail;
3065     
3066     /* add a new connection */
3067     c = av_mallocz(sizeof(HTTPContext));
3068     if (!c)
3069         goto fail;
3070     
3071     c->fd = -1;
3072     c->poll_entry = NULL;
3073     c->from_addr = *from_addr;
3074     c->buffer_size = IOBUFFER_INIT_SIZE;
3075     c->buffer = av_malloc(c->buffer_size);
3076     if (!c->buffer)
3077         goto fail;
3078     nb_connections++;
3079     c->stream = stream;
3080     pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3081     c->state = HTTPSTATE_READY;
3082     c->is_packetized = 1;
3083     c->rtp_protocol = rtp_protocol;
3084
3085     /* protocol is shown in statistics */
3086     switch(c->rtp_protocol) {
3087     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3088         proto_str = "MCAST";
3089         break;
3090     case RTSP_PROTOCOL_RTP_UDP:
3091         proto_str = "UDP";
3092         break;
3093     case RTSP_PROTOCOL_RTP_TCP:
3094         proto_str = "TCP";
3095         break;
3096     default:
3097         proto_str = "???";
3098         break;
3099     }
3100     pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3101     pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3102
3103     current_bandwidth += stream->bandwidth;
3104
3105     c->next = first_http_ctx;
3106     first_http_ctx = c;
3107     return c;
3108         
3109  fail:
3110     if (c) {
3111         av_free(c->buffer);
3112         av_free(c);
3113     }
3114     return NULL;
3115 }
3116
3117 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3118    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3119    used. */
3120 static int rtp_new_av_stream(HTTPContext *c, 
3121                              int stream_index, struct sockaddr_in *dest_addr,
3122                              HTTPContext *rtsp_c)
3123 {
3124     AVFormatContext *ctx;
3125     AVStream *st;
3126     char *ipaddr;
3127     URLContext *h;
3128     uint8_t *dummy_buf;
3129     char buf2[32];
3130     int max_packet_size;
3131     
3132     /* now we can open the relevant output stream */
3133     ctx = av_alloc_format_context();
3134     if (!ctx)
3135         return -1;
3136     ctx->oformat = &rtp_mux;
3137
3138     st = av_mallocz(sizeof(AVStream));
3139     if (!st)
3140         goto fail;
3141     ctx->nb_streams = 1;
3142     ctx->streams[0] = st;
3143
3144     if (!c->stream->feed || 
3145         c->stream->feed == c->stream) {
3146         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3147     } else {
3148         memcpy(st, 
3149                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3150                sizeof(AVStream));
3151     }
3152     
3153     /* build destination RTP address */
3154     ipaddr = inet_ntoa(dest_addr->sin_addr);
3155
3156     switch(c->rtp_protocol) {
3157     case RTSP_PROTOCOL_RTP_UDP:
3158     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3159         /* RTP/UDP case */
3160         
3161         /* XXX: also pass as parameter to function ? */
3162         if (c->stream->is_multicast) {
3163             int ttl;
3164             ttl = c->stream->multicast_ttl;
3165             if (!ttl)
3166                 ttl = 16;
3167             snprintf(ctx->filename, sizeof(ctx->filename),
3168                      "rtp://%s:%d?multicast=1&ttl=%d", 
3169                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3170         } else {
3171             snprintf(ctx->filename, sizeof(ctx->filename),
3172                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3173         }
3174
3175         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3176             goto fail;
3177         c->rtp_handles[stream_index] = h;
3178         max_packet_size = url_get_max_packet_size(h);
3179         break;
3180     case RTSP_PROTOCOL_RTP_TCP:
3181         /* RTP/TCP case */
3182         c->rtsp_c = rtsp_c;
3183         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3184         break;
3185     default:
3186         goto fail;
3187     }
3188
3189     http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3190              ipaddr, ntohs(dest_addr->sin_port), 
3191              ctime1(buf2), 
3192              c->stream->filename, stream_index, c->protocol);
3193
3194     /* normally, no packets should be output here, but the packet size may be checked */
3195     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3196         /* XXX: close stream */
3197         goto fail;
3198     }
3199     av_set_parameters(ctx, NULL);
3200     if (av_write_header(ctx) < 0) {
3201     fail:
3202         if (h)
3203             url_close(h);
3204         av_free(ctx);
3205         return -1;
3206     }
3207     url_close_dyn_buf(&ctx->pb, &dummy_buf);
3208     av_free(dummy_buf);
3209     
3210     c->rtp_ctx[stream_index] = ctx;
3211     return 0;
3212 }
3213
3214 /********************************************************************/
3215 /* ffserver initialization */
3216
3217 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3218 {
3219     AVStream *fst;
3220
3221     fst = av_mallocz(sizeof(AVStream));
3222     if (!fst)
3223         return NULL;
3224     fst->priv_data = av_mallocz(sizeof(FeedData));
3225     memcpy(&fst->codec, codec, sizeof(AVCodecContext));
3226     fst->codec.coded_frame = &dummy_frame;
3227     fst->index = stream->nb_streams;
3228     av_set_pts_info(fst, 33, 1, 90000);
3229     stream->streams[stream->nb_streams++] = fst;
3230     return fst;
3231 }
3232
3233 /* return the stream number in the feed */
3234 static int add_av_stream(FFStream *feed, AVStream *st)
3235 {
3236     AVStream *fst;
3237     AVCodecContext *av, *av1;
3238     int i;
3239
3240     av = &st->codec;
3241     for(i=0;i<feed->nb_streams;i++) {
3242         st = feed->streams[i];
3243         av1 = &st->codec;
3244         if (av1->codec_id == av->codec_id &&
3245             av1->codec_type == av->codec_type &&
3246             av1->bit_rate == av->bit_rate) {
3247
3248             switch(av->codec_type) {
3249             case CODEC_TYPE_AUDIO:
3250                 if (av1->channels == av->channels &&
3251                     av1->sample_rate == av->sample_rate)
3252                     goto found;
3253                 break;
3254             case CODEC_TYPE_VIDEO:
3255                 if (av1->width == av->width &&
3256                     av1->height == av->height &&
3257                     av1->time_base.den == av->time_base.den &&
3258                     av1->time_base.num == av->time_base.num &&
3259                     av1->gop_size == av->gop_size)
3260                     goto found;
3261                 break;
3262             default:
3263                 av_abort();
3264             }
3265         }
3266     }
3267     
3268     fst = add_av_stream1(feed, av);
3269     if (!fst)
3270         return -1;
3271     return feed->nb_streams - 1;
3272  found:
3273     return i;
3274 }
3275
3276 static void remove_stream(FFStream *stream)
3277 {
3278     FFStream **ps;
3279     ps = &first_stream;
3280     while (*ps != NULL) {
3281         if (*ps == stream) {
3282             *ps = (*ps)->next;
3283         } else {
3284             ps = &(*ps)->next;
3285         }
3286     }
3287 }
3288
3289 /* specific mpeg4 handling : we extract the raw parameters */
3290 static void extract_mpeg4_header(AVFormatContext *infile)
3291 {
3292     int mpeg4_count, i, size;
3293     AVPacket pkt;
3294     AVStream *st;
3295     const uint8_t *p;
3296
3297     mpeg4_count = 0;
3298     for(i=0;i<infile->nb_streams;i++) {
3299         st = infile->streams[i];
3300         if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3301             st->codec.extradata_size == 0) {
3302             mpeg4_count++;
3303         }
3304     }
3305     if (!mpeg4_count)
3306         return;
3307
3308     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3309     while (mpeg4_count > 0) {
3310         if (av_read_packet(infile, &pkt) < 0)
3311             break;
3312         st = infile->streams[pkt.stream_index];
3313         if (st->codec.codec_id == CODEC_ID_MPEG4 &&
3314             st->codec.extradata_size == 0) {
3315             av_freep(&st->codec.extradata);
3316             /* fill extradata with the header */
3317             /* XXX: we make hard suppositions here ! */
3318             p = pkt.data;
3319             while (p < pkt.data + pkt.size - 4) {
3320                 /* stop when vop header is found */
3321                 if (p[0] == 0x00 && p[1] == 0x00 && 
3322                     p[2] == 0x01 && p[3] == 0xb6) {
3323                     size = p - pkt.data;
3324                     //                    av_hex_dump(pkt.data, size);
3325                     st->codec.extradata = av_malloc(size);
3326                     st->codec.extradata_size = size;
3327                     memcpy(st->codec.extradata, pkt.data, size);
3328                     break;
3329                 }
3330                 p++;
3331             }
3332             mpeg4_count--;
3333         }
3334         av_free_packet(&pkt);
3335     }
3336 }
3337
3338 /* compute the needed AVStream for each file */
3339 static void build_file_streams(void)
3340 {
3341     FFStream *stream, *stream_next;
3342     AVFormatContext *infile;
3343     int i;
3344
3345     /* gather all streams */
3346     for(stream = first_stream; stream != NULL; stream = stream_next) {
3347         stream_next = stream->next;
3348         if (stream->stream_type == STREAM_TYPE_LIVE &&
3349             !stream->feed) {
3350             /* the stream comes from a file */
3351             /* try to open the file */
3352             /* open stream */
3353             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3354             if (stream->fmt == &rtp_mux) {
3355                 /* specific case : if transport stream output to RTP,
3356                    we use a raw transport stream reader */
3357                 stream->ap_in->mpeg2ts_raw = 1;
3358                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3359             }
3360             
3361             if (av_open_input_file(&infile, stream->feed_filename, 
3362                                    stream->ifmt, 0, stream->ap_in) < 0) {
3363                 http_log("%s not found", stream->feed_filename);
3364                 /* remove stream (no need to spend more time on it) */
3365             fail:
3366                 remove_stream(stream);
3367             } else {
3368                 /* find all the AVStreams inside and reference them in
3369                    'stream' */
3370                 if (av_find_stream_info(infile) < 0) {
3371                     http_log("Could not find codec parameters from '%s'", 
3372                              stream->feed_filename);
3373                     av_close_input_file(infile);
3374                     goto fail;
3375                 }
3376                 extract_mpeg4_header(infile);
3377
3378                 for(i=0;i<infile->nb_streams;i++) {
3379                     add_av_stream1(stream, &infile->streams[i]->codec);
3380                 }
3381                 av_close_input_file(infile);
3382             }
3383         }
3384     }
3385 }
3386
3387 /* compute the needed AVStream for each feed */
3388 static void build_feed_streams(void)
3389 {
3390     FFStream *stream, *feed;
3391     int i;
3392
3393     /* gather all streams */
3394     for(stream = first_stream; stream != NULL; stream = stream->next) {
3395         feed = stream->feed;
3396         if (feed) {
3397             if (!stream->is_feed) {
3398                 /* we handle a stream coming from a feed */
3399                 for(i=0;i<stream->nb_streams;i++) {
3400                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3401                 }
3402             }
3403         }
3404     }
3405
3406     /* gather all streams */
3407     for(stream = first_stream; stream != NULL; stream = stream->next) {
3408         feed = stream->feed;
3409         if (feed) {
3410             if (stream->is_feed) {
3411                 for(i=0;i<stream->nb_streams;i++) {
3412                     stream->feed_streams[i] = i;
3413                 }
3414             }
3415         }
3416     }
3417
3418     /* create feed files if needed */
3419     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3420         int fd;
3421
3422         if (url_exist(feed->feed_filename)) {
3423             /* See if it matches */
3424             AVFormatContext *s;
3425             int matches = 0;
3426
3427             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3428                 /* Now see if it matches */
3429                 if (s->nb_streams == feed->nb_streams) {
3430                     matches = 1;
3431                     for(i=0;i<s->nb_streams;i++) {
3432                         AVStream *sf, *ss;
3433                         sf = feed->streams[i];
3434                         ss = s->streams[i];
3435
3436                         if (sf->index != ss->index ||
3437                             sf->id != ss->id) {
3438                             printf("Index & Id do not match for stream %d (%s)\n", 
3439                                    i, feed->feed_filename);
3440                             matches = 0;
3441                         } else {
3442                             AVCodecContext *ccf, *ccs;
3443
3444                             ccf = &sf->codec;
3445                             ccs = &ss->codec;
3446 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3447
3448                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3449                                 printf("Codecs do not match for stream %d\n", i);
3450                                 matches = 0;
3451                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3452                                 printf("Codec bitrates do not match for stream %d\n", i);
3453                                 matches = 0;
3454                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3455                                 if (CHECK_CODEC(time_base.den) ||
3456                                     CHECK_CODEC(time_base.num) ||
3457                                     CHECK_CODEC(width) ||
3458                                     CHECK_CODEC(height)) {
3459                                     printf("Codec width, height and framerate do not match for stream %d\n", i);
3460                                     matches = 0;
3461                                 }
3462                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3463                                 if (CHECK_CODEC(sample_rate) ||
3464                                     CHECK_CODEC(channels) ||
3465                                     CHECK_CODEC(frame_size)) {
3466                                     printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3467                                     matches = 0;
3468                                 }
3469                             } else {
3470                                 printf("Unknown codec type\n");
3471                                 matches = 0;
3472                             }
3473                         }
3474                         if (!matches) {
3475                             break;
3476                         }
3477                     }
3478                 } else {
3479                     printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3480                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3481                 }
3482
3483                 av_close_input_file(s);
3484             } else {
3485                 printf("Deleting feed file '%s' as it appears to be corrupt\n",
3486                         feed->feed_filename);
3487             }
3488             if (!matches) {
3489                 if (feed->readonly) {
3490                     printf("Unable to delete feed file '%s' as it is marked readonly\n",
3491                         feed->feed_filename);
3492                     exit(1);
3493                 }
3494                 unlink(feed->feed_filename);
3495             }
3496         }
3497         if (!url_exist(feed->feed_filename)) {
3498             AVFormatContext s1, *s = &s1;
3499
3500             if (feed->readonly) {
3501                 printf("Unable to create feed file '%s' as it is marked readonly\n",
3502                     feed->feed_filename);
3503                 exit(1);
3504             }
3505
3506             /* only write the header of the ffm file */
3507             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3508                 fprintf(stderr, "Could not open output feed file '%s'\n",
3509                         feed->feed_filename);
3510                 exit(1);
3511             }
3512             s->oformat = feed->fmt;
3513             s->nb_streams = feed->nb_streams;
3514             for(i=0;i<s->nb_streams;i++) {
3515                 AVStream *st;
3516                 st = feed->streams[i];
3517                 s->streams[i] = st;
3518             }
3519             av_set_parameters(s, NULL);
3520             av_write_header(s);
3521             /* XXX: need better api */
3522             av_freep(&s->priv_data);
3523             url_fclose(&s->pb);
3524         }
3525         /* get feed size and write index */
3526         fd = open(feed->feed_filename, O_RDONLY);
3527         if (fd < 0) {
3528             fprintf(stderr, "Could not open output feed file '%s'\n",
3529                     feed->feed_filename);
3530             exit(1);
3531         }
3532
3533         feed->feed_write_index = ffm_read_write_index(fd);
3534         feed->feed_size = lseek(fd, 0, SEEK_END);
3535         /* ensure that we do not wrap before the end of file */
3536         if (feed->feed_max_size < feed->feed_size)
3537             feed->feed_max_size = feed->feed_size;
3538
3539         close(fd);
3540     }
3541 }
3542
3543 /* compute the bandwidth used by each stream */
3544 static void compute_bandwidth(void)
3545 {
3546     int bandwidth, i;
3547     FFStream *stream;
3548     
3549     for(stream = first_stream; stream != NULL; stream = stream->next) {
3550         bandwidth = 0;
3551         for(i=0;i<stream->nb_streams;i++) {
3552             AVStream *st = stream->streams[i];
3553             switch(st->codec.codec_type) {
3554             case CODEC_TYPE_AUDIO:
3555             case CODEC_TYPE_VIDEO:
3556                 bandwidth += st->codec.bit_rate;
3557                 break;
3558             default:
3559                 break;
3560             }
3561         }
3562         stream->bandwidth = (bandwidth + 999) / 1000;
3563     }
3564 }
3565
3566 static void get_arg(char *buf, int buf_size, const char **pp)
3567 {
3568     const char *p;
3569     char *q;
3570     int quote;
3571
3572     p = *pp;
3573     while (isspace(*p)) p++;
3574     q = buf;
3575     quote = 0;
3576     if (*p == '\"' || *p == '\'')
3577         quote = *p++;
3578     for(;;) {
3579         if (quote) {
3580             if (*p == quote)
3581                 break;
3582         } else {
3583             if (isspace(*p))
3584                 break;
3585         }
3586         if (*p == '\0')
3587             break;
3588         if ((q - buf) < buf_size - 1)
3589             *q++ = *p;
3590         p++;
3591     }
3592     *q = '\0';
3593     if (quote && *p == quote)
3594         p++;
3595     *pp = p;
3596 }
3597
3598 /* add a codec and set the default parameters */
3599 static void add_codec(FFStream *stream, AVCodecContext *av)
3600 {
3601     AVStream *st;
3602
3603     /* compute default parameters */
3604     switch(av->codec_type) {
3605     case CODEC_TYPE_AUDIO:
3606         if (av->bit_rate == 0)
3607             av->bit_rate = 64000;
3608         if (av->sample_rate == 0)
3609             av->sample_rate = 22050;
3610         if (av->channels == 0)
3611             av->channels = 1;
3612         break;
3613     case CODEC_TYPE_VIDEO:
3614         if (av->bit_rate == 0)
3615             av->bit_rate = 64000;
3616         if (av->time_base.num == 0){
3617             av->time_base.den = 5;
3618             av->time_base.num = 1;
3619         }
3620         if (av->width == 0 || av->height == 0) {
3621             av->width = 160;
3622             av->height = 128;
3623         }
3624         /* Bitrate tolerance is less for streaming */
3625         if (av->bit_rate_tolerance == 0)
3626             av->bit_rate_tolerance = av->bit_rate / 4;
3627         if (av->qmin == 0)
3628             av->qmin = 3;
3629         if (av->qmax == 0)
3630             av->qmax = 31;
3631         if (av->max_qdiff == 0)
3632             av->max_qdiff = 3;
3633         av->qcompress = 0.5;
3634         av->qblur = 0.5;
3635
3636         if (!av->nsse_weight) 
3637             av->nsse_weight = 8;
3638
3639         av->frame_skip_cmp = FF_CMP_DCTMAX;
3640         av->me_method = ME_EPZS;
3641         av->rc_buffer_aggressivity = 1.0;
3642
3643         if (!av->rc_eq)
3644             av->rc_eq = "tex^qComp";
3645         if (!av->i_quant_factor)
3646             av->i_quant_factor = -0.8;
3647         if (!av->b_quant_factor)
3648             av->b_quant_factor = 1.25;
3649         if (!av->b_quant_offset)
3650             av->b_quant_offset = 1.25;
3651         if (!av->rc_max_rate)
3652             av->rc_max_rate = av->bit_rate * 2;
3653
3654         if (av->rc_max_rate && !av->rc_buffer_size) {
3655             av->rc_buffer_size = av->rc_max_rate;
3656         }
3657
3658
3659         break;
3660     default:
3661         av_abort();
3662     }
3663
3664     st = av_mallocz(sizeof(AVStream));
3665     if (!st)
3666         return;
3667     stream->streams[stream->nb_streams++] = st;
3668     memcpy(&st->codec, av, sizeof(AVCodecContext));
3669 }
3670
3671 static int opt_audio_codec(const char *arg)
3672 {
3673     AVCodec *p;
3674
3675     p = first_avcodec;
3676     while (p) {
3677         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3678             break;
3679         p = p->next;
3680     }
3681     if (p == NULL) {
3682         return CODEC_ID_NONE;
3683     }
3684
3685     return p->id;
3686 }
3687
3688 static int opt_video_codec(const char *arg)
3689 {
3690     AVCodec *p;
3691
3692     p = first_avcodec;
3693     while (p) {
3694         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3695             break;
3696         p = p->next;
3697     }
3698     if (p == NULL) {
3699         return CODEC_ID_NONE;
3700     }
3701
3702     return p->id;
3703 }
3704
3705 /* simplistic plugin support */
3706
3707 #ifdef CONFIG_HAVE_DLOPEN
3708 void load_module(const char *filename)
3709 {
3710     void *dll;
3711     void (*init_func)(void);
3712     dll = dlopen(filename, RTLD_NOW);
3713     if (!dll) {
3714         fprintf(stderr, "Could not load module '%s' - %s\n",
3715                 filename, dlerror());
3716         return;
3717     }
3718     
3719     init_func = dlsym(dll, "ffserver_module_init");
3720     if (!init_func) {
3721         fprintf(stderr, 
3722                 "%s: init function 'ffserver_module_init()' not found\n",
3723                 filename);
3724         dlclose(dll);
3725     }
3726
3727     init_func();
3728 }
3729 #endif
3730
3731 static int parse_ffconfig(const char *filename)
3732 {
3733     FILE *f;
3734     char line[1024];
3735     char cmd[64];
3736     char arg[1024];
3737     const char *p;
3738     int val, errors, line_num;
3739     FFStream **last_stream, *stream, *redirect;
3740     FFStream **last_feed, *feed;
3741     AVCodecContext audio_enc, video_enc;
3742     int audio_id, video_id;
3743
3744     f = fopen(filename, "r");
3745     if (!f) {
3746         perror(filename);
3747         return -1;
3748     }
3749     
3750     errors = 0;
3751     line_num = 0;
3752     first_stream = NULL;
3753     last_stream = &first_stream;
3754     first_feed = NULL;
3755     last_feed = &first_feed;
3756     stream = NULL;
3757     feed = NULL;
3758     redirect = NULL;
3759     audio_id = CODEC_ID_NONE;
3760     video_id = CODEC_ID_NONE;
3761     for(;;) {
3762         if (fgets(line, sizeof(line), f) == NULL)
3763             break;
3764         line_num++;
3765         p = line;
3766         while (isspace(*p)) 
3767             p++;
3768         if (*p == '\0' || *p == '#')
3769             continue;
3770
3771         get_arg(cmd, sizeof(cmd), &p);
3772         
3773         if (!strcasecmp(cmd, "Port")) {
3774             get_arg(arg, sizeof(arg), &p);
3775             my_http_addr.sin_port = htons (atoi(arg));
3776         } else if (!strcasecmp(cmd, "BindAddress")) {
3777             get_arg(arg, sizeof(arg), &p);
3778             if (!inet_aton(arg, &my_http_addr.sin_addr)) {
3779                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3780                         filename, line_num, arg);
3781                 errors++;
3782             }
3783         } else if (!strcasecmp(cmd, "NoDaemon")) {
3784             ffserver_daemon = 0;
3785         } else if (!strcasecmp(cmd, "RTSPPort")) {
3786             get_arg(arg, sizeof(arg), &p);
3787             my_rtsp_addr.sin_port = htons (atoi(arg));
3788         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3789             get_arg(arg, sizeof(arg), &p);
3790             if (!inet_aton(arg, &my_rtsp_addr.sin_addr)) {
3791                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
3792                         filename, line_num, arg);
3793                 errors++;
3794             }
3795         } else if (!strcasecmp(cmd, "MaxClients")) {
3796             get_arg(arg, sizeof(arg), &p);
3797             val = atoi(arg);
3798             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3799                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
3800                         filename, line_num, arg);
3801                 errors++;
3802             } else {
3803                 nb_max_connections = val;
3804             }
3805         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3806             get_arg(arg, sizeof(arg), &p);
3807             val = atoi(arg);
3808             if (val < 10 || val > 100000) {
3809                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
3810                         filename, line_num, arg);
3811                 errors++;
3812             } else {
3813                 max_bandwidth = val;
3814             }
3815         } else if (!strcasecmp(cmd, "CustomLog")) {
3816             get_arg(logfilename, sizeof(logfilename), &p);
3817         } else if (!strcasecmp(cmd, "<Feed")) {
3818             /*********************************************/
3819             /* Feed related options */
3820             char *q;
3821             if (stream || feed) {
3822                 fprintf(stderr, "%s:%d: Already in a tag\n",
3823                         filename, line_num);
3824             } else {
3825                 feed = av_mallocz(sizeof(FFStream));
3826                 /* add in stream list */
3827                 *last_stream = feed;
3828                 last_stream = &feed->next;
3829                 /* add in feed list */
3830                 *last_feed = feed;
3831                 last_feed = &feed->next_feed;
3832                 
3833                 get_arg(feed->filename, sizeof(feed->filename), &p);
3834                 q = strrchr(feed->filename, '>');
3835                 if (*q)
3836                     *q = '\0';
3837                 feed->fmt = guess_format("ffm", NULL, NULL);
3838                 /* defaut feed file */
3839                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3840                          "/tmp/%s.ffm", feed->filename);
3841                 feed->feed_max_size = 5 * 1024 * 1024;
3842                 feed->is_feed = 1;
3843                 feed->feed = feed; /* self feeding :-) */
3844             }
3845         } else if (!strcasecmp(cmd, "Launch")) {
3846             if (feed) {
3847                 int i;
3848
3849                 feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
3850
3851                 feed->child_argv[0] = av_malloc(7);
3852                 strcpy(feed->child_argv[0], "ffmpeg");
3853
3854                 for (i = 1; i < 62; i++) {
3855                     char argbuf[256];
3856
3857                     get_arg(argbuf, sizeof(argbuf), &p);
3858                     if (!argbuf[0])
3859                         break;
3860
3861                     feed->child_argv[i] = av_malloc(strlen(argbuf) + 1);
3862                     strcpy(feed->child_argv[i], argbuf);
3863                 }
3864
3865                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3866
3867                 snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
3868                     ntohs(my_http_addr.sin_port), feed->filename);
3869             }
3870         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3871             if (feed) {
3872                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3873                 feed->readonly = 1;
3874             } else if (stream) {
3875                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3876             }
3877         } else if (!strcasecmp(cmd, "File")) {
3878             if (feed) {
3879                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3880             } else if (stream) {
3881                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3882             }
3883         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3884             if (feed) {
3885                 const char *p1;
3886                 double fsize;
3887
3888                 get_arg(arg, sizeof(arg), &p);
3889                 p1 = arg;
3890                 fsize = strtod(p1, (char **)&p1);
3891                 switch(toupper(*p1)) {
3892                 case 'K':
3893                     fsize *= 1024;
3894                     break;
3895                 case 'M':
3896                     fsize *= 1024 * 1024;
3897                     break;
3898                 case 'G':
3899                     fsize *= 1024 * 1024 * 1024;
3900                     break;
3901                 }
3902                 feed->feed_max_size = (int64_t)fsize;
3903             }
3904         } else if (!strcasecmp(cmd, "</Feed>")) {
3905             if (!feed) {
3906                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3907                         filename, line_num);
3908                 errors++;
3909 #if 0
3910             } else {
3911                 /* Make sure that we start out clean */
3912                 if (unlink(feed->feed_filename) < 0 
3913                     && errno != ENOENT) {
3914                     fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
3915                         filename, line_num, feed->feed_filename, strerror(errno));
3916                     errors++;
3917                 }
3918 #endif
3919             }
3920             feed = NULL;
3921         } else if (!strcasecmp(cmd, "<Stream")) {
3922             /*********************************************/
3923             /* Stream related options */
3924             char *q;
3925             if (stream || feed) {
3926                 fprintf(stderr, "%s:%d: Already in a tag\n",
3927                         filename, line_num);
3928             } else {
3929                 stream = av_mallocz(sizeof(FFStream));
3930                 *last_stream = stream;
3931                 last_stream = &stream->next;
3932
3933                 get_arg(stream->filename, sizeof(stream->filename), &p);
3934                 q = strrchr(stream->filename, '>');
3935                 if (*q)
3936                     *q = '\0';
3937                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3938                 memset(&audio_enc, 0, sizeof(AVCodecContext));
3939                 memset(&video_enc, 0, sizeof(AVCodecContext));
3940                 audio_id = CODEC_ID_NONE;
3941                 video_id = CODEC_ID_NONE;
3942                 if (stream->fmt) {
3943                     audio_id = stream->fmt->audio_codec;
3944                     video_id = stream->fmt->video_codec;
3945                 }
3946             }
3947         } else if (!strcasecmp(cmd, "Feed")) {
3948             get_arg(arg, sizeof(arg), &p);
3949             if (stream) {
3950                 FFStream *sfeed;
3951                 
3952                 sfeed = first_feed;
3953                 while (sfeed != NULL) {
3954                     if (!strcmp(sfeed->filename, arg))
3955                         break;
3956                     sfeed = sfeed->next_feed;
3957                 }
3958                 if (!sfeed) {
3959                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3960                             filename, line_num, arg);
3961                 } else {
3962                     stream->feed = sfeed;
3963                 }
3964             }
3965         } else if (!strcasecmp(cmd, "Format")) {
3966             get_arg(arg, sizeof(arg), &p);
3967             if (!strcmp(arg, "status")) {
3968                 stream->stream_type = STREAM_TYPE_STATUS;
3969                 stream->fmt = NULL;
3970             } else {
3971                 stream->stream_type = STREAM_TYPE_LIVE;
3972                 /* jpeg cannot be used here, so use single frame jpeg */
3973                 if (!strcmp(arg, "jpeg"))
3974                     strcpy(arg, "singlejpeg");
3975                 stream->fmt = guess_stream_format(arg, NULL, NULL);
3976                 if (!stream->fmt) {
3977                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
3978                             filename, line_num, arg);
3979                     errors++;
3980                 }
3981             }
3982             if (stream->fmt) {
3983                 audio_id = stream->fmt->audio_codec;
3984                 video_id = stream->fmt->video_codec;
3985             }
3986         } else if (!strcasecmp(cmd, "InputFormat")) {
3987             stream->ifmt = av_find_input_format(arg);
3988             if (!stream->ifmt) {
3989                 fprintf(stderr, "%s:%d: Unknown input format: %s\n", 
3990                         filename, line_num, arg);
3991             }
3992         } else if (!strcasecmp(cmd, "FaviconURL")) {
3993             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3994                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3995             } else {
3996                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
3997                             filename, line_num);
3998                 errors++;
3999             }
4000         } else if (!strcasecmp(cmd, "Author")) {
4001             if (stream) {
4002                 get_arg(stream->author, sizeof(stream->author), &p);
4003             }
4004         } else if (!strcasecmp(cmd, "Comment")) {
4005             if (stream) {
4006                 get_arg(stream->comment, sizeof(stream->comment), &p);
4007             }
4008         } else if (!strcasecmp(cmd, "Copyright")) {
4009             if (stream) {
4010                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4011             }
4012         } else if (!strcasecmp(cmd, "Title")) {
4013             if (stream) {
4014                 get_arg(stream->title, sizeof(stream->title), &p);
4015             }
4016         } else if (!strcasecmp(cmd, "Preroll")) {
4017             get_arg(arg, sizeof(arg), &p);
4018             if (stream) {
4019                 stream->prebuffer = atof(arg) * 1000;
4020             }
4021         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4022             if (stream) {
4023                 stream->send_on_key = 1;
4024             }
4025         } else if (!strcasecmp(cmd, "AudioCodec")) {
4026             get_arg(arg, sizeof(arg), &p);
4027             audio_id = opt_audio_codec(arg);
4028             if (audio_id == CODEC_ID_NONE) {
4029                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
4030                         filename, line_num, arg);
4031                 errors++;
4032             }
4033         } else if (!strcasecmp(cmd, "VideoCodec")) {
4034             get_arg(arg, sizeof(arg), &p);
4035             video_id = opt_video_codec(arg);
4036             if (video_id == CODEC_ID_NONE) {
4037                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
4038                         filename, line_num, arg);
4039                 errors++;
4040             }
4041         } else if (!strcasecmp(cmd, "MaxTime")) {
4042             get_arg(arg, sizeof(arg), &p);
4043             if (stream) {
4044                 stream->max_time = atof(arg) * 1000;
4045             }
4046         } else if (!strcasecmp(cmd, "AudioBitRate")) {
4047             get_arg(arg, sizeof(arg), &p);
4048             if (stream) {
4049                 audio_enc.bit_rate = atoi(arg) * 1000;
4050             }
4051         } else if (!strcasecmp(cmd, "AudioChannels")) {
4052             get_arg(arg, sizeof(arg), &p);
4053             if (stream) {
4054                 audio_enc.channels = atoi(arg);
4055             }
4056         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4057             get_arg(arg, sizeof(arg), &p);
4058             if (stream) {
4059                 audio_enc.sample_rate = atoi(arg);
4060             }
4061         } else if (!strcasecmp(cmd, "AudioQuality")) {
4062             get_arg(arg, sizeof(arg), &p);
4063             if (stream) {
4064 //                audio_enc.quality = atof(arg) * 1000;
4065             }
4066         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4067             if (stream) {
4068                 int minrate, maxrate;
4069
4070                 get_arg(arg, sizeof(arg), &p);
4071
4072                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4073                     video_enc.rc_min_rate = minrate * 1000;
4074                     video_enc.rc_max_rate = maxrate * 1000;
4075                 } else {
4076                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", 
4077                             filename, line_num, arg);
4078                     errors++;
4079                 }
4080             }
4081         } else if (!strcasecmp(cmd, "Debug")) {
4082             if (stream) {
4083                 get_arg(arg, sizeof(arg), &p);
4084                 video_enc.debug = strtol(arg,0,0);
4085             }
4086         } else if (!strcasecmp(cmd, "Strict")) {
4087             if (stream) {
4088                 get_arg(arg, sizeof(arg), &p);
4089                 video_enc.strict_std_compliance = atoi(arg);
4090             }
4091         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4092             if (stream) {
4093                 get_arg(arg, sizeof(arg), &p);
4094                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4095             }
4096         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4097             if (stream) {
4098                 get_arg(arg, sizeof(arg), &p);
4099                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4100             }
4101         } else if (!strcasecmp(cmd, "VideoBitRate")) {
4102             get_arg(arg, sizeof(arg), &p);
4103             if (stream) {
4104                 video_enc.bit_rate = atoi(arg) * 1000;
4105             }
4106         } else if (!strcasecmp(cmd, "VideoSize")) {
4107             get_arg(arg, sizeof(arg), &p);
4108             if (stream) {
4109                 parse_image_size(&video_enc.width, &video_enc.height, arg);
4110                 if ((video_enc.width % 16) != 0 ||
4111                     (video_enc.height % 16) != 0) {
4112                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4113                             filename, line_num);
4114                     errors++;
4115                 }
4116             }
4117         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4118             get_arg(arg, sizeof(arg), &p);
4119             if (stream) {
4120                 video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4121                 video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4122             }
4123         } else if (!strcasecmp(cmd, "VideoGopSize")) {
4124             get_arg(arg, sizeof(arg), &p);
4125             if (stream) {
4126                 video_enc.gop_size = atoi(arg);
4127             }
4128         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4129             if (stream) {
4130                 video_enc.gop_size = 1;
4131             }
4132         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4133             if (stream) {
4134                 video_enc.mb_decision = FF_MB_DECISION_BITS;
4135             }
4136         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4137             if (stream) {
4138                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4139                 video_enc.flags |= CODEC_FLAG_4MV;
4140             }
4141         } else if (!strcasecmp(cmd, "VideoQDiff")) {
4142             get_arg(arg, sizeof(arg), &p);
4143             if (stream) {
4144                 video_enc.max_qdiff = atoi(arg);
4145                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4146                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4147                             filename, line_num);
4148                     errors++;
4149                 }
4150             }
4151         } else if (!strcasecmp(cmd, "VideoQMax")) {
4152             get_arg(arg, sizeof(arg), &p);
4153             if (stream) {
4154                 video_enc.qmax = atoi(arg);
4155                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4156                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4157                             filename, line_num);
4158                     errors++;
4159                 }
4160             }
4161         } else if (!strcasecmp(cmd, "VideoQMin")) {
4162             get_arg(arg, sizeof(arg), &p);
4163             if (stream) {
4164                 video_enc.qmin = atoi(arg);
4165                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4166                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4167                             filename, line_num);
4168                     errors++;
4169                 }
4170             }
4171         } else if (!strcasecmp(cmd, "LumaElim")) {
4172             get_arg(arg, sizeof(arg), &p);
4173             if (stream) {
4174                 video_enc.luma_elim_threshold = atoi(arg);
4175             }
4176         } else if (!strcasecmp(cmd, "ChromaElim")) {
4177             get_arg(arg, sizeof(arg), &p);
4178             if (stream) {
4179                 video_enc.chroma_elim_threshold = atoi(arg);
4180             }
4181         } else if (!strcasecmp(cmd, "LumiMask")) {
4182             get_arg(arg, sizeof(arg), &p);
4183             if (stream) {
4184                 video_enc.lumi_masking = atof(arg);
4185             }
4186         } else if (!strcasecmp(cmd, "DarkMask")) {
4187             get_arg(arg, sizeof(arg), &p);
4188             if (stream) {
4189                 video_enc.dark_masking = atof(arg);
4190             }
4191         } else if (!strcasecmp(cmd, "NoVideo")) {
4192             video_id = CODEC_ID_NONE;
4193         } else if (!strcasecmp(cmd, "NoAudio")) {
4194             audio_id = CODEC_ID_NONE;
4195         } else if (!strcasecmp(cmd, "ACL")) {
4196             IPAddressACL acl;
4197             struct hostent *he;
4198
4199             get_arg(arg, sizeof(arg), &p);
4200             if (strcasecmp(arg, "allow") == 0) {
4201                 acl.action = IP_ALLOW;
4202             } else if (strcasecmp(arg, "deny") == 0) {
4203                 acl.action = IP_DENY;
4204             } else {
4205                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4206                         filename, line_num, arg);
4207                 errors++;
4208             }
4209
4210             get_arg(arg, sizeof(arg), &p);
4211
4212             he = gethostbyname(arg);
4213             if (!he) {
4214                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4215                         filename, line_num, arg);
4216                 errors++;
4217             } else {
4218                 /* Only take the first */
4219                 acl.first.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4220                 acl.last = acl.first;
4221             }
4222
4223             get_arg(arg, sizeof(arg), &p);
4224
4225             if (arg[0]) {
4226                 he = gethostbyname(arg);
4227                 if (!he) {
4228                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4229                             filename, line_num, arg);
4230                     errors++;
4231                 } else {
4232                     /* Only take the first */
4233                     acl.last.s_addr = ntohl(((struct in_addr *) he->h_addr_list[0])->s_addr);
4234                 }
4235             }
4236
4237             if (!errors) {
4238                 IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl));
4239                 IPAddressACL **naclp = 0;
4240
4241                 *nacl = acl;
4242                 nacl->next = 0;
4243
4244                 if (stream) {
4245                     naclp = &stream->acl;
4246                 } else if (feed) {
4247                     naclp = &feed->acl;
4248                 } else {
4249                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4250                             filename, line_num);
4251                     errors++;
4252                 }
4253
4254                 if (naclp) {
4255                     while (*naclp)
4256                         naclp = &(*naclp)->next;
4257
4258                     *naclp = nacl;
4259                 }
4260             }
4261         } else if (!strcasecmp(cmd, "RTSPOption")) {
4262             get_arg(arg, sizeof(arg), &p);
4263             if (stream) {
4264                 av_freep(&stream->rtsp_option);
4265                 /* XXX: av_strdup ? */
4266                 stream->rtsp_option = av_malloc(strlen(arg) + 1);
4267                 if (stream->rtsp_option) {
4268                     strcpy(stream->rtsp_option, arg);
4269                 }
4270             }
4271         } else if (!strcasecmp(cmd, "MulticastAddress")) {
4272             get_arg(arg, sizeof(arg), &p);
4273             if (stream) {
4274                 if (!inet_aton(arg, &stream->multicast_ip)) {
4275                     fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
4276                             filename, line_num, arg);
4277                     errors++;
4278                 }
4279                 stream->is_multicast = 1;
4280                 stream->loop = 1; /* default is looping */
4281             }
4282         } else if (!strcasecmp(cmd, "MulticastPort")) {
4283             get_arg(arg, sizeof(arg), &p);
4284             if (stream) {
4285                 stream->multicast_port = atoi(arg);
4286             }
4287         } else if (!strcasecmp(cmd, "MulticastTTL")) {
4288             get_arg(arg, sizeof(arg), &p);
4289             if (stream) {
4290                 stream->multicast_ttl = atoi(arg);
4291             }
4292         } else if (!strcasecmp(cmd, "NoLoop")) {
4293             if (stream) {
4294                 stream->loop = 0;
4295             }
4296         } else if (!strcasecmp(cmd, "</Stream>")) {
4297             if (!stream) {
4298                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4299                         filename, line_num);
4300                 errors++;
4301             }
4302             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4303                 if (audio_id != CODEC_ID_NONE) {
4304                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
4305                     audio_enc.codec_id = audio_id;
4306                     add_codec(stream, &audio_enc);
4307                 }
4308                 if (video_id != CODEC_ID_NONE) {
4309                     video_enc.codec_type = CODEC_TYPE_VIDEO;
4310                     video_enc.codec_id = video_id;
4311                     add_codec(stream, &video_enc);
4312                 }
4313             }
4314             stream = NULL;
4315         } else if (!strcasecmp(cmd, "<Redirect")) {
4316             /*********************************************/
4317             char *q;
4318             if (stream || feed || redirect) {
4319                 fprintf(stderr, "%s:%d: Already in a tag\n",
4320                         filename, line_num);
4321                 errors++;
4322             } else {
4323                 redirect = av_mallocz(sizeof(FFStream));
4324                 *last_stream = redirect;
4325                 last_stream = &redirect->next;
4326
4327                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4328                 q = strrchr(redirect->filename, '>');
4329                 if (*q)
4330                     *q = '\0';
4331                 redirect->stream_type = STREAM_TYPE_REDIRECT;
4332             }
4333         } else if (!strcasecmp(cmd, "URL")) {
4334             if (redirect) {
4335                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4336             }
4337         } else if (!strcasecmp(cmd, "</Redirect>")) {
4338             if (!redirect) {
4339                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4340                         filename, line_num);
4341                 errors++;
4342             }
4343             if (!redirect->feed_filename[0]) {
4344                 fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4345                         filename, line_num);
4346                 errors++;
4347             }
4348             redirect = NULL;
4349         } else if (!strcasecmp(cmd, "LoadModule")) {
4350             get_arg(arg, sizeof(arg), &p);
4351 #ifdef CONFIG_HAVE_DLOPEN
4352             load_module(arg);
4353 #else
4354             fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n", 
4355                     filename, line_num, arg);
4356             errors++;
4357 #endif
4358         } else {
4359             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
4360                     filename, line_num, cmd);
4361             errors++;
4362         }
4363     }
4364
4365     fclose(f);
4366     if (errors)
4367         return -1;
4368     else
4369         return 0;
4370 }
4371
4372
4373 #if 0
4374 static void write_packet(FFCodec *ffenc,
4375                          uint8_t *buf, int size)
4376 {
4377     PacketHeader hdr;
4378     AVCodecContext *enc = &ffenc->enc;
4379     uint8_t *wptr;
4380     mk_header(&hdr, enc, size);
4381     wptr = http_fifo.wptr;
4382     fifo_write(&http_fifo, (uint8_t *)&hdr, sizeof(hdr), &wptr);
4383     fifo_write(&http_fifo, buf, size, &wptr);
4384     /* atomic modification of wptr */
4385     http_fifo.wptr = wptr;
4386     ffenc->data_count += size;
4387     ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
4388 }
4389 #endif
4390
4391 static void show_banner(void)
4392 {
4393     printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000-2003 Fabrice Bellard\n");
4394 }
4395
4396 static void show_help(void)
4397 {
4398     show_banner();
4399     printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4400            "Hyper fast multi format Audio/Video streaming server\n"
4401            "\n"
4402            "-L            : print the LICENSE\n"
4403            "-h            : this help\n"
4404            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4405            );
4406 }
4407
4408 static void show_license(void)
4409 {
4410     show_banner();
4411     printf(
4412     "This library is free software; you can redistribute it and/or\n"
4413     "modify it under the terms of the GNU Lesser General Public\n"
4414     "License as published by the Free Software Foundation; either\n"
4415     "version 2 of the License, or (at your option) any later version.\n"
4416     "\n"
4417     "This library is distributed in the hope that it will be useful,\n"
4418     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
4419     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
4420     "Lesser General Public License for more details.\n"
4421     "\n"
4422     "You should have received a copy of the GNU Lesser General Public\n"
4423     "License along with this library; if not, write to the Free Software\n"
4424     "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
4425     );
4426 }
4427
4428 static void handle_child_exit(int sig)
4429 {
4430     pid_t pid;
4431     int status;
4432
4433     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4434         FFStream *feed;
4435
4436         for (feed = first_feed; feed; feed = feed->next) {
4437             if (feed->pid == pid) {
4438                 int uptime = time(0) - feed->pid_start;
4439
4440                 feed->pid = 0;
4441                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4442
4443                 if (uptime < 30) {
4444                     /* Turn off any more restarts */
4445                     feed->child_argv = 0;
4446                 }    
4447             }
4448         }
4449     }
4450
4451     need_to_start_children = 1;
4452 }
4453
4454 int main(int argc, char **argv)
4455 {
4456     const char *config_filename;
4457     int c;
4458     struct sigaction sigact;
4459
4460     av_register_all();
4461
4462     config_filename = "/etc/ffserver.conf";
4463
4464     my_program_name = argv[0];
4465     my_program_dir = getcwd(0, 0);
4466     ffserver_daemon = 1;
4467     
4468     for(;;) {
4469         c = getopt(argc, argv, "ndLh?f:");
4470         if (c == -1)
4471             break;
4472         switch(c) {
4473         case 'L':
4474             show_license();
4475             exit(1);
4476         case '?':
4477         case 'h':
4478             show_help();
4479             exit(1);
4480         case 'n':
4481             no_launch = 1;
4482             break;
4483         case 'd':
4484             ffserver_debug = 1;
4485             ffserver_daemon = 0;
4486             break;
4487         case 'f':
4488             config_filename = optarg;
4489             break;
4490         default:
4491             exit(2);
4492         }
4493     }
4494
4495     putenv("http_proxy");               /* Kill the http_proxy */
4496
4497     srandom(gettime_ms() + (getpid() << 16));
4498
4499     /* address on which the server will handle HTTP connections */
4500     my_http_addr.sin_family = AF_INET;
4501     my_http_addr.sin_port = htons (8080);
4502     my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4503
4504     /* address on which the server will handle RTSP connections */
4505     my_rtsp_addr.sin_family = AF_INET;
4506     my_rtsp_addr.sin_port = htons (5454);
4507     my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4508     
4509     nb_max_connections = 5;
4510     max_bandwidth = 1000;
4511     first_stream = NULL;
4512     logfilename[0] = '\0';
4513
4514     memset(&sigact, 0, sizeof(sigact));
4515     sigact.sa_handler = handle_child_exit;
4516     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4517     sigaction(SIGCHLD, &sigact, 0);
4518
4519     if (parse_ffconfig(config_filename) < 0) {
4520         fprintf(stderr, "Incorrect config file - exiting.\n");
4521         exit(1);
4522     }
4523
4524     build_file_streams();
4525
4526     build_feed_streams();
4527
4528     compute_bandwidth();
4529
4530     /* put the process in background and detach it from its TTY */
4531     if (ffserver_daemon) {
4532         int pid;
4533
4534         pid = fork();
4535         if (pid < 0) {
4536             perror("fork");
4537             exit(1);
4538         } else if (pid > 0) {
4539             /* parent : exit */
4540             exit(0);
4541         } else {
4542             /* child */
4543             setsid();
4544             chdir("/");
4545             close(0);
4546             open("/dev/null", O_RDWR);
4547             if (strcmp(logfilename, "-") != 0) {
4548                 close(1);
4549                 dup(0);
4550             }
4551             close(2);
4552             dup(0);
4553         }
4554     }
4555
4556     /* signal init */
4557     signal(SIGPIPE, SIG_IGN);
4558
4559     /* open log file if needed */
4560     if (logfilename[0] != '\0') {
4561         if (!strcmp(logfilename, "-"))
4562             logfile = stdout;
4563         else
4564             logfile = fopen(logfilename, "w");
4565     }
4566
4567     if (http_server() < 0) {
4568         fprintf(stderr, "Could not start server\n");
4569         exit(1);
4570     }
4571
4572     return 0;
4573 }