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