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