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