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