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