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