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