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