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