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