]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - ffserver.c
new Truncate option which will make feeder truncate feed file
[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
2449     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2450     lseek(fd, 0, SEEK_SET);
2451
2452     /* init buffer input */
2453     c->buffer_ptr = c->buffer;
2454     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2455     c->stream->feed_opened = 1;
2456     return 0;
2457 }
2458
2459 static int http_receive_data(HTTPContext *c)
2460 {
2461     HTTPContext *c1;
2462
2463     if (c->buffer_end > c->buffer_ptr) {
2464         int len;
2465
2466         len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2467         if (len < 0) {
2468             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2469                 ff_neterrno() != FF_NETERROR(EINTR))
2470                 /* error : close connection */
2471                 goto fail;
2472         } else if (len == 0)
2473             /* end of connection : close it */
2474             goto fail;
2475         else {
2476             c->buffer_ptr += len;
2477             c->data_count += len;
2478             update_datarate(&c->datarate, c->data_count);
2479         }
2480     }
2481
2482     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2483         if (c->buffer[0] != 'f' ||
2484             c->buffer[1] != 'm') {
2485             http_log("Feed stream has become desynchronized -- disconnecting\n");
2486             goto fail;
2487         }
2488     }
2489
2490     if (c->buffer_ptr >= c->buffer_end) {
2491         FFStream *feed = c->stream;
2492         /* a packet has been received : write it in the store, except
2493            if header */
2494         if (c->data_count > FFM_PACKET_SIZE) {
2495
2496             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2497             /* XXX: use llseek or url_seek */
2498             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2499             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2500                 http_log("Error writing to feed file: %s\n", strerror(errno));
2501                 goto fail;
2502             }
2503
2504             feed->feed_write_index += FFM_PACKET_SIZE;
2505             /* update file size */
2506             if (feed->feed_write_index > c->stream->feed_size)
2507                 feed->feed_size = feed->feed_write_index;
2508
2509             /* handle wrap around if max file size reached */
2510             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2511                 feed->feed_write_index = FFM_PACKET_SIZE;
2512
2513             /* write index */
2514             if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2515                 http_log("Error writing index to feed file: %s\n", strerror(errno));
2516                 goto fail;
2517             }
2518
2519             /* wake up any waiting connections */
2520             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2521                 if (c1->state == HTTPSTATE_WAIT_FEED &&
2522                     c1->stream->feed == c->stream->feed)
2523                     c1->state = HTTPSTATE_SEND_DATA;
2524             }
2525         } else {
2526             /* We have a header in our hands that contains useful data */
2527             AVFormatContext *s = NULL;
2528             ByteIOContext *pb;
2529             AVInputFormat *fmt_in;
2530             int i;
2531
2532             /* use feed output format name to find corresponding input format */
2533             fmt_in = av_find_input_format(feed->fmt->name);
2534             if (!fmt_in)
2535                 goto fail;
2536
2537             url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2538             pb->is_streamed = 1;
2539
2540             if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2541                 av_free(pb);
2542                 goto fail;
2543             }
2544
2545             /* Now we have the actual streams */
2546             if (s->nb_streams != feed->nb_streams) {
2547                 av_close_input_stream(s);
2548                 av_free(pb);
2549                 http_log("Feed '%s' stream number does not match registered feed\n",
2550                          c->stream->feed_filename);
2551                 goto fail;
2552             }
2553
2554             for (i = 0; i < s->nb_streams; i++) {
2555                 AVStream *fst = feed->streams[i];
2556                 AVStream *st = s->streams[i];
2557                 memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2558                 if (fst->codec->extradata_size) {
2559                     fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2560                     if (!fst->codec->extradata)
2561                         goto fail;
2562                     memcpy(fst->codec->extradata, st->codec->extradata,
2563                            fst->codec->extradata_size);
2564                 }
2565             }
2566
2567             av_close_input_stream(s);
2568             av_free(pb);
2569         }
2570         c->buffer_ptr = c->buffer;
2571     }
2572
2573     return 0;
2574  fail:
2575     c->stream->feed_opened = 0;
2576     close(c->feed_fd);
2577     /* wake up any waiting connections to stop waiting for feed */
2578     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2579         if (c1->state == HTTPSTATE_WAIT_FEED &&
2580             c1->stream->feed == c->stream->feed)
2581             c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2582     }
2583     return -1;
2584 }
2585
2586 /********************************************************************/
2587 /* RTSP handling */
2588
2589 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2590 {
2591     const char *str;
2592     time_t ti;
2593     char *p;
2594     char buf2[32];
2595
2596     switch(error_number) {
2597     case RTSP_STATUS_OK:
2598         str = "OK";
2599         break;
2600     case RTSP_STATUS_METHOD:
2601         str = "Method Not Allowed";
2602         break;
2603     case RTSP_STATUS_BANDWIDTH:
2604         str = "Not Enough Bandwidth";
2605         break;
2606     case RTSP_STATUS_SESSION:
2607         str = "Session Not Found";
2608         break;
2609     case RTSP_STATUS_STATE:
2610         str = "Method Not Valid in This State";
2611         break;
2612     case RTSP_STATUS_AGGREGATE:
2613         str = "Aggregate operation not allowed";
2614         break;
2615     case RTSP_STATUS_ONLY_AGGREGATE:
2616         str = "Only aggregate operation allowed";
2617         break;
2618     case RTSP_STATUS_TRANSPORT:
2619         str = "Unsupported transport";
2620         break;
2621     case RTSP_STATUS_INTERNAL:
2622         str = "Internal Server Error";
2623         break;
2624     case RTSP_STATUS_SERVICE:
2625         str = "Service Unavailable";
2626         break;
2627     case RTSP_STATUS_VERSION:
2628         str = "RTSP Version not supported";
2629         break;
2630     default:
2631         str = "Unknown Error";
2632         break;
2633     }
2634
2635     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2636     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2637
2638     /* output GMT time */
2639     ti = time(NULL);
2640     p = ctime(&ti);
2641     strcpy(buf2, p);
2642     p = buf2 + strlen(p) - 1;
2643     if (*p == '\n')
2644         *p = '\0';
2645     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2646 }
2647
2648 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2649 {
2650     rtsp_reply_header(c, error_number);
2651     url_fprintf(c->pb, "\r\n");
2652 }
2653
2654 static int rtsp_parse_request(HTTPContext *c)
2655 {
2656     const char *p, *p1, *p2;
2657     char cmd[32];
2658     char url[1024];
2659     char protocol[32];
2660     char line[1024];
2661     int len;
2662     RTSPMessageHeader header1, *header = &header1;
2663
2664     c->buffer_ptr[0] = '\0';
2665     p = c->buffer;
2666
2667     get_word(cmd, sizeof(cmd), &p);
2668     get_word(url, sizeof(url), &p);
2669     get_word(protocol, sizeof(protocol), &p);
2670
2671     av_strlcpy(c->method, cmd, sizeof(c->method));
2672     av_strlcpy(c->url, url, sizeof(c->url));
2673     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2674
2675     if (url_open_dyn_buf(&c->pb) < 0) {
2676         /* XXX: cannot do more */
2677         c->pb = NULL; /* safety */
2678         return -1;
2679     }
2680
2681     /* check version name */
2682     if (strcmp(protocol, "RTSP/1.0") != 0) {
2683         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2684         goto the_end;
2685     }
2686
2687     /* parse each header line */
2688     memset(header, 0, sizeof(*header));
2689     /* skip to next line */
2690     while (*p != '\n' && *p != '\0')
2691         p++;
2692     if (*p == '\n')
2693         p++;
2694     while (*p != '\0') {
2695         p1 = strchr(p, '\n');
2696         if (!p1)
2697             break;
2698         p2 = p1;
2699         if (p2 > p && p2[-1] == '\r')
2700             p2--;
2701         /* skip empty line */
2702         if (p2 == p)
2703             break;
2704         len = p2 - p;
2705         if (len > sizeof(line) - 1)
2706             len = sizeof(line) - 1;
2707         memcpy(line, p, len);
2708         line[len] = '\0';
2709         rtsp_parse_line(header, line);
2710         p = p1 + 1;
2711     }
2712
2713     /* handle sequence number */
2714     c->seq = header->seq;
2715
2716     if (!strcmp(cmd, "DESCRIBE"))
2717         rtsp_cmd_describe(c, url);
2718     else if (!strcmp(cmd, "OPTIONS"))
2719         rtsp_cmd_options(c, url);
2720     else if (!strcmp(cmd, "SETUP"))
2721         rtsp_cmd_setup(c, url, header);
2722     else if (!strcmp(cmd, "PLAY"))
2723         rtsp_cmd_play(c, url, header);
2724     else if (!strcmp(cmd, "PAUSE"))
2725         rtsp_cmd_pause(c, url, header);
2726     else if (!strcmp(cmd, "TEARDOWN"))
2727         rtsp_cmd_teardown(c, url, header);
2728     else
2729         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2730
2731  the_end:
2732     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2733     c->pb = NULL; /* safety */
2734     if (len < 0) {
2735         /* XXX: cannot do more */
2736         return -1;
2737     }
2738     c->buffer_ptr = c->pb_buffer;
2739     c->buffer_end = c->pb_buffer + len;
2740     c->state = RTSPSTATE_SEND_REPLY;
2741     return 0;
2742 }
2743
2744 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2745                                    struct in_addr my_ip)
2746 {
2747     AVFormatContext *avc;
2748     AVStream avs[MAX_STREAMS];
2749     int i;
2750
2751     avc =  avformat_alloc_context();
2752     if (avc == NULL) {
2753         return -1;
2754     }
2755     av_metadata_set(&avc->metadata, "title",
2756                     stream->title[0] ? stream->title : "No Title");
2757     avc->nb_streams = stream->nb_streams;
2758     if (stream->is_multicast) {
2759         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2760                  inet_ntoa(stream->multicast_ip),
2761                  stream->multicast_port, stream->multicast_ttl);
2762     }
2763
2764     for(i = 0; i < stream->nb_streams; i++) {
2765         avc->streams[i] = &avs[i];
2766         avc->streams[i]->codec = stream->streams[i]->codec;
2767     }
2768     *pbuffer = av_mallocz(2048);
2769     avf_sdp_create(&avc, 1, *pbuffer, 2048);
2770     av_free(avc);
2771
2772     return strlen(*pbuffer);
2773 }
2774
2775 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2776 {
2777 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2778     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2779     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2780     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2781     url_fprintf(c->pb, "\r\n");
2782 }
2783
2784 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2785 {
2786     FFStream *stream;
2787     char path1[1024];
2788     const char *path;
2789     uint8_t *content;
2790     int content_length, len;
2791     struct sockaddr_in my_addr;
2792
2793     /* find which url is asked */
2794     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2795     path = path1;
2796     if (*path == '/')
2797         path++;
2798
2799     for(stream = first_stream; stream != NULL; stream = stream->next) {
2800         if (!stream->is_feed &&
2801             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2802             !strcmp(path, stream->filename)) {
2803             goto found;
2804         }
2805     }
2806     /* no stream found */
2807     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2808     return;
2809
2810  found:
2811     /* prepare the media description in sdp format */
2812
2813     /* get the host IP */
2814     len = sizeof(my_addr);
2815     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2816     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2817     if (content_length < 0) {
2818         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2819         return;
2820     }
2821     rtsp_reply_header(c, RTSP_STATUS_OK);
2822     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2823     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2824     url_fprintf(c->pb, "\r\n");
2825     put_buffer(c->pb, content, content_length);
2826 }
2827
2828 static HTTPContext *find_rtp_session(const char *session_id)
2829 {
2830     HTTPContext *c;
2831
2832     if (session_id[0] == '\0')
2833         return NULL;
2834
2835     for(c = first_http_ctx; c != NULL; c = c->next) {
2836         if (!strcmp(c->session_id, session_id))
2837             return c;
2838     }
2839     return NULL;
2840 }
2841
2842 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2843 {
2844     RTSPTransportField *th;
2845     int i;
2846
2847     for(i=0;i<h->nb_transports;i++) {
2848         th = &h->transports[i];
2849         if (th->lower_transport == lower_transport)
2850             return th;
2851     }
2852     return NULL;
2853 }
2854
2855 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2856                            RTSPMessageHeader *h)
2857 {
2858     FFStream *stream;
2859     int stream_index, port;
2860     char buf[1024];
2861     char path1[1024];
2862     const char *path;
2863     HTTPContext *rtp_c;
2864     RTSPTransportField *th;
2865     struct sockaddr_in dest_addr;
2866     RTSPActionServerSetup setup;
2867
2868     /* find which url is asked */
2869     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2870     path = path1;
2871     if (*path == '/')
2872         path++;
2873
2874     /* now check each stream */
2875     for(stream = first_stream; stream != NULL; stream = stream->next) {
2876         if (!stream->is_feed &&
2877             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2878             /* accept aggregate filenames only if single stream */
2879             if (!strcmp(path, stream->filename)) {
2880                 if (stream->nb_streams != 1) {
2881                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2882                     return;
2883                 }
2884                 stream_index = 0;
2885                 goto found;
2886             }
2887
2888             for(stream_index = 0; stream_index < stream->nb_streams;
2889                 stream_index++) {
2890                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2891                          stream->filename, stream_index);
2892                 if (!strcmp(path, buf))
2893                     goto found;
2894             }
2895         }
2896     }
2897     /* no stream found */
2898     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2899     return;
2900  found:
2901
2902     /* generate session id if needed */
2903     if (h->session_id[0] == '\0')
2904         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2905                  av_lfg_get(&random_state), av_lfg_get(&random_state));
2906
2907     /* find rtp session, and create it if none found */
2908     rtp_c = find_rtp_session(h->session_id);
2909     if (!rtp_c) {
2910         /* always prefer UDP */
2911         th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2912         if (!th) {
2913             th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2914             if (!th) {
2915                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2916                 return;
2917             }
2918         }
2919
2920         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2921                                    th->lower_transport);
2922         if (!rtp_c) {
2923             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2924             return;
2925         }
2926
2927         /* open input stream */
2928         if (open_input_stream(rtp_c, "") < 0) {
2929             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2930             return;
2931         }
2932     }
2933
2934     /* test if stream is OK (test needed because several SETUP needs
2935        to be done for a given file) */
2936     if (rtp_c->stream != stream) {
2937         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2938         return;
2939     }
2940
2941     /* test if stream is already set up */
2942     if (rtp_c->rtp_ctx[stream_index]) {
2943         rtsp_reply_error(c, RTSP_STATUS_STATE);
2944         return;
2945     }
2946
2947     /* check transport */
2948     th = find_transport(h, rtp_c->rtp_protocol);
2949     if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2950                 th->client_port_min <= 0)) {
2951         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2952         return;
2953     }
2954
2955     /* setup default options */
2956     setup.transport_option[0] = '\0';
2957     dest_addr = rtp_c->from_addr;
2958     dest_addr.sin_port = htons(th->client_port_min);
2959
2960     /* setup stream */
2961     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2962         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2963         return;
2964     }
2965
2966     /* now everything is OK, so we can send the connection parameters */
2967     rtsp_reply_header(c, RTSP_STATUS_OK);
2968     /* session ID */
2969     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2970
2971     switch(rtp_c->rtp_protocol) {
2972     case RTSP_LOWER_TRANSPORT_UDP:
2973         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2974         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2975                     "client_port=%d-%d;server_port=%d-%d",
2976                     th->client_port_min, th->client_port_min + 1,
2977                     port, port + 1);
2978         break;
2979     case RTSP_LOWER_TRANSPORT_TCP:
2980         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2981                     stream_index * 2, stream_index * 2 + 1);
2982         break;
2983     default:
2984         break;
2985     }
2986     if (setup.transport_option[0] != '\0')
2987         url_fprintf(c->pb, ";%s", setup.transport_option);
2988     url_fprintf(c->pb, "\r\n");
2989
2990
2991     url_fprintf(c->pb, "\r\n");
2992 }
2993
2994
2995 /* find an rtp connection by using the session ID. Check consistency
2996    with filename */
2997 static HTTPContext *find_rtp_session_with_url(const char *url,
2998                                               const char *session_id)
2999 {
3000     HTTPContext *rtp_c;
3001     char path1[1024];
3002     const char *path;
3003     char buf[1024];
3004     int s;
3005
3006     rtp_c = find_rtp_session(session_id);
3007     if (!rtp_c)
3008         return NULL;
3009
3010     /* find which url is asked */
3011     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3012     path = path1;
3013     if (*path == '/')
3014         path++;
3015     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3016     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3017       snprintf(buf, sizeof(buf), "%s/streamid=%d",
3018         rtp_c->stream->filename, s);
3019       if(!strncmp(path, buf, sizeof(buf))) {
3020     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3021         return rtp_c;
3022       }
3023     }
3024     return NULL;
3025 }
3026
3027 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3028 {
3029     HTTPContext *rtp_c;
3030
3031     rtp_c = find_rtp_session_with_url(url, h->session_id);
3032     if (!rtp_c) {
3033         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3034         return;
3035     }
3036
3037     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3038         rtp_c->state != HTTPSTATE_WAIT_FEED &&
3039         rtp_c->state != HTTPSTATE_READY) {
3040         rtsp_reply_error(c, RTSP_STATUS_STATE);
3041         return;
3042     }
3043
3044 #if 0
3045     /* XXX: seek in stream */
3046     if (h->range_start != AV_NOPTS_VALUE) {
3047         printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3048         av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3049     }
3050 #endif
3051
3052     rtp_c->state = HTTPSTATE_SEND_DATA;
3053
3054     /* now everything is OK, so we can send the connection parameters */
3055     rtsp_reply_header(c, RTSP_STATUS_OK);
3056     /* session ID */
3057     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3058     url_fprintf(c->pb, "\r\n");
3059 }
3060
3061 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3062 {
3063     HTTPContext *rtp_c;
3064
3065     rtp_c = find_rtp_session_with_url(url, h->session_id);
3066     if (!rtp_c) {
3067         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3068         return;
3069     }
3070
3071     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3072         rtp_c->state != HTTPSTATE_WAIT_FEED) {
3073         rtsp_reply_error(c, RTSP_STATUS_STATE);
3074         return;
3075     }
3076
3077     rtp_c->state = HTTPSTATE_READY;
3078     rtp_c->first_pts = AV_NOPTS_VALUE;
3079     /* now everything is OK, so we can send the connection parameters */
3080     rtsp_reply_header(c, RTSP_STATUS_OK);
3081     /* session ID */
3082     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3083     url_fprintf(c->pb, "\r\n");
3084 }
3085
3086 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3087 {
3088     HTTPContext *rtp_c;
3089     char session_id[32];
3090
3091     rtp_c = find_rtp_session_with_url(url, h->session_id);
3092     if (!rtp_c) {
3093         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3094         return;
3095     }
3096
3097     av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3098
3099     /* abort the session */
3100     close_connection(rtp_c);
3101
3102     /* now everything is OK, so we can send the connection parameters */
3103     rtsp_reply_header(c, RTSP_STATUS_OK);
3104     /* session ID */
3105     url_fprintf(c->pb, "Session: %s\r\n", session_id);
3106     url_fprintf(c->pb, "\r\n");
3107 }
3108
3109
3110 /********************************************************************/
3111 /* RTP handling */
3112
3113 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3114                                        FFStream *stream, const char *session_id,
3115                                        enum RTSPLowerTransport rtp_protocol)
3116 {
3117     HTTPContext *c = NULL;
3118     const char *proto_str;
3119
3120     /* XXX: should output a warning page when coming
3121        close to the connection limit */
3122     if (nb_connections >= nb_max_connections)
3123         goto fail;
3124
3125     /* add a new connection */
3126     c = av_mallocz(sizeof(HTTPContext));
3127     if (!c)
3128         goto fail;
3129
3130     c->fd = -1;
3131     c->poll_entry = NULL;
3132     c->from_addr = *from_addr;
3133     c->buffer_size = IOBUFFER_INIT_SIZE;
3134     c->buffer = av_malloc(c->buffer_size);
3135     if (!c->buffer)
3136         goto fail;
3137     nb_connections++;
3138     c->stream = stream;
3139     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3140     c->state = HTTPSTATE_READY;
3141     c->is_packetized = 1;
3142     c->rtp_protocol = rtp_protocol;
3143
3144     /* protocol is shown in statistics */
3145     switch(c->rtp_protocol) {
3146     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3147         proto_str = "MCAST";
3148         break;
3149     case RTSP_LOWER_TRANSPORT_UDP:
3150         proto_str = "UDP";
3151         break;
3152     case RTSP_LOWER_TRANSPORT_TCP:
3153         proto_str = "TCP";
3154         break;
3155     default:
3156         proto_str = "???";
3157         break;
3158     }
3159     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3160     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3161
3162     current_bandwidth += stream->bandwidth;
3163
3164     c->next = first_http_ctx;
3165     first_http_ctx = c;
3166     return c;
3167
3168  fail:
3169     if (c) {
3170         av_free(c->buffer);
3171         av_free(c);
3172     }
3173     return NULL;
3174 }
3175
3176 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3177    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3178    used. */
3179 static int rtp_new_av_stream(HTTPContext *c,
3180                              int stream_index, struct sockaddr_in *dest_addr,
3181                              HTTPContext *rtsp_c)
3182 {
3183     AVFormatContext *ctx;
3184     AVStream *st;
3185     char *ipaddr;
3186     URLContext *h = NULL;
3187     uint8_t *dummy_buf;
3188     int max_packet_size;
3189
3190     /* now we can open the relevant output stream */
3191     ctx = avformat_alloc_context();
3192     if (!ctx)
3193         return -1;
3194     ctx->oformat = guess_format("rtp", NULL, NULL);
3195
3196     st = av_mallocz(sizeof(AVStream));
3197     if (!st)
3198         goto fail;
3199     st->codec= avcodec_alloc_context();
3200     ctx->nb_streams = 1;
3201     ctx->streams[0] = st;
3202
3203     if (!c->stream->feed ||
3204         c->stream->feed == c->stream)
3205         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3206     else
3207         memcpy(st,
3208                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3209                sizeof(AVStream));
3210     st->priv_data = NULL;
3211
3212     /* build destination RTP address */
3213     ipaddr = inet_ntoa(dest_addr->sin_addr);
3214
3215     switch(c->rtp_protocol) {
3216     case RTSP_LOWER_TRANSPORT_UDP:
3217     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3218         /* RTP/UDP case */
3219
3220         /* XXX: also pass as parameter to function ? */
3221         if (c->stream->is_multicast) {
3222             int ttl;
3223             ttl = c->stream->multicast_ttl;
3224             if (!ttl)
3225                 ttl = 16;
3226             snprintf(ctx->filename, sizeof(ctx->filename),
3227                      "rtp://%s:%d?multicast=1&ttl=%d",
3228                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3229         } else {
3230             snprintf(ctx->filename, sizeof(ctx->filename),
3231                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3232         }
3233
3234         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3235             goto fail;
3236         c->rtp_handles[stream_index] = h;
3237         max_packet_size = url_get_max_packet_size(h);
3238         break;
3239     case RTSP_LOWER_TRANSPORT_TCP:
3240         /* RTP/TCP case */
3241         c->rtsp_c = rtsp_c;
3242         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3243         break;
3244     default:
3245         goto fail;
3246     }
3247
3248     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3249              ipaddr, ntohs(dest_addr->sin_port),
3250              c->stream->filename, stream_index, c->protocol);
3251
3252     /* normally, no packets should be output here, but the packet size may be checked */
3253     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3254         /* XXX: close stream */
3255         goto fail;
3256     }
3257     av_set_parameters(ctx, NULL);
3258     if (av_write_header(ctx) < 0) {
3259     fail:
3260         if (h)
3261             url_close(h);
3262         av_free(ctx);
3263         return -1;
3264     }
3265     url_close_dyn_buf(ctx->pb, &dummy_buf);
3266     av_free(dummy_buf);
3267
3268     c->rtp_ctx[stream_index] = ctx;
3269     return 0;
3270 }
3271
3272 /********************************************************************/
3273 /* ffserver initialization */
3274
3275 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3276 {
3277     AVStream *fst;
3278
3279     fst = av_mallocz(sizeof(AVStream));
3280     if (!fst)
3281         return NULL;
3282     fst->codec= avcodec_alloc_context();
3283     fst->priv_data = av_mallocz(sizeof(FeedData));
3284     memcpy(fst->codec, codec, sizeof(AVCodecContext));
3285     fst->index = stream->nb_streams;
3286     av_set_pts_info(fst, 33, 1, 90000);
3287     stream->streams[stream->nb_streams++] = fst;
3288     return fst;
3289 }
3290
3291 /* return the stream number in the feed */
3292 static int add_av_stream(FFStream *feed, AVStream *st)
3293 {
3294     AVStream *fst;
3295     AVCodecContext *av, *av1;
3296     int i;
3297
3298     av = st->codec;
3299     for(i=0;i<feed->nb_streams;i++) {
3300         st = feed->streams[i];
3301         av1 = st->codec;
3302         if (av1->codec_id == av->codec_id &&
3303             av1->codec_type == av->codec_type &&
3304             av1->bit_rate == av->bit_rate) {
3305
3306             switch(av->codec_type) {
3307             case CODEC_TYPE_AUDIO:
3308                 if (av1->channels == av->channels &&
3309                     av1->sample_rate == av->sample_rate)
3310                     goto found;
3311                 break;
3312             case CODEC_TYPE_VIDEO:
3313                 if (av1->width == av->width &&
3314                     av1->height == av->height &&
3315                     av1->time_base.den == av->time_base.den &&
3316                     av1->time_base.num == av->time_base.num &&
3317                     av1->gop_size == av->gop_size)
3318                     goto found;
3319                 break;
3320             default:
3321                 abort();
3322             }
3323         }
3324     }
3325
3326     fst = add_av_stream1(feed, av);
3327     if (!fst)
3328         return -1;
3329     return feed->nb_streams - 1;
3330  found:
3331     return i;
3332 }
3333
3334 static void remove_stream(FFStream *stream)
3335 {
3336     FFStream **ps;
3337     ps = &first_stream;
3338     while (*ps != NULL) {
3339         if (*ps == stream)
3340             *ps = (*ps)->next;
3341         else
3342             ps = &(*ps)->next;
3343     }
3344 }
3345
3346 /* specific mpeg4 handling : we extract the raw parameters */
3347 static void extract_mpeg4_header(AVFormatContext *infile)
3348 {
3349     int mpeg4_count, i, size;
3350     AVPacket pkt;
3351     AVStream *st;
3352     const uint8_t *p;
3353
3354     mpeg4_count = 0;
3355     for(i=0;i<infile->nb_streams;i++) {
3356         st = infile->streams[i];
3357         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3358             st->codec->extradata_size == 0) {
3359             mpeg4_count++;
3360         }
3361     }
3362     if (!mpeg4_count)
3363         return;
3364
3365     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3366     while (mpeg4_count > 0) {
3367         if (av_read_packet(infile, &pkt) < 0)
3368             break;
3369         st = infile->streams[pkt.stream_index];
3370         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3371             st->codec->extradata_size == 0) {
3372             av_freep(&st->codec->extradata);
3373             /* fill extradata with the header */
3374             /* XXX: we make hard suppositions here ! */
3375             p = pkt.data;
3376             while (p < pkt.data + pkt.size - 4) {
3377                 /* stop when vop header is found */
3378                 if (p[0] == 0x00 && p[1] == 0x00 &&
3379                     p[2] == 0x01 && p[3] == 0xb6) {
3380                     size = p - pkt.data;
3381                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3382                     st->codec->extradata = av_malloc(size);
3383                     st->codec->extradata_size = size;
3384                     memcpy(st->codec->extradata, pkt.data, size);
3385                     break;
3386                 }
3387                 p++;
3388             }
3389             mpeg4_count--;
3390         }
3391         av_free_packet(&pkt);
3392     }
3393 }
3394
3395 /* compute the needed AVStream for each file */
3396 static void build_file_streams(void)
3397 {
3398     FFStream *stream, *stream_next;
3399     AVFormatContext *infile;
3400     int i, ret;
3401
3402     /* gather all streams */
3403     for(stream = first_stream; stream != NULL; stream = stream_next) {
3404         stream_next = stream->next;
3405         if (stream->stream_type == STREAM_TYPE_LIVE &&
3406             !stream->feed) {
3407             /* the stream comes from a file */
3408             /* try to open the file */
3409             /* open stream */
3410             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3411             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3412                 /* specific case : if transport stream output to RTP,
3413                    we use a raw transport stream reader */
3414                 stream->ap_in->mpeg2ts_raw = 1;
3415                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3416             }
3417
3418             http_log("Opening file '%s'\n", stream->feed_filename);
3419             if ((ret = av_open_input_file(&infile, stream->feed_filename,
3420                                           stream->ifmt, 0, stream->ap_in)) < 0) {
3421                 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3422                 /* remove stream (no need to spend more time on it) */
3423             fail:
3424                 remove_stream(stream);
3425             } else {
3426                 /* find all the AVStreams inside and reference them in
3427                    'stream' */
3428                 if (av_find_stream_info(infile) < 0) {
3429                     http_log("Could not find codec parameters from '%s'\n",
3430                              stream->feed_filename);
3431                     av_close_input_file(infile);
3432                     goto fail;
3433                 }
3434                 extract_mpeg4_header(infile);
3435
3436                 for(i=0;i<infile->nb_streams;i++)
3437                     add_av_stream1(stream, infile->streams[i]->codec);
3438
3439                 av_close_input_file(infile);
3440             }
3441         }
3442     }
3443 }
3444
3445 /* compute the needed AVStream for each feed */
3446 static void build_feed_streams(void)
3447 {
3448     FFStream *stream, *feed;
3449     int i;
3450
3451     /* gather all streams */
3452     for(stream = first_stream; stream != NULL; stream = stream->next) {
3453         feed = stream->feed;
3454         if (feed) {
3455             if (!stream->is_feed) {
3456                 /* we handle a stream coming from a feed */
3457                 for(i=0;i<stream->nb_streams;i++)
3458                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3459             }
3460         }
3461     }
3462
3463     /* gather all streams */
3464     for(stream = first_stream; stream != NULL; stream = stream->next) {
3465         feed = stream->feed;
3466         if (feed) {
3467             if (stream->is_feed) {
3468                 for(i=0;i<stream->nb_streams;i++)
3469                     stream->feed_streams[i] = i;
3470             }
3471         }
3472     }
3473
3474     /* create feed files if needed */
3475     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3476         int fd;
3477
3478         if (url_exist(feed->feed_filename)) {
3479             /* See if it matches */
3480             AVFormatContext *s;
3481             int matches = 0;
3482
3483             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3484                 /* Now see if it matches */
3485                 if (s->nb_streams == feed->nb_streams) {
3486                     matches = 1;
3487                     for(i=0;i<s->nb_streams;i++) {
3488                         AVStream *sf, *ss;
3489                         sf = feed->streams[i];
3490                         ss = s->streams[i];
3491
3492                         if (sf->index != ss->index ||
3493                             sf->id != ss->id) {
3494                             http_log("Index & Id do not match for stream %d (%s)\n",
3495                                    i, feed->feed_filename);
3496                             matches = 0;
3497                         } else {
3498                             AVCodecContext *ccf, *ccs;
3499
3500                             ccf = sf->codec;
3501                             ccs = ss->codec;
3502 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3503
3504                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3505                                 http_log("Codecs do not match for stream %d\n", i);
3506                                 matches = 0;
3507                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3508                                 http_log("Codec bitrates do not match for stream %d\n", i);
3509                                 matches = 0;
3510                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3511                                 if (CHECK_CODEC(time_base.den) ||
3512                                     CHECK_CODEC(time_base.num) ||
3513                                     CHECK_CODEC(width) ||
3514                                     CHECK_CODEC(height)) {
3515                                     http_log("Codec width, height and framerate do not match for stream %d\n", i);
3516                                     matches = 0;
3517                                 }
3518                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3519                                 if (CHECK_CODEC(sample_rate) ||
3520                                     CHECK_CODEC(channels) ||
3521                                     CHECK_CODEC(frame_size)) {
3522                                     http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3523                                     matches = 0;
3524                                 }
3525                             } else {
3526                                 http_log("Unknown codec type\n");
3527                                 matches = 0;
3528                             }
3529                         }
3530                         if (!matches)
3531                             break;
3532                     }
3533                 } else
3534                     http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3535                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3536
3537                 av_close_input_file(s);
3538             } else
3539                 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3540                         feed->feed_filename);
3541
3542             if (!matches) {
3543                 if (feed->readonly) {
3544                     http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3545                         feed->feed_filename);
3546                     exit(1);
3547                 }
3548                 unlink(feed->feed_filename);
3549             }
3550         }
3551         if (!url_exist(feed->feed_filename)) {
3552             AVFormatContext s1 = {0}, *s = &s1;
3553
3554             if (feed->readonly) {
3555                 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3556                     feed->feed_filename);
3557                 exit(1);
3558             }
3559
3560             /* only write the header of the ffm file */
3561             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3562                 http_log("Could not open output feed file '%s'\n",
3563                          feed->feed_filename);
3564                 exit(1);
3565             }
3566             s->oformat = feed->fmt;
3567             s->nb_streams = feed->nb_streams;
3568             for(i=0;i<s->nb_streams;i++) {
3569                 AVStream *st;
3570                 st = feed->streams[i];
3571                 s->streams[i] = st;
3572             }
3573             av_set_parameters(s, NULL);
3574             if (av_write_header(s) < 0) {
3575                 http_log("Container doesn't supports the required parameters\n");
3576                 exit(1);
3577             }
3578             /* XXX: need better api */
3579             av_freep(&s->priv_data);
3580             url_fclose(s->pb);
3581         }
3582         /* get feed size and write index */
3583         fd = open(feed->feed_filename, O_RDONLY);
3584         if (fd < 0) {
3585             http_log("Could not open output feed file '%s'\n",
3586                     feed->feed_filename);
3587             exit(1);
3588         }
3589
3590         feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3591         feed->feed_size = lseek(fd, 0, SEEK_END);
3592         /* ensure that we do not wrap before the end of file */
3593         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3594             feed->feed_max_size = feed->feed_size;
3595
3596         close(fd);
3597     }
3598 }
3599
3600 /* compute the bandwidth used by each stream */
3601 static void compute_bandwidth(void)
3602 {
3603     unsigned bandwidth;
3604     int i;
3605     FFStream *stream;
3606
3607     for(stream = first_stream; stream != NULL; stream = stream->next) {
3608         bandwidth = 0;
3609         for(i=0;i<stream->nb_streams;i++) {
3610             AVStream *st = stream->streams[i];
3611             switch(st->codec->codec_type) {
3612             case CODEC_TYPE_AUDIO:
3613             case CODEC_TYPE_VIDEO:
3614                 bandwidth += st->codec->bit_rate;
3615                 break;
3616             default:
3617                 break;
3618             }
3619         }
3620         stream->bandwidth = (bandwidth + 999) / 1000;
3621     }
3622 }
3623
3624 static void get_arg(char *buf, int buf_size, const char **pp)
3625 {
3626     const char *p;
3627     char *q;
3628     int quote;
3629
3630     p = *pp;
3631     while (isspace(*p)) p++;
3632     q = buf;
3633     quote = 0;
3634     if (*p == '\"' || *p == '\'')
3635         quote = *p++;
3636     for(;;) {
3637         if (quote) {
3638             if (*p == quote)
3639                 break;
3640         } else {
3641             if (isspace(*p))
3642                 break;
3643         }
3644         if (*p == '\0')
3645             break;
3646         if ((q - buf) < buf_size - 1)
3647             *q++ = *p;
3648         p++;
3649     }
3650     *q = '\0';
3651     if (quote && *p == quote)
3652         p++;
3653     *pp = p;
3654 }
3655
3656 /* add a codec and set the default parameters */
3657 static void add_codec(FFStream *stream, AVCodecContext *av)
3658 {
3659     AVStream *st;
3660
3661     /* compute default parameters */
3662     switch(av->codec_type) {
3663     case CODEC_TYPE_AUDIO:
3664         if (av->bit_rate == 0)
3665             av->bit_rate = 64000;
3666         if (av->sample_rate == 0)
3667             av->sample_rate = 22050;
3668         if (av->channels == 0)
3669             av->channels = 1;
3670         break;
3671     case CODEC_TYPE_VIDEO:
3672         if (av->bit_rate == 0)
3673             av->bit_rate = 64000;
3674         if (av->time_base.num == 0){
3675             av->time_base.den = 5;
3676             av->time_base.num = 1;
3677         }
3678         if (av->width == 0 || av->height == 0) {
3679             av->width = 160;
3680             av->height = 128;
3681         }
3682         /* Bitrate tolerance is less for streaming */
3683         if (av->bit_rate_tolerance == 0)
3684             av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3685                       (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3686         if (av->qmin == 0)
3687             av->qmin = 3;
3688         if (av->qmax == 0)
3689             av->qmax = 31;
3690         if (av->max_qdiff == 0)
3691             av->max_qdiff = 3;
3692         av->qcompress = 0.5;
3693         av->qblur = 0.5;
3694
3695         if (!av->nsse_weight)
3696             av->nsse_weight = 8;
3697
3698         av->frame_skip_cmp = FF_CMP_DCTMAX;
3699         av->me_method = ME_EPZS;
3700         av->rc_buffer_aggressivity = 1.0;
3701
3702         if (!av->rc_eq)
3703             av->rc_eq = "tex^qComp";
3704         if (!av->i_quant_factor)
3705             av->i_quant_factor = -0.8;
3706         if (!av->b_quant_factor)
3707             av->b_quant_factor = 1.25;
3708         if (!av->b_quant_offset)
3709             av->b_quant_offset = 1.25;
3710         if (!av->rc_max_rate)
3711             av->rc_max_rate = av->bit_rate * 2;
3712
3713         if (av->rc_max_rate && !av->rc_buffer_size) {
3714             av->rc_buffer_size = av->rc_max_rate;
3715         }
3716
3717
3718         break;
3719     default:
3720         abort();
3721     }
3722
3723     st = av_mallocz(sizeof(AVStream));
3724     if (!st)
3725         return;
3726     st->codec = avcodec_alloc_context();
3727     stream->streams[stream->nb_streams++] = st;
3728     memcpy(st->codec, av, sizeof(AVCodecContext));
3729 }
3730
3731 static enum CodecID opt_audio_codec(const char *arg)
3732 {
3733     AVCodec *p= avcodec_find_encoder_by_name(arg);
3734
3735     if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3736         return CODEC_ID_NONE;
3737
3738     return p->id;
3739 }
3740
3741 static enum CodecID opt_video_codec(const char *arg)
3742 {
3743     AVCodec *p= avcodec_find_encoder_by_name(arg);
3744
3745     if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3746         return CODEC_ID_NONE;
3747
3748     return p->id;
3749 }
3750
3751 /* simplistic plugin support */
3752
3753 #if HAVE_DLOPEN
3754 static void load_module(const char *filename)
3755 {
3756     void *dll;
3757     void (*init_func)(void);
3758     dll = dlopen(filename, RTLD_NOW);
3759     if (!dll) {
3760         fprintf(stderr, "Could not load module '%s' - %s\n",
3761                 filename, dlerror());
3762         return;
3763     }
3764
3765     init_func = dlsym(dll, "ffserver_module_init");
3766     if (!init_func) {
3767         fprintf(stderr,
3768                 "%s: init function 'ffserver_module_init()' not found\n",
3769                 filename);
3770         dlclose(dll);
3771     }
3772
3773     init_func();
3774 }
3775 #endif
3776
3777 static int ffserver_opt_default(const char *opt, const char *arg,
3778                        AVCodecContext *avctx, int type)
3779 {
3780     int ret = 0;
3781     const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3782     if(o)
3783         ret = av_set_string3(avctx, opt, arg, 1, NULL);
3784     return ret;
3785 }
3786
3787 static int parse_ffconfig(const char *filename)
3788 {
3789     FILE *f;
3790     char line[1024];
3791     char cmd[64];
3792     char arg[1024];
3793     const char *p;
3794     int val, errors, line_num;
3795     FFStream **last_stream, *stream, *redirect;
3796     FFStream **last_feed, *feed, *s;
3797     AVCodecContext audio_enc, video_enc;
3798     enum CodecID audio_id, video_id;
3799
3800     f = fopen(filename, "r");
3801     if (!f) {
3802         perror(filename);
3803         return -1;
3804     }
3805
3806     errors = 0;
3807     line_num = 0;
3808     first_stream = NULL;
3809     last_stream = &first_stream;
3810     first_feed = NULL;
3811     last_feed = &first_feed;
3812     stream = NULL;
3813     feed = NULL;
3814     redirect = NULL;
3815     audio_id = CODEC_ID_NONE;
3816     video_id = CODEC_ID_NONE;
3817     for(;;) {
3818         if (fgets(line, sizeof(line), f) == NULL)
3819             break;
3820         line_num++;
3821         p = line;
3822         while (isspace(*p))
3823             p++;
3824         if (*p == '\0' || *p == '#')
3825             continue;
3826
3827         get_arg(cmd, sizeof(cmd), &p);
3828
3829         if (!strcasecmp(cmd, "Port")) {
3830             get_arg(arg, sizeof(arg), &p);
3831             val = atoi(arg);
3832             if (val < 1 || val > 65536) {
3833                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3834                         filename, line_num, arg);
3835                 errors++;
3836             }
3837             my_http_addr.sin_port = htons(val);
3838         } else if (!strcasecmp(cmd, "BindAddress")) {
3839             get_arg(arg, sizeof(arg), &p);
3840             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3841                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3842                         filename, line_num, arg);
3843                 errors++;
3844             }
3845         } else if (!strcasecmp(cmd, "NoDaemon")) {
3846             ffserver_daemon = 0;
3847         } else if (!strcasecmp(cmd, "RTSPPort")) {
3848             get_arg(arg, sizeof(arg), &p);
3849             val = atoi(arg);
3850             if (val < 1 || val > 65536) {
3851                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3852                         filename, line_num, arg);
3853                 errors++;
3854             }
3855             my_rtsp_addr.sin_port = htons(atoi(arg));
3856         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3857             get_arg(arg, sizeof(arg), &p);
3858             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3859                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3860                         filename, line_num, arg);
3861                 errors++;
3862             }
3863         } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3864             get_arg(arg, sizeof(arg), &p);
3865             val = atoi(arg);
3866             if (val < 1 || val > 65536) {
3867                 fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3868                         filename, line_num, arg);
3869                 errors++;
3870             }
3871             nb_max_http_connections = val;
3872         } else if (!strcasecmp(cmd, "MaxClients")) {
3873             get_arg(arg, sizeof(arg), &p);
3874             val = atoi(arg);
3875             if (val < 1 || val > nb_max_http_connections) {
3876                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3877                         filename, line_num, arg);
3878                 errors++;
3879             } else {
3880                 nb_max_connections = val;
3881             }
3882         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3883             int64_t llval;
3884             get_arg(arg, sizeof(arg), &p);
3885             llval = atoll(arg);
3886             if (llval < 10 || llval > 10000000) {
3887                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3888                         filename, line_num, arg);
3889                 errors++;
3890             } else
3891                 max_bandwidth = llval;
3892         } else if (!strcasecmp(cmd, "CustomLog")) {
3893             if (!ffserver_debug)
3894                 get_arg(logfilename, sizeof(logfilename), &p);
3895         } else if (!strcasecmp(cmd, "<Feed")) {
3896             /*********************************************/
3897             /* Feed related options */
3898             char *q;
3899             if (stream || feed) {
3900                 fprintf(stderr, "%s:%d: Already in a tag\n",
3901                         filename, line_num);
3902             } else {
3903                 feed = av_mallocz(sizeof(FFStream));
3904                 get_arg(feed->filename, sizeof(feed->filename), &p);
3905                 q = strrchr(feed->filename, '>');
3906                 if (*q)
3907                     *q = '\0';
3908
3909                 for (s = first_feed; s; s = s->next) {
3910                     if (!strcmp(feed->filename, s->filename)) {
3911                         fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3912                                 filename, line_num, s->filename);
3913                         errors++;
3914                     }
3915                 }
3916
3917                 feed->fmt = guess_format("ffm", NULL, NULL);
3918                 /* defaut feed file */
3919                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3920                          "/tmp/%s.ffm", feed->filename);
3921                 feed->feed_max_size = 5 * 1024 * 1024;
3922                 feed->is_feed = 1;
3923                 feed->feed = feed; /* self feeding :-) */
3924
3925                 /* add in stream list */
3926                 *last_stream = feed;
3927                 last_stream = &feed->next;
3928                 /* add in feed list */
3929                 *last_feed = feed;
3930                 last_feed = &feed->next_feed;
3931             }
3932         } else if (!strcasecmp(cmd, "Launch")) {
3933             if (feed) {
3934                 int i;
3935
3936                 feed->child_argv = av_mallocz(64 * sizeof(char *));
3937
3938                 for (i = 0; i < 62; i++) {
3939                     get_arg(arg, sizeof(arg), &p);
3940                     if (!arg[0])
3941                         break;
3942
3943                     feed->child_argv[i] = av_strdup(arg);
3944                 }
3945
3946                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3947
3948                 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3949                     "http://%s:%d/%s",
3950                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3951                     inet_ntoa(my_http_addr.sin_addr),
3952                     ntohs(my_http_addr.sin_port), feed->filename);
3953             }
3954         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3955             if (feed) {
3956                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3957                 feed->readonly = 1;
3958             } else if (stream) {
3959                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3960             }
3961         } else if (!strcasecmp(cmd, "File")) {
3962             if (feed) {
3963                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3964             } else if (stream)
3965                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3966         } else if (!strcasecmp(cmd, "Truncate")) {
3967             if (feed) {
3968                 get_arg(arg, sizeof(arg), &p);
3969                 feed->truncate = strtod(arg, NULL);
3970             }
3971         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3972             if (feed) {
3973                 char *p1;
3974                 double fsize;
3975
3976                 get_arg(arg, sizeof(arg), &p);
3977                 p1 = arg;
3978                 fsize = strtod(p1, &p1);
3979                 switch(toupper(*p1)) {
3980                 case 'K':
3981                     fsize *= 1024;
3982                     break;
3983                 case 'M':
3984                     fsize *= 1024 * 1024;
3985                     break;
3986                 case 'G':
3987                     fsize *= 1024 * 1024 * 1024;
3988                     break;
3989                 }
3990                 feed->feed_max_size = (int64_t)fsize;
3991             }
3992         } else if (!strcasecmp(cmd, "</Feed>")) {
3993             if (!feed) {
3994                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3995                         filename, line_num);
3996                 errors++;
3997             }
3998             feed = NULL;
3999         } else if (!strcasecmp(cmd, "<Stream")) {
4000             /*********************************************/
4001             /* Stream related options */
4002             char *q;
4003             if (stream || feed) {
4004                 fprintf(stderr, "%s:%d: Already in a tag\n",
4005                         filename, line_num);
4006             } else {
4007                 FFStream *s;
4008                 const AVClass *class;
4009                 stream = av_mallocz(sizeof(FFStream));
4010                 get_arg(stream->filename, sizeof(stream->filename), &p);
4011                 q = strrchr(stream->filename, '>');
4012                 if (*q)
4013                     *q = '\0';
4014
4015                 for (s = first_stream; s; s = s->next) {
4016                     if (!strcmp(stream->filename, s->filename)) {
4017                         fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
4018                                 filename, line_num, s->filename);
4019                         errors++;
4020                     }
4021                 }
4022
4023                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
4024                 /* fetch avclass so AVOption works
4025                  * FIXME try to use avcodec_get_context_defaults2
4026                  * without changing defaults too much */
4027                 avcodec_get_context_defaults(&video_enc);
4028                 class = video_enc.av_class;
4029                 memset(&audio_enc, 0, sizeof(AVCodecContext));
4030                 memset(&video_enc, 0, sizeof(AVCodecContext));
4031                 audio_enc.av_class = class;
4032                 video_enc.av_class = class;
4033                 audio_id = CODEC_ID_NONE;
4034                 video_id = CODEC_ID_NONE;
4035                 if (stream->fmt) {
4036                     audio_id = stream->fmt->audio_codec;
4037                     video_id = stream->fmt->video_codec;
4038                 }
4039
4040                 *last_stream = stream;
4041                 last_stream = &stream->next;
4042             }
4043         } else if (!strcasecmp(cmd, "Feed")) {
4044             get_arg(arg, sizeof(arg), &p);
4045             if (stream) {
4046                 FFStream *sfeed;
4047
4048                 sfeed = first_feed;
4049                 while (sfeed != NULL) {
4050                     if (!strcmp(sfeed->filename, arg))
4051                         break;
4052                     sfeed = sfeed->next_feed;
4053                 }
4054                 if (!sfeed)
4055                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4056                             filename, line_num, arg);
4057                 else
4058                     stream->feed = sfeed;
4059             }
4060         } else if (!strcasecmp(cmd, "Format")) {
4061             get_arg(arg, sizeof(arg), &p);
4062             if (stream) {
4063                 if (!strcmp(arg, "status")) {
4064                     stream->stream_type = STREAM_TYPE_STATUS;
4065                     stream->fmt = NULL;
4066                 } else {
4067                     stream->stream_type = STREAM_TYPE_LIVE;
4068                     /* jpeg cannot be used here, so use single frame jpeg */
4069                     if (!strcmp(arg, "jpeg"))
4070                         strcpy(arg, "mjpeg");
4071                     stream->fmt = guess_stream_format(arg, NULL, NULL);
4072                     if (!stream->fmt) {
4073                         fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4074                                 filename, line_num, arg);
4075                         errors++;
4076                     }
4077                 }
4078                 if (stream->fmt) {
4079                     audio_id = stream->fmt->audio_codec;
4080                     video_id = stream->fmt->video_codec;
4081                 }
4082             }
4083         } else if (!strcasecmp(cmd, "InputFormat")) {
4084             get_arg(arg, sizeof(arg), &p);
4085             if (stream) {
4086                 stream->ifmt = av_find_input_format(arg);
4087                 if (!stream->ifmt) {
4088                     fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4089                             filename, line_num, arg);
4090                 }
4091             }
4092         } else if (!strcasecmp(cmd, "FaviconURL")) {
4093             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4094                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4095             } else {
4096                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4097                             filename, line_num);
4098                 errors++;
4099             }
4100         } else if (!strcasecmp(cmd, "Author")) {
4101             if (stream)
4102                 get_arg(stream->author, sizeof(stream->author), &p);
4103         } else if (!strcasecmp(cmd, "Comment")) {
4104             if (stream)
4105                 get_arg(stream->comment, sizeof(stream->comment), &p);
4106         } else if (!strcasecmp(cmd, "Copyright")) {
4107             if (stream)
4108                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4109         } else if (!strcasecmp(cmd, "Title")) {
4110             if (stream)
4111                 get_arg(stream->title, sizeof(stream->title), &p);
4112         } else if (!strcasecmp(cmd, "Preroll")) {
4113             get_arg(arg, sizeof(arg), &p);
4114             if (stream)
4115                 stream->prebuffer = atof(arg) * 1000;
4116         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4117             if (stream)
4118                 stream->send_on_key = 1;
4119         } else if (!strcasecmp(cmd, "AudioCodec")) {
4120             get_arg(arg, sizeof(arg), &p);
4121             audio_id = opt_audio_codec(arg);
4122             if (audio_id == CODEC_ID_NONE) {
4123                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4124                         filename, line_num, arg);
4125                 errors++;
4126             }
4127         } else if (!strcasecmp(cmd, "VideoCodec")) {
4128             get_arg(arg, sizeof(arg), &p);
4129             video_id = opt_video_codec(arg);
4130             if (video_id == CODEC_ID_NONE) {
4131                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4132                         filename, line_num, arg);
4133                 errors++;
4134             }
4135         } else if (!strcasecmp(cmd, "MaxTime")) {
4136             get_arg(arg, sizeof(arg), &p);
4137             if (stream)
4138                 stream->max_time = atof(arg) * 1000;
4139         } else if (!strcasecmp(cmd, "AudioBitRate")) {
4140             get_arg(arg, sizeof(arg), &p);
4141             if (stream)
4142                 audio_enc.bit_rate = atoi(arg) * 1000;
4143         } else if (!strcasecmp(cmd, "AudioChannels")) {
4144             get_arg(arg, sizeof(arg), &p);
4145             if (stream)
4146                 audio_enc.channels = atoi(arg);
4147         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4148             get_arg(arg, sizeof(arg), &p);
4149             if (stream)
4150                 audio_enc.sample_rate = atoi(arg);
4151         } else if (!strcasecmp(cmd, "AudioQuality")) {
4152             get_arg(arg, sizeof(arg), &p);
4153             if (stream) {
4154 //                audio_enc.quality = atof(arg) * 1000;
4155             }
4156         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4157             if (stream) {
4158                 int minrate, maxrate;
4159
4160                 get_arg(arg, sizeof(arg), &p);
4161
4162                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4163                     video_enc.rc_min_rate = minrate * 1000;
4164                     video_enc.rc_max_rate = maxrate * 1000;
4165                 } else {
4166                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4167                             filename, line_num, arg);
4168                     errors++;
4169                 }
4170             }
4171         } else if (!strcasecmp(cmd, "Debug")) {
4172             if (stream) {
4173                 get_arg(arg, sizeof(arg), &p);
4174                 video_enc.debug = strtol(arg,0,0);
4175             }
4176         } else if (!strcasecmp(cmd, "Strict")) {
4177             if (stream) {
4178                 get_arg(arg, sizeof(arg), &p);
4179                 video_enc.strict_std_compliance = atoi(arg);
4180             }
4181         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4182             if (stream) {
4183                 get_arg(arg, sizeof(arg), &p);
4184                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4185             }
4186         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4187             if (stream) {
4188                 get_arg(arg, sizeof(arg), &p);
4189                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4190             }
4191         } else if (!strcasecmp(cmd, "VideoBitRate")) {
4192             get_arg(arg, sizeof(arg), &p);
4193             if (stream) {
4194                 video_enc.bit_rate = atoi(arg) * 1000;
4195             }
4196         } else if (!strcasecmp(cmd, "VideoSize")) {
4197             get_arg(arg, sizeof(arg), &p);
4198             if (stream) {
4199                 av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4200                 if ((video_enc.width % 16) != 0 ||
4201                     (video_enc.height % 16) != 0) {
4202                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4203                             filename, line_num);
4204                     errors++;
4205                 }
4206             }
4207         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4208             get_arg(arg, sizeof(arg), &p);
4209             if (stream) {
4210                 AVRational frame_rate;
4211                 if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4212                     fprintf(stderr, "Incorrect frame rate\n");
4213                     errors++;
4214                 } else {
4215                     video_enc.time_base.num = frame_rate.den;
4216                     video_enc.time_base.den = frame_rate.num;
4217                 }
4218             }
4219         } else if (!strcasecmp(cmd, "VideoGopSize")) {
4220             get_arg(arg, sizeof(arg), &p);
4221             if (stream)
4222                 video_enc.gop_size = atoi(arg);
4223         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4224             if (stream)
4225                 video_enc.gop_size = 1;
4226         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4227             if (stream)
4228                 video_enc.mb_decision = FF_MB_DECISION_BITS;
4229         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4230             if (stream) {
4231                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4232                 video_enc.flags |= CODEC_FLAG_4MV;
4233             }
4234         } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4235                    !strcasecmp(cmd, "AVOptionAudio")) {
4236             char arg2[1024];
4237             AVCodecContext *avctx;
4238             int type;
4239             get_arg(arg, sizeof(arg), &p);
4240             get_arg(arg2, sizeof(arg2), &p);
4241             if (!strcasecmp(cmd, "AVOptionVideo")) {
4242                 avctx = &video_enc;
4243                 type = AV_OPT_FLAG_VIDEO_PARAM;
4244             } else {
4245                 avctx = &audio_enc;
4246                 type = AV_OPT_FLAG_AUDIO_PARAM;
4247             }
4248             if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4249                 fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4250                 errors++;
4251             }
4252         } else if (!strcasecmp(cmd, "VideoTag")) {
4253             get_arg(arg, sizeof(arg), &p);
4254             if ((strlen(arg) == 4) && stream)
4255                 video_enc.codec_tag = AV_RL32(arg);
4256         } else if (!strcasecmp(cmd, "BitExact")) {
4257             if (stream)
4258                 video_enc.flags |= CODEC_FLAG_BITEXACT;
4259         } else if (!strcasecmp(cmd, "DctFastint")) {
4260             if (stream)
4261                 video_enc.dct_algo  = FF_DCT_FASTINT;
4262         } else if (!strcasecmp(cmd, "IdctSimple")) {
4263             if (stream)
4264                 video_enc.idct_algo = FF_IDCT_SIMPLE;
4265         } else if (!strcasecmp(cmd, "Qscale")) {
4266             get_arg(arg, sizeof(arg), &p);
4267             if (stream) {
4268                 video_enc.flags |= CODEC_FLAG_QSCALE;
4269                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4270             }
4271         } else if (!strcasecmp(cmd, "VideoQDiff")) {
4272             get_arg(arg, sizeof(arg), &p);
4273             if (stream) {
4274                 video_enc.max_qdiff = atoi(arg);
4275                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4276                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4277                             filename, line_num);
4278                     errors++;
4279                 }
4280             }
4281         } else if (!strcasecmp(cmd, "VideoQMax")) {
4282             get_arg(arg, sizeof(arg), &p);
4283             if (stream) {
4284                 video_enc.qmax = atoi(arg);
4285                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4286                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4287                             filename, line_num);
4288                     errors++;
4289                 }
4290             }
4291         } else if (!strcasecmp(cmd, "VideoQMin")) {
4292             get_arg(arg, sizeof(arg), &p);
4293             if (stream) {
4294                 video_enc.qmin = atoi(arg);
4295                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4296                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4297                             filename, line_num);
4298                     errors++;
4299                 }
4300             }
4301         } else if (!strcasecmp(cmd, "LumaElim")) {
4302             get_arg(arg, sizeof(arg), &p);
4303             if (stream)
4304                 video_enc.luma_elim_threshold = atoi(arg);
4305         } else if (!strcasecmp(cmd, "ChromaElim")) {
4306             get_arg(arg, sizeof(arg), &p);
4307             if (stream)
4308                 video_enc.chroma_elim_threshold = atoi(arg);
4309         } else if (!strcasecmp(cmd, "LumiMask")) {
4310             get_arg(arg, sizeof(arg), &p);
4311             if (stream)
4312                 video_enc.lumi_masking = atof(arg);
4313         } else if (!strcasecmp(cmd, "DarkMask")) {
4314             get_arg(arg, sizeof(arg), &p);
4315             if (stream)
4316                 video_enc.dark_masking = atof(arg);
4317         } else if (!strcasecmp(cmd, "NoVideo")) {
4318             video_id = CODEC_ID_NONE;
4319         } else if (!strcasecmp(cmd, "NoAudio")) {
4320             audio_id = CODEC_ID_NONE;
4321         } else if (!strcasecmp(cmd, "ACL")) {
4322             IPAddressACL acl;
4323
4324             get_arg(arg, sizeof(arg), &p);
4325             if (strcasecmp(arg, "allow") == 0)
4326                 acl.action = IP_ALLOW;
4327             else if (strcasecmp(arg, "deny") == 0)
4328                 acl.action = IP_DENY;
4329             else {
4330                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4331                         filename, line_num, arg);
4332                 errors++;
4333             }
4334
4335             get_arg(arg, sizeof(arg), &p);
4336
4337             if (resolve_host(&acl.first, arg) != 0) {
4338                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4339                         filename, line_num, arg);
4340                 errors++;
4341             } else
4342                 acl.last = acl.first;
4343
4344             get_arg(arg, sizeof(arg), &p);
4345
4346             if (arg[0]) {
4347                 if (resolve_host(&acl.last, arg) != 0) {
4348                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4349                             filename, line_num, arg);
4350                     errors++;
4351                 }
4352             }
4353
4354             if (!errors) {
4355                 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4356                 IPAddressACL **naclp = 0;
4357
4358                 acl.next = 0;
4359                 *nacl = acl;
4360
4361                 if (stream)
4362                     naclp = &stream->acl;
4363                 else if (feed)
4364                     naclp = &feed->acl;
4365                 else {
4366                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4367                             filename, line_num);
4368                     errors++;
4369                 }
4370
4371                 if (naclp) {
4372                     while (*naclp)
4373                         naclp = &(*naclp)->next;
4374
4375                     *naclp = nacl;
4376                 }
4377             }
4378         } else if (!strcasecmp(cmd, "RTSPOption")) {
4379             get_arg(arg, sizeof(arg), &p);
4380             if (stream) {
4381                 av_freep(&stream->rtsp_option);
4382                 stream->rtsp_option = av_strdup(arg);
4383             }
4384         } else if (!strcasecmp(cmd, "MulticastAddress")) {
4385             get_arg(arg, sizeof(arg), &p);
4386             if (stream) {
4387                 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4388                     fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4389                             filename, line_num, arg);
4390                     errors++;
4391                 }
4392                 stream->is_multicast = 1;
4393                 stream->loop = 1; /* default is looping */
4394             }
4395         } else if (!strcasecmp(cmd, "MulticastPort")) {
4396             get_arg(arg, sizeof(arg), &p);
4397             if (stream)
4398                 stream->multicast_port = atoi(arg);
4399         } else if (!strcasecmp(cmd, "MulticastTTL")) {
4400             get_arg(arg, sizeof(arg), &p);
4401             if (stream)
4402                 stream->multicast_ttl = atoi(arg);
4403         } else if (!strcasecmp(cmd, "NoLoop")) {
4404             if (stream)
4405                 stream->loop = 0;
4406         } else if (!strcasecmp(cmd, "</Stream>")) {
4407             if (!stream) {
4408                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4409                         filename, line_num);
4410                 errors++;
4411             } else {
4412                 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4413                     if (audio_id != CODEC_ID_NONE) {
4414                         audio_enc.codec_type = CODEC_TYPE_AUDIO;
4415                         audio_enc.codec_id = audio_id;
4416                         add_codec(stream, &audio_enc);
4417                     }
4418                     if (video_id != CODEC_ID_NONE) {
4419                         video_enc.codec_type = CODEC_TYPE_VIDEO;
4420                         video_enc.codec_id = video_id;
4421                         add_codec(stream, &video_enc);
4422                     }
4423                 }
4424                 stream = NULL;
4425             }
4426         } else if (!strcasecmp(cmd, "<Redirect")) {
4427             /*********************************************/
4428             char *q;
4429             if (stream || feed || redirect) {
4430                 fprintf(stderr, "%s:%d: Already in a tag\n",
4431                         filename, line_num);
4432                 errors++;
4433             } else {
4434                 redirect = av_mallocz(sizeof(FFStream));
4435                 *last_stream = redirect;
4436                 last_stream = &redirect->next;
4437
4438                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4439                 q = strrchr(redirect->filename, '>');
4440                 if (*q)
4441                     *q = '\0';
4442                 redirect->stream_type = STREAM_TYPE_REDIRECT;
4443             }
4444         } else if (!strcasecmp(cmd, "URL")) {
4445             if (redirect)
4446                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4447         } else if (!strcasecmp(cmd, "</Redirect>")) {
4448             if (!redirect) {
4449                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4450                         filename, line_num);
4451                 errors++;
4452             } else {
4453                 if (!redirect->feed_filename[0]) {
4454                     fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4455                             filename, line_num);
4456                     errors++;
4457                 }
4458                 redirect = NULL;
4459             }
4460         } else if (!strcasecmp(cmd, "LoadModule")) {
4461             get_arg(arg, sizeof(arg), &p);
4462 #if HAVE_DLOPEN
4463             load_module(arg);
4464 #else
4465             fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4466                     filename, line_num, arg);
4467             errors++;
4468 #endif
4469         } else {
4470             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4471                     filename, line_num, cmd);
4472         }
4473     }
4474
4475     fclose(f);
4476     if (errors)
4477         return -1;
4478     else
4479         return 0;
4480 }
4481
4482 static void handle_child_exit(int sig)
4483 {
4484     pid_t pid;
4485     int status;
4486
4487     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4488         FFStream *feed;
4489
4490         for (feed = first_feed; feed; feed = feed->next) {
4491             if (feed->pid == pid) {
4492                 int uptime = time(0) - feed->pid_start;
4493
4494                 feed->pid = 0;
4495                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4496
4497                 if (uptime < 30)
4498                     /* Turn off any more restarts */
4499                     feed->child_argv = 0;
4500             }
4501         }
4502     }
4503
4504     need_to_start_children = 1;
4505 }
4506
4507 static void opt_debug(void)
4508 {
4509     ffserver_debug = 1;
4510     ffserver_daemon = 0;
4511     logfilename[0] = '-';
4512 }
4513
4514 static void opt_show_help(void)
4515 {
4516     printf("usage: ffserver [options]\n"
4517            "Hyper fast multi format Audio/Video streaming server\n");
4518     printf("\n");
4519     show_help_options(options, "Main options:\n", 0, 0);
4520 }
4521
4522 static const OptionDef options[] = {
4523     { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4524     { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4525     { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4526     { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4527     { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4528     { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4529     { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4530     { NULL },
4531 };
4532
4533 int main(int argc, char **argv)
4534 {
4535     struct sigaction sigact;
4536
4537     av_register_all();
4538
4539     show_banner();
4540
4541     config_filename = "/etc/ffserver.conf";
4542
4543     my_program_name = argv[0];
4544     my_program_dir = getcwd(0, 0);
4545     ffserver_daemon = 1;
4546
4547     parse_options(argc, argv, options, NULL);
4548
4549     unsetenv("http_proxy");             /* Kill the http_proxy */
4550
4551     av_lfg_init(&random_state, ff_random_get_seed());
4552
4553     memset(&sigact, 0, sizeof(sigact));
4554     sigact.sa_handler = handle_child_exit;
4555     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4556     sigaction(SIGCHLD, &sigact, 0);
4557
4558     if (parse_ffconfig(config_filename) < 0) {
4559         fprintf(stderr, "Incorrect config file - exiting.\n");
4560         exit(1);
4561     }
4562
4563     /* open log file if needed */
4564     if (logfilename[0] != '\0') {
4565         if (!strcmp(logfilename, "-"))
4566             logfile = stdout;
4567         else
4568             logfile = fopen(logfilename, "a");
4569         av_log_set_callback(http_av_log);
4570     }
4571
4572     build_file_streams();
4573
4574     build_feed_streams();
4575
4576     compute_bandwidth();
4577
4578     /* put the process in background and detach it from its TTY */
4579     if (ffserver_daemon) {
4580         int pid;
4581
4582         pid = fork();
4583         if (pid < 0) {
4584             perror("fork");
4585             exit(1);
4586         } else if (pid > 0) {
4587             /* parent : exit */
4588             exit(0);
4589         } else {
4590             /* child */
4591             setsid();
4592             close(0);
4593             open("/dev/null", O_RDWR);
4594             if (strcmp(logfilename, "-") != 0) {
4595                 close(1);
4596                 dup(0);
4597             }
4598             close(2);
4599             dup(0);
4600         }
4601     }
4602
4603     /* signal init */
4604     signal(SIGPIPE, SIG_IGN);
4605
4606     if (ffserver_daemon)
4607         chdir("/");
4608
4609     if (http_server() < 0) {
4610         http_log("Could not start server\n");
4611         exit(1);
4612     }
4613
4614     return 0;
4615 }