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