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