]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - ffserver.c
WMA: extend exponent range to 95
[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 void get_arg(char *buf, int buf_size, const char **pp)
1196 {
1197     const char *p;
1198     char *q;
1199     int quote;
1200
1201     p = *pp;
1202     while (isspace(*p)) p++;
1203     q = buf;
1204     quote = 0;
1205     if (*p == '\"' || *p == '\'')
1206         quote = *p++;
1207     for(;;) {
1208         if (quote) {
1209             if (*p == quote)
1210                 break;
1211         } else {
1212             if (isspace(*p))
1213                 break;
1214         }
1215         if (*p == '\0')
1216             break;
1217         if ((q - buf) < buf_size - 1)
1218             *q++ = *p;
1219         p++;
1220     }
1221     *q = '\0';
1222     if (quote && *p == quote)
1223         p++;
1224     *pp = p;
1225 }
1226
1227 static int validate_acl(FFStream *stream, HTTPContext *c)
1228 {
1229     enum IPAddressAction last_action = IP_DENY;
1230     IPAddressACL *acl;
1231     struct in_addr *src = &c->from_addr.sin_addr;
1232     unsigned long src_addr = src->s_addr;
1233
1234     for (acl = stream->acl; acl; acl = acl->next) {
1235         if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1236             return (acl->action == IP_ALLOW) ? 1 : 0;
1237         last_action = acl->action;
1238     }
1239
1240     /* Nothing matched, so return not the last action */
1241     return (last_action == IP_DENY) ? 1 : 0;
1242 }
1243
1244 /* compute the real filename of a file by matching it without its
1245    extensions to all the stream filenames */
1246 static void compute_real_filename(char *filename, int max_size)
1247 {
1248     char file1[1024];
1249     char file2[1024];
1250     char *p;
1251     FFStream *stream;
1252
1253     /* compute filename by matching without the file extensions */
1254     av_strlcpy(file1, filename, sizeof(file1));
1255     p = strrchr(file1, '.');
1256     if (p)
1257         *p = '\0';
1258     for(stream = first_stream; stream != NULL; stream = stream->next) {
1259         av_strlcpy(file2, stream->filename, sizeof(file2));
1260         p = strrchr(file2, '.');
1261         if (p)
1262             *p = '\0';
1263         if (!strcmp(file1, file2)) {
1264             av_strlcpy(filename, stream->filename, max_size);
1265             break;
1266         }
1267     }
1268 }
1269
1270 enum RedirType {
1271     REDIR_NONE,
1272     REDIR_ASX,
1273     REDIR_RAM,
1274     REDIR_ASF,
1275     REDIR_RTSP,
1276     REDIR_SDP,
1277 };
1278
1279 /* parse http request and prepare header */
1280 static int http_parse_request(HTTPContext *c)
1281 {
1282     char *p;
1283     enum RedirType redir_type;
1284     char cmd[32];
1285     char info[1024], filename[1024];
1286     char url[1024], *q;
1287     char protocol[32];
1288     char msg[1024];
1289     const char *mime_type;
1290     FFStream *stream;
1291     int i;
1292     char ratebuf[32];
1293     char *useragent = 0;
1294
1295     p = c->buffer;
1296     get_word(cmd, sizeof(cmd), (const char **)&p);
1297     av_strlcpy(c->method, cmd, sizeof(c->method));
1298
1299     if (!strcmp(cmd, "GET"))
1300         c->post = 0;
1301     else if (!strcmp(cmd, "POST"))
1302         c->post = 1;
1303     else
1304         return -1;
1305
1306     get_word(url, sizeof(url), (const char **)&p);
1307     av_strlcpy(c->url, url, sizeof(c->url));
1308
1309     get_word(protocol, sizeof(protocol), (const char **)&p);
1310     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1311         return -1;
1312
1313     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1314
1315     if (ffserver_debug)
1316         http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1317
1318     /* find the filename and the optional info string in the request */
1319     p = strchr(url, '?');
1320     if (p) {
1321         av_strlcpy(info, p, sizeof(info));
1322         *p = '\0';
1323     } else
1324         info[0] = '\0';
1325
1326     av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1327
1328     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1329         if (strncasecmp(p, "User-Agent:", 11) == 0) {
1330             useragent = p + 11;
1331             if (*useragent && *useragent != '\n' && isspace(*useragent))
1332                 useragent++;
1333             break;
1334         }
1335         p = strchr(p, '\n');
1336         if (!p)
1337             break;
1338
1339         p++;
1340     }
1341
1342     redir_type = REDIR_NONE;
1343     if (match_ext(filename, "asx")) {
1344         redir_type = REDIR_ASX;
1345         filename[strlen(filename)-1] = 'f';
1346     } else if (match_ext(filename, "asf") &&
1347         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1348         /* if this isn't WMP or lookalike, return the redirector file */
1349         redir_type = REDIR_ASF;
1350     } else if (match_ext(filename, "rpm,ram")) {
1351         redir_type = REDIR_RAM;
1352         strcpy(filename + strlen(filename)-2, "m");
1353     } else if (match_ext(filename, "rtsp")) {
1354         redir_type = REDIR_RTSP;
1355         compute_real_filename(filename, sizeof(filename) - 1);
1356     } else if (match_ext(filename, "sdp")) {
1357         redir_type = REDIR_SDP;
1358         compute_real_filename(filename, sizeof(filename) - 1);
1359     }
1360
1361     // "redirect" / request to index.html
1362     if (!strlen(filename))
1363         av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1364
1365     stream = first_stream;
1366     while (stream != NULL) {
1367         if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1368             break;
1369         stream = stream->next;
1370     }
1371     if (stream == NULL) {
1372         snprintf(msg, sizeof(msg), "File '%s' not found", url);
1373         http_log("File '%s' not found\n", url);
1374         goto send_error;
1375     }
1376
1377     c->stream = stream;
1378     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1379     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1380
1381     if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1382         c->http_error = 301;
1383         q = c->buffer;
1384         q += snprintf(q, c->buffer_size,
1385                       "HTTP/1.0 301 Moved\r\n"
1386                       "Location: %s\r\n"
1387                       "Content-type: text/html\r\n"
1388                       "\r\n"
1389                       "<html><head><title>Moved</title></head><body>\r\n"
1390                       "You should be <a href=\"%s\">redirected</a>.\r\n"
1391                       "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1392         /* prepare output buffer */
1393         c->buffer_ptr = c->buffer;
1394         c->buffer_end = q;
1395         c->state = HTTPSTATE_SEND_HEADER;
1396         return 0;
1397     }
1398
1399     /* If this is WMP, get the rate information */
1400     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1401         if (modify_current_stream(c, ratebuf)) {
1402             for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1403                 if (c->switch_feed_streams[i] >= 0)
1404                     do_switch_stream(c, i);
1405             }
1406         }
1407     }
1408
1409     if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1410         current_bandwidth += stream->bandwidth;
1411
1412     /* If already streaming this feed, do not let start another feeder. */
1413     if (stream->feed_opened) {
1414         snprintf(msg, sizeof(msg), "This feed is already being received.");
1415         http_log("Feed '%s' already being received\n", stream->feed_filename);
1416         goto send_error;
1417     }
1418
1419     if (c->post == 0 && max_bandwidth < current_bandwidth) {
1420         c->http_error = 200;
1421         q = c->buffer;
1422         q += snprintf(q, c->buffer_size,
1423                       "HTTP/1.0 200 Server too busy\r\n"
1424                       "Content-type: text/html\r\n"
1425                       "\r\n"
1426                       "<html><head><title>Too busy</title></head><body>\r\n"
1427                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
1428                       "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1429                       "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1430                       "</body></html>\r\n", current_bandwidth, max_bandwidth);
1431         /* prepare output buffer */
1432         c->buffer_ptr = c->buffer;
1433         c->buffer_end = q;
1434         c->state = HTTPSTATE_SEND_HEADER;
1435         return 0;
1436     }
1437
1438     if (redir_type != REDIR_NONE) {
1439         char *hostinfo = 0;
1440
1441         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1442             if (strncasecmp(p, "Host:", 5) == 0) {
1443                 hostinfo = p + 5;
1444                 break;
1445             }
1446             p = strchr(p, '\n');
1447             if (!p)
1448                 break;
1449
1450             p++;
1451         }
1452
1453         if (hostinfo) {
1454             char *eoh;
1455             char hostbuf[260];
1456
1457             while (isspace(*hostinfo))
1458                 hostinfo++;
1459
1460             eoh = strchr(hostinfo, '\n');
1461             if (eoh) {
1462                 if (eoh[-1] == '\r')
1463                     eoh--;
1464
1465                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1466                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
1467                     hostbuf[eoh - hostinfo] = 0;
1468
1469                     c->http_error = 200;
1470                     q = c->buffer;
1471                     switch(redir_type) {
1472                     case REDIR_ASX:
1473                         q += snprintf(q, c->buffer_size,
1474                                       "HTTP/1.0 200 ASX Follows\r\n"
1475                                       "Content-type: video/x-ms-asf\r\n"
1476                                       "\r\n"
1477                                       "<ASX Version=\"3\">\r\n"
1478                                       //"<!-- Autogenerated by ffserver -->\r\n"
1479                                       "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1480                                       "</ASX>\r\n", hostbuf, filename, info);
1481                         break;
1482                     case REDIR_RAM:
1483                         q += snprintf(q, c->buffer_size,
1484                                       "HTTP/1.0 200 RAM Follows\r\n"
1485                                       "Content-type: audio/x-pn-realaudio\r\n"
1486                                       "\r\n"
1487                                       "# Autogenerated by ffserver\r\n"
1488                                       "http://%s/%s%s\r\n", hostbuf, filename, info);
1489                         break;
1490                     case REDIR_ASF:
1491                         q += snprintf(q, c->buffer_size,
1492                                       "HTTP/1.0 200 ASF Redirect follows\r\n"
1493                                       "Content-type: video/x-ms-asf\r\n"
1494                                       "\r\n"
1495                                       "[Reference]\r\n"
1496                                       "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1497                         break;
1498                     case REDIR_RTSP:
1499                         {
1500                             char hostname[256], *p;
1501                             /* extract only hostname */
1502                             av_strlcpy(hostname, hostbuf, sizeof(hostname));
1503                             p = strrchr(hostname, ':');
1504                             if (p)
1505                                 *p = '\0';
1506                             q += snprintf(q, c->buffer_size,
1507                                           "HTTP/1.0 200 RTSP Redirect follows\r\n"
1508                                           /* XXX: incorrect mime type ? */
1509                                           "Content-type: application/x-rtsp\r\n"
1510                                           "\r\n"
1511                                           "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1512                         }
1513                         break;
1514                     case REDIR_SDP:
1515                         {
1516                             uint8_t *sdp_data;
1517                             int sdp_data_size, len;
1518                             struct sockaddr_in my_addr;
1519
1520                             q += snprintf(q, c->buffer_size,
1521                                           "HTTP/1.0 200 OK\r\n"
1522                                           "Content-type: application/sdp\r\n"
1523                                           "\r\n");
1524
1525                             len = sizeof(my_addr);
1526                             getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1527
1528                             /* XXX: should use a dynamic buffer */
1529                             sdp_data_size = prepare_sdp_description(stream,
1530                                                                     &sdp_data,
1531                                                                     my_addr.sin_addr);
1532                             if (sdp_data_size > 0) {
1533                                 memcpy(q, sdp_data, sdp_data_size);
1534                                 q += sdp_data_size;
1535                                 *q = '\0';
1536                                 av_free(sdp_data);
1537                             }
1538                         }
1539                         break;
1540                     default:
1541                         abort();
1542                         break;
1543                     }
1544
1545                     /* prepare output buffer */
1546                     c->buffer_ptr = c->buffer;
1547                     c->buffer_end = q;
1548                     c->state = HTTPSTATE_SEND_HEADER;
1549                     return 0;
1550                 }
1551             }
1552         }
1553
1554         snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1555         goto send_error;
1556     }
1557
1558     stream->conns_served++;
1559
1560     /* XXX: add there authenticate and IP match */
1561
1562     if (c->post) {
1563         /* if post, it means a feed is being sent */
1564         if (!stream->is_feed) {
1565             /* However it might be a status report from WMP! Let us log the
1566              * data as it might come in handy one day. */
1567             char *logline = 0;
1568             int client_id = 0;
1569
1570             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1571                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1572                     logline = p;
1573                     break;
1574                 }
1575                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1576                     client_id = strtol(p + 18, 0, 10);
1577                 p = strchr(p, '\n');
1578                 if (!p)
1579                     break;
1580
1581                 p++;
1582             }
1583
1584             if (logline) {
1585                 char *eol = strchr(logline, '\n');
1586
1587                 logline += 17;
1588
1589                 if (eol) {
1590                     if (eol[-1] == '\r')
1591                         eol--;
1592                     http_log("%.*s\n", (int) (eol - logline), logline);
1593                     c->suppress_log = 1;
1594                 }
1595             }
1596
1597 #ifdef DEBUG_WMP
1598             http_log("\nGot request:\n%s\n", c->buffer);
1599 #endif
1600
1601             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1602                 HTTPContext *wmpc;
1603
1604                 /* Now we have to find the client_id */
1605                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1606                     if (wmpc->wmp_client_id == client_id)
1607                         break;
1608                 }
1609
1610                 if (wmpc && modify_current_stream(wmpc, ratebuf))
1611                     wmpc->switch_pending = 1;
1612             }
1613
1614             snprintf(msg, sizeof(msg), "POST command not handled");
1615             c->stream = 0;
1616             goto send_error;
1617         }
1618         if (http_start_receive_data(c) < 0) {
1619             snprintf(msg, sizeof(msg), "could not open feed");
1620             goto send_error;
1621         }
1622         c->http_error = 0;
1623         c->state = HTTPSTATE_RECEIVE_DATA;
1624         return 0;
1625     }
1626
1627 #ifdef DEBUG_WMP
1628     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1629         http_log("\nGot request:\n%s\n", c->buffer);
1630 #endif
1631
1632     if (c->stream->stream_type == STREAM_TYPE_STATUS)
1633         goto send_status;
1634
1635     /* open input stream */
1636     if (open_input_stream(c, info) < 0) {
1637         snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1638         goto send_error;
1639     }
1640
1641     /* prepare http header */
1642     q = c->buffer;
1643     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1644     mime_type = c->stream->fmt->mime_type;
1645     if (!mime_type)
1646         mime_type = "application/x-octet-stream";
1647     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1648
1649     /* for asf, we need extra headers */
1650     if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1651         /* Need to allocate a client id */
1652
1653         c->wmp_client_id = av_lfg_get(&random_state);
1654
1655         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);
1656     }
1657     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1658     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1659
1660     /* prepare output buffer */
1661     c->http_error = 0;
1662     c->buffer_ptr = c->buffer;
1663     c->buffer_end = q;
1664     c->state = HTTPSTATE_SEND_HEADER;
1665     return 0;
1666  send_error:
1667     c->http_error = 404;
1668     q = c->buffer;
1669     q += snprintf(q, c->buffer_size,
1670                   "HTTP/1.0 404 Not Found\r\n"
1671                   "Content-type: text/html\r\n"
1672                   "\r\n"
1673                   "<html>\n"
1674                   "<head><title>404 Not Found</title></head>\n"
1675                   "<body>%s</body>\n"
1676                   "</html>\n", msg);
1677     /* prepare output buffer */
1678     c->buffer_ptr = c->buffer;
1679     c->buffer_end = q;
1680     c->state = HTTPSTATE_SEND_HEADER;
1681     return 0;
1682  send_status:
1683     compute_status(c);
1684     c->http_error = 200; /* horrible : we use this value to avoid
1685                             going to the send data state */
1686     c->state = HTTPSTATE_SEND_HEADER;
1687     return 0;
1688 }
1689
1690 static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1691 {
1692     static const char *suffix = " kMGTP";
1693     const char *s;
1694
1695     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1696
1697     url_fprintf(pb, "%"PRId64"%c", count, *s);
1698 }
1699
1700 static void compute_status(HTTPContext *c)
1701 {
1702     HTTPContext *c1;
1703     FFStream *stream;
1704     char *p;
1705     time_t ti;
1706     int i, len;
1707     ByteIOContext *pb;
1708
1709     if (url_open_dyn_buf(&pb) < 0) {
1710         /* XXX: return an error ? */
1711         c->buffer_ptr = c->buffer;
1712         c->buffer_end = c->buffer;
1713         return;
1714     }
1715
1716     url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1717     url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1718     url_fprintf(pb, "Pragma: no-cache\r\n");
1719     url_fprintf(pb, "\r\n");
1720
1721     url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1722     if (c->stream->feed_filename[0])
1723         url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1724     url_fprintf(pb, "</head>\n<body>");
1725     url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1726     /* format status */
1727     url_fprintf(pb, "<h2>Available Streams</h2>\n");
1728     url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1729     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");
1730     stream = first_stream;
1731     while (stream != NULL) {
1732         char sfilename[1024];
1733         char *eosf;
1734
1735         if (stream->feed != stream) {
1736             av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1737             eosf = sfilename + strlen(sfilename);
1738             if (eosf - sfilename >= 4) {
1739                 if (strcmp(eosf - 4, ".asf") == 0)
1740                     strcpy(eosf - 4, ".asx");
1741                 else if (strcmp(eosf - 3, ".rm") == 0)
1742                     strcpy(eosf - 3, ".ram");
1743                 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1744                     /* generate a sample RTSP director if
1745                        unicast. Generate an SDP redirector if
1746                        multicast */
1747                     eosf = strrchr(sfilename, '.');
1748                     if (!eosf)
1749                         eosf = sfilename + strlen(sfilename);
1750                     if (stream->is_multicast)
1751                         strcpy(eosf, ".sdp");
1752                     else
1753                         strcpy(eosf, ".rtsp");
1754                 }
1755             }
1756
1757             url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1758                          sfilename, stream->filename);
1759             url_fprintf(pb, "<td align=right> %d <td align=right> ",
1760                         stream->conns_served);
1761             fmt_bytecount(pb, stream->bytes_served);
1762             switch(stream->stream_type) {
1763             case STREAM_TYPE_LIVE: {
1764                     int audio_bit_rate = 0;
1765                     int video_bit_rate = 0;
1766                     const char *audio_codec_name = "";
1767                     const char *video_codec_name = "";
1768                     const char *audio_codec_name_extra = "";
1769                     const char *video_codec_name_extra = "";
1770
1771                     for(i=0;i<stream->nb_streams;i++) {
1772                         AVStream *st = stream->streams[i];
1773                         AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1774                         switch(st->codec->codec_type) {
1775                         case CODEC_TYPE_AUDIO:
1776                             audio_bit_rate += st->codec->bit_rate;
1777                             if (codec) {
1778                                 if (*audio_codec_name)
1779                                     audio_codec_name_extra = "...";
1780                                 audio_codec_name = codec->name;
1781                             }
1782                             break;
1783                         case CODEC_TYPE_VIDEO:
1784                             video_bit_rate += st->codec->bit_rate;
1785                             if (codec) {
1786                                 if (*video_codec_name)
1787                                     video_codec_name_extra = "...";
1788                                 video_codec_name = codec->name;
1789                             }
1790                             break;
1791                         case CODEC_TYPE_DATA:
1792                             video_bit_rate += st->codec->bit_rate;
1793                             break;
1794                         default:
1795                             abort();
1796                         }
1797                     }
1798                     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",
1799                                  stream->fmt->name,
1800                                  stream->bandwidth,
1801                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1802                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1803                     if (stream->feed)
1804                         url_fprintf(pb, "<td>%s", stream->feed->filename);
1805                     else
1806                         url_fprintf(pb, "<td>%s", stream->feed_filename);
1807                     url_fprintf(pb, "\n");
1808                 }
1809                 break;
1810             default:
1811                 url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1812                 break;
1813             }
1814         }
1815         stream = stream->next;
1816     }
1817     url_fprintf(pb, "</table>\n");
1818
1819     stream = first_stream;
1820     while (stream != NULL) {
1821         if (stream->feed == stream) {
1822             url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1823             if (stream->pid) {
1824                 url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1825
1826 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1827                 {
1828                     FILE *pid_stat;
1829                     char ps_cmd[64];
1830
1831                     /* This is somewhat linux specific I guess */
1832                     snprintf(ps_cmd, sizeof(ps_cmd),
1833                              "ps -o \"%%cpu,cputime\" --no-headers %d",
1834                              stream->pid);
1835
1836                     pid_stat = popen(ps_cmd, "r");
1837                     if (pid_stat) {
1838                         char cpuperc[10];
1839                         char cpuused[64];
1840
1841                         if (fscanf(pid_stat, "%10s %64s", cpuperc,
1842                                    cpuused) == 2) {
1843                             url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1844                                          cpuperc, cpuused);
1845                         }
1846                         fclose(pid_stat);
1847                     }
1848                 }
1849 #endif
1850
1851                 url_fprintf(pb, "<p>");
1852             }
1853             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");
1854
1855             for (i = 0; i < stream->nb_streams; i++) {
1856                 AVStream *st = stream->streams[i];
1857                 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1858                 const char *type = "unknown";
1859                 char parameters[64];
1860
1861                 parameters[0] = 0;
1862
1863                 switch(st->codec->codec_type) {
1864                 case CODEC_TYPE_AUDIO:
1865                     type = "audio";
1866                     snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1867                     break;
1868                 case CODEC_TYPE_VIDEO:
1869                     type = "video";
1870                     snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1871                                 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1872                     break;
1873                 default:
1874                     abort();
1875                 }
1876                 url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1877                         i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1878             }
1879             url_fprintf(pb, "</table>\n");
1880
1881         }
1882         stream = stream->next;
1883     }
1884
1885     /* connection status */
1886     url_fprintf(pb, "<h2>Connection Status</h2>\n");
1887
1888     url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1889                  nb_connections, nb_max_connections);
1890
1891     url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1892                  current_bandwidth, max_bandwidth);
1893
1894     url_fprintf(pb, "<table>\n");
1895     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");
1896     c1 = first_http_ctx;
1897     i = 0;
1898     while (c1 != NULL) {
1899         int bitrate;
1900         int j;
1901
1902         bitrate = 0;
1903         if (c1->stream) {
1904             for (j = 0; j < c1->stream->nb_streams; j++) {
1905                 if (!c1->stream->feed)
1906                     bitrate += c1->stream->streams[j]->codec->bit_rate;
1907                 else if (c1->feed_streams[j] >= 0)
1908                     bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1909             }
1910         }
1911
1912         i++;
1913         p = inet_ntoa(c1->from_addr.sin_addr);
1914         url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1915                     i,
1916                     c1->stream ? c1->stream->filename : "",
1917                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1918                     p,
1919                     c1->protocol,
1920                     http_state[c1->state]);
1921         fmt_bytecount(pb, bitrate);
1922         url_fprintf(pb, "<td align=right>");
1923         fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1924         url_fprintf(pb, "<td align=right>");
1925         fmt_bytecount(pb, c1->data_count);
1926         url_fprintf(pb, "\n");
1927         c1 = c1->next;
1928     }
1929     url_fprintf(pb, "</table>\n");
1930
1931     /* date */
1932     ti = time(NULL);
1933     p = ctime(&ti);
1934     url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1935     url_fprintf(pb, "</body>\n</html>\n");
1936
1937     len = url_close_dyn_buf(pb, &c->pb_buffer);
1938     c->buffer_ptr = c->pb_buffer;
1939     c->buffer_end = c->pb_buffer + len;
1940 }
1941
1942 /* check if the parser needs to be opened for stream i */
1943 static void open_parser(AVFormatContext *s, int i)
1944 {
1945     AVStream *st = s->streams[i];
1946     AVCodec *codec;
1947
1948     if (!st->codec->codec) {
1949         codec = avcodec_find_decoder(st->codec->codec_id);
1950         if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1951             st->codec->parse_only = 1;
1952             if (avcodec_open(st->codec, codec) < 0)
1953                 st->codec->parse_only = 0;
1954         }
1955     }
1956 }
1957
1958 static int open_input_stream(HTTPContext *c, const char *info)
1959 {
1960     char buf[128];
1961     char input_filename[1024];
1962     AVFormatContext *s;
1963     int buf_size, i, ret;
1964     int64_t stream_pos;
1965
1966     /* find file name */
1967     if (c->stream->feed) {
1968         strcpy(input_filename, c->stream->feed->feed_filename);
1969         buf_size = FFM_PACKET_SIZE;
1970         /* compute position (absolute time) */
1971         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1972             stream_pos = parse_date(buf, 0);
1973             if (stream_pos == INT64_MIN)
1974                 return -1;
1975         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1976             int prebuffer = strtol(buf, 0, 10);
1977             stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1978         } else
1979             stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1980     } else {
1981         strcpy(input_filename, c->stream->feed_filename);
1982         buf_size = 0;
1983         /* compute position (relative time) */
1984         if (find_info_tag(buf, sizeof(buf), "date", info)) {
1985             stream_pos = parse_date(buf, 1);
1986             if (stream_pos == INT64_MIN)
1987                 return -1;
1988         } else
1989             stream_pos = 0;
1990     }
1991     if (input_filename[0] == '\0')
1992         return -1;
1993
1994     /* open stream */
1995     if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1996                                   buf_size, c->stream->ap_in)) < 0) {
1997         http_log("could not open %s: %d\n", input_filename, ret);
1998         return -1;
1999     }
2000     s->flags |= AVFMT_FLAG_GENPTS;
2001     c->fmt_in = s;
2002     if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2003         http_log("Could not find stream info '%s'\n", input_filename);
2004         av_close_input_file(s);
2005         return -1;
2006     }
2007
2008     /* open each parser */
2009     for(i=0;i<s->nb_streams;i++)
2010         open_parser(s, i);
2011
2012     /* choose stream as clock source (we favorize video stream if
2013        present) for packet sending */
2014     c->pts_stream_index = 0;
2015     for(i=0;i<c->stream->nb_streams;i++) {
2016         if (c->pts_stream_index == 0 &&
2017             c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2018             c->pts_stream_index = i;
2019         }
2020     }
2021
2022 #if 1
2023     if (c->fmt_in->iformat->read_seek)
2024         av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2025 #endif
2026     /* set the start time (needed for maxtime and RTP packet timing) */
2027     c->start_time = cur_time;
2028     c->first_pts = AV_NOPTS_VALUE;
2029     return 0;
2030 }
2031
2032 /* return the server clock (in us) */
2033 static int64_t get_server_clock(HTTPContext *c)
2034 {
2035     /* compute current pts value from system time */
2036     return (cur_time - c->start_time) * 1000;
2037 }
2038
2039 /* return the estimated time at which the current packet must be sent
2040    (in us) */
2041 static int64_t get_packet_send_clock(HTTPContext *c)
2042 {
2043     int bytes_left, bytes_sent, frame_bytes;
2044
2045     frame_bytes = c->cur_frame_bytes;
2046     if (frame_bytes <= 0)
2047         return c->cur_pts;
2048     else {
2049         bytes_left = c->buffer_end - c->buffer_ptr;
2050         bytes_sent = frame_bytes - bytes_left;
2051         return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2052     }
2053 }
2054
2055
2056 static int http_prepare_data(HTTPContext *c)
2057 {
2058     int i, len, ret;
2059     AVFormatContext *ctx;
2060
2061     av_freep(&c->pb_buffer);
2062     switch(c->state) {
2063     case HTTPSTATE_SEND_DATA_HEADER:
2064         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2065         av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2066         av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2067         av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2068         av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2069
2070         for(i=0;i<c->stream->nb_streams;i++) {
2071             AVStream *st;
2072             AVStream *src;
2073             st = av_mallocz(sizeof(AVStream));
2074             c->fmt_ctx.streams[i] = st;
2075             /* if file or feed, then just take streams from FFStream struct */
2076             if (!c->stream->feed ||
2077                 c->stream->feed == c->stream)
2078                 src = c->stream->streams[i];
2079             else
2080                 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2081
2082             *st = *src;
2083             st->priv_data = 0;
2084             st->codec->frame_number = 0; /* XXX: should be done in
2085                                            AVStream, not in codec */
2086         }
2087         /* set output format parameters */
2088         c->fmt_ctx.oformat = c->stream->fmt;
2089         c->fmt_ctx.nb_streams = c->stream->nb_streams;
2090
2091         c->got_key_frame = 0;
2092
2093         /* prepare header and save header data in a stream */
2094         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2095             /* XXX: potential leak */
2096             return -1;
2097         }
2098         c->fmt_ctx.pb->is_streamed = 1;
2099
2100         /*
2101          * HACK to avoid mpeg ps muxer to spit many underflow errors
2102          * Default value from FFmpeg
2103          * Try to set it use configuration option
2104          */
2105         c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2106         c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2107
2108         av_set_parameters(&c->fmt_ctx, NULL);
2109         if (av_write_header(&c->fmt_ctx) < 0) {
2110             http_log("Error writing output header\n");
2111             return -1;
2112         }
2113
2114         len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2115         c->buffer_ptr = c->pb_buffer;
2116         c->buffer_end = c->pb_buffer + len;
2117
2118         c->state = HTTPSTATE_SEND_DATA;
2119         c->last_packet_sent = 0;
2120         break;
2121     case HTTPSTATE_SEND_DATA:
2122         /* find a new packet */
2123         /* read a packet from the input stream */
2124         if (c->stream->feed)
2125             ffm_set_write_index(c->fmt_in,
2126                                 c->stream->feed->feed_write_index,
2127                                 c->stream->feed->feed_size);
2128
2129         if (c->stream->max_time &&
2130             c->stream->max_time + c->start_time - cur_time < 0)
2131             /* We have timed out */
2132             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2133         else {
2134             AVPacket pkt;
2135         redo:
2136             if (av_read_frame(c->fmt_in, &pkt) < 0) {
2137                 if (c->stream->feed && c->stream->feed->feed_opened) {
2138                     /* if coming from feed, it means we reached the end of the
2139                        ffm file, so must wait for more data */
2140                     c->state = HTTPSTATE_WAIT_FEED;
2141                     return 1; /* state changed */
2142                 } else {
2143                     if (c->stream->loop) {
2144                         av_close_input_file(c->fmt_in);
2145                         c->fmt_in = NULL;
2146                         if (open_input_stream(c, "") < 0)
2147                             goto no_loop;
2148                         goto redo;
2149                     } else {
2150                     no_loop:
2151                         /* must send trailer now because eof or error */
2152                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
2153                     }
2154                 }
2155             } else {
2156                 int source_index = pkt.stream_index;
2157                 /* update first pts if needed */
2158                 if (c->first_pts == AV_NOPTS_VALUE) {
2159                     c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2160                     c->start_time = cur_time;
2161                 }
2162                 /* send it to the appropriate stream */
2163                 if (c->stream->feed) {
2164                     /* if coming from a feed, select the right stream */
2165                     if (c->switch_pending) {
2166                         c->switch_pending = 0;
2167                         for(i=0;i<c->stream->nb_streams;i++) {
2168                             if (c->switch_feed_streams[i] == pkt.stream_index)
2169                                 if (pkt.flags & PKT_FLAG_KEY)
2170                                     do_switch_stream(c, i);
2171                             if (c->switch_feed_streams[i] >= 0)
2172                                 c->switch_pending = 1;
2173                         }
2174                     }
2175                     for(i=0;i<c->stream->nb_streams;i++) {
2176                         if (c->feed_streams[i] == pkt.stream_index) {
2177                             AVStream *st = c->fmt_in->streams[source_index];
2178                             pkt.stream_index = i;
2179                             if (pkt.flags & PKT_FLAG_KEY &&
2180                                 (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2181                                  c->stream->nb_streams == 1))
2182                                 c->got_key_frame = 1;
2183                             if (!c->stream->send_on_key || c->got_key_frame)
2184                                 goto send_it;
2185                         }
2186                     }
2187                 } else {
2188                     AVCodecContext *codec;
2189                     AVStream *ist, *ost;
2190                 send_it:
2191                     ist = c->fmt_in->streams[source_index];
2192                     /* specific handling for RTP: we use several
2193                        output stream (one for each RTP
2194                        connection). XXX: need more abstract handling */
2195                     if (c->is_packetized) {
2196                         /* compute send time and duration */
2197                         c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2198                         if (ist->start_time != AV_NOPTS_VALUE)
2199                             c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2200                         c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2201                         /* find RTP context */
2202                         c->packet_stream_index = pkt.stream_index;
2203                         ctx = c->rtp_ctx[c->packet_stream_index];
2204                         if(!ctx) {
2205                             av_free_packet(&pkt);
2206                             break;
2207                         }
2208                         codec = ctx->streams[0]->codec;
2209                         /* only one stream per RTP connection */
2210                         pkt.stream_index = 0;
2211                     } else {
2212                         ctx = &c->fmt_ctx;
2213                         /* Fudge here */
2214                         codec = ctx->streams[pkt.stream_index]->codec;
2215                     }
2216
2217                     if (c->is_packetized) {
2218                         int max_packet_size;
2219                         if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2220                             max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2221                         else
2222                             max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2223                         ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2224                     } else {
2225                         ret = url_open_dyn_buf(&ctx->pb);
2226                     }
2227                     if (ret < 0) {
2228                         /* XXX: potential leak */
2229                         return -1;
2230                     }
2231                     ost = ctx->streams[pkt.stream_index];
2232
2233                     ctx->pb->is_streamed = 1;
2234                     if (pkt.dts != AV_NOPTS_VALUE)
2235                         pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2236                     if (pkt.pts != AV_NOPTS_VALUE)
2237                         pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2238                     pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2239                     if (av_write_frame(ctx, &pkt) < 0) {
2240                         http_log("Error writing frame to output\n");
2241                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
2242                     }
2243
2244                     len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2245                     c->cur_frame_bytes = len;
2246                     c->buffer_ptr = c->pb_buffer;
2247                     c->buffer_end = c->pb_buffer + len;
2248
2249                     codec->frame_number++;
2250                     if (len == 0) {
2251                         av_free_packet(&pkt);
2252                         goto redo;
2253                     }
2254                 }
2255                 av_free_packet(&pkt);
2256             }
2257         }
2258         break;
2259     default:
2260     case HTTPSTATE_SEND_DATA_TRAILER:
2261         /* last packet test ? */
2262         if (c->last_packet_sent || c->is_packetized)
2263             return -1;
2264         ctx = &c->fmt_ctx;
2265         /* prepare header */
2266         if (url_open_dyn_buf(&ctx->pb) < 0) {
2267             /* XXX: potential leak */
2268             return -1;
2269         }
2270         c->fmt_ctx.pb->is_streamed = 1;
2271         av_write_trailer(ctx);
2272         len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2273         c->buffer_ptr = c->pb_buffer;
2274         c->buffer_end = c->pb_buffer + len;
2275
2276         c->last_packet_sent = 1;
2277         break;
2278     }
2279     return 0;
2280 }
2281
2282 /* should convert the format at the same time */
2283 /* send data starting at c->buffer_ptr to the output connection
2284    (either UDP or TCP connection) */
2285 static int http_send_data(HTTPContext *c)
2286 {
2287     int len, ret;
2288
2289     for(;;) {
2290         if (c->buffer_ptr >= c->buffer_end) {
2291             ret = http_prepare_data(c);
2292             if (ret < 0)
2293                 return -1;
2294             else if (ret != 0)
2295                 /* state change requested */
2296                 break;
2297         } else {
2298             if (c->is_packetized) {
2299                 /* RTP data output */
2300                 len = c->buffer_end - c->buffer_ptr;
2301                 if (len < 4) {
2302                     /* fail safe - should never happen */
2303                 fail1:
2304                     c->buffer_ptr = c->buffer_end;
2305                     return 0;
2306                 }
2307                 len = (c->buffer_ptr[0] << 24) |
2308                     (c->buffer_ptr[1] << 16) |
2309                     (c->buffer_ptr[2] << 8) |
2310                     (c->buffer_ptr[3]);
2311                 if (len > (c->buffer_end - c->buffer_ptr))
2312                     goto fail1;
2313                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2314                     /* nothing to send yet: we can wait */
2315                     return 0;
2316                 }
2317
2318                 c->data_count += len;
2319                 update_datarate(&c->datarate, c->data_count);
2320                 if (c->stream)
2321                     c->stream->bytes_served += len;
2322
2323                 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2324                     /* RTP packets are sent inside the RTSP TCP connection */
2325                     ByteIOContext *pb;
2326                     int interleaved_index, size;
2327                     uint8_t header[4];
2328                     HTTPContext *rtsp_c;
2329
2330                     rtsp_c = c->rtsp_c;
2331                     /* if no RTSP connection left, error */
2332                     if (!rtsp_c)
2333                         return -1;
2334                     /* if already sending something, then wait. */
2335                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2336                         break;
2337                     if (url_open_dyn_buf(&pb) < 0)
2338                         goto fail1;
2339                     interleaved_index = c->packet_stream_index * 2;
2340                     /* RTCP packets are sent at odd indexes */
2341                     if (c->buffer_ptr[1] == 200)
2342                         interleaved_index++;
2343                     /* write RTSP TCP header */
2344                     header[0] = '$';
2345                     header[1] = interleaved_index;
2346                     header[2] = len >> 8;
2347                     header[3] = len;
2348                     put_buffer(pb, header, 4);
2349                     /* write RTP packet data */
2350                     c->buffer_ptr += 4;
2351                     put_buffer(pb, c->buffer_ptr, len);
2352                     size = url_close_dyn_buf(pb, &c->packet_buffer);
2353                     /* prepare asynchronous TCP sending */
2354                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
2355                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
2356                     c->buffer_ptr += len;
2357
2358                     /* send everything we can NOW */
2359                     len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2360                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2361                     if (len > 0)
2362                         rtsp_c->packet_buffer_ptr += len;
2363                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2364                         /* if we could not send all the data, we will
2365                            send it later, so a new state is needed to
2366                            "lock" the RTSP TCP connection */
2367                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
2368                         break;
2369                     } else
2370                         /* all data has been sent */
2371                         av_freep(&c->packet_buffer);
2372                 } else {
2373                     /* send RTP packet directly in UDP */
2374                     c->buffer_ptr += 4;
2375                     url_write(c->rtp_handles[c->packet_stream_index],
2376                               c->buffer_ptr, len);
2377                     c->buffer_ptr += len;
2378                     /* here we continue as we can send several packets per 10 ms slot */
2379                 }
2380             } else {
2381                 /* TCP data output */
2382                 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2383                 if (len < 0) {
2384                     if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2385                         ff_neterrno() != FF_NETERROR(EINTR))
2386                         /* error : close connection */
2387                         return -1;
2388                     else
2389                         return 0;
2390                 } else
2391                     c->buffer_ptr += len;
2392
2393                 c->data_count += len;
2394                 update_datarate(&c->datarate, c->data_count);
2395                 if (c->stream)
2396                     c->stream->bytes_served += len;
2397                 break;
2398             }
2399         }
2400     } /* for(;;) */
2401     return 0;
2402 }
2403
2404 static int http_start_receive_data(HTTPContext *c)
2405 {
2406     int fd;
2407
2408     if (c->stream->feed_opened)
2409         return -1;
2410
2411     /* Don't permit writing to this one */
2412     if (c->stream->readonly)
2413         return -1;
2414
2415     /* open feed */
2416     fd = open(c->stream->feed_filename, O_RDWR);
2417     if (fd < 0) {
2418         http_log("Error opening feeder file: %s\n", strerror(errno));
2419         return -1;
2420     }
2421     c->feed_fd = fd;
2422
2423     if (c->stream->truncate) {
2424         /* truncate feed file */
2425         ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2426         ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2427         http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2428     } else {
2429         if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2430             http_log("Error reading write index from feed file: %s\n", strerror(errno));
2431             return -1;
2432         }
2433     }
2434
2435     c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2436     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2437     lseek(fd, 0, SEEK_SET);
2438
2439     /* init buffer input */
2440     c->buffer_ptr = c->buffer;
2441     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2442     c->stream->feed_opened = 1;
2443     return 0;
2444 }
2445
2446 static int http_receive_data(HTTPContext *c)
2447 {
2448     HTTPContext *c1;
2449
2450     if (c->buffer_end > c->buffer_ptr) {
2451         int len;
2452
2453         len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2454         if (len < 0) {
2455             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2456                 ff_neterrno() != FF_NETERROR(EINTR))
2457                 /* error : close connection */
2458                 goto fail;
2459         } else if (len == 0)
2460             /* end of connection : close it */
2461             goto fail;
2462         else {
2463             c->buffer_ptr += len;
2464             c->data_count += len;
2465             update_datarate(&c->datarate, c->data_count);
2466         }
2467     }
2468
2469     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2470         if (c->buffer[0] != 'f' ||
2471             c->buffer[1] != 'm') {
2472             http_log("Feed stream has become desynchronized -- disconnecting\n");
2473             goto fail;
2474         }
2475     }
2476
2477     if (c->buffer_ptr >= c->buffer_end) {
2478         FFStream *feed = c->stream;
2479         /* a packet has been received : write it in the store, except
2480            if header */
2481         if (c->data_count > FFM_PACKET_SIZE) {
2482
2483             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2484             /* XXX: use llseek or url_seek */
2485             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2486             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2487                 http_log("Error writing to feed file: %s\n", strerror(errno));
2488                 goto fail;
2489             }
2490
2491             feed->feed_write_index += FFM_PACKET_SIZE;
2492             /* update file size */
2493             if (feed->feed_write_index > c->stream->feed_size)
2494                 feed->feed_size = feed->feed_write_index;
2495
2496             /* handle wrap around if max file size reached */
2497             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2498                 feed->feed_write_index = FFM_PACKET_SIZE;
2499
2500             /* write index */
2501             if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2502                 http_log("Error writing index to feed file: %s\n", strerror(errno));
2503                 goto fail;
2504             }
2505
2506             /* wake up any waiting connections */
2507             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2508                 if (c1->state == HTTPSTATE_WAIT_FEED &&
2509                     c1->stream->feed == c->stream->feed)
2510                     c1->state = HTTPSTATE_SEND_DATA;
2511             }
2512         } else {
2513             /* We have a header in our hands that contains useful data */
2514             AVFormatContext *s = NULL;
2515             ByteIOContext *pb;
2516             AVInputFormat *fmt_in;
2517             int i;
2518
2519             /* use feed output format name to find corresponding input format */
2520             fmt_in = av_find_input_format(feed->fmt->name);
2521             if (!fmt_in)
2522                 goto fail;
2523
2524             url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2525             pb->is_streamed = 1;
2526
2527             if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2528                 av_free(pb);
2529                 goto fail;
2530             }
2531
2532             /* Now we have the actual streams */
2533             if (s->nb_streams != feed->nb_streams) {
2534                 av_close_input_stream(s);
2535                 av_free(pb);
2536                 http_log("Feed '%s' stream number does not match registered feed\n",
2537                          c->stream->feed_filename);
2538                 goto fail;
2539             }
2540
2541             for (i = 0; i < s->nb_streams; i++) {
2542                 AVStream *fst = feed->streams[i];
2543                 AVStream *st = s->streams[i];
2544                 memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2545                 if (fst->codec->extradata_size) {
2546                     fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2547                     if (!fst->codec->extradata)
2548                         goto fail;
2549                     memcpy(fst->codec->extradata, st->codec->extradata,
2550                            fst->codec->extradata_size);
2551                 }
2552             }
2553
2554             av_close_input_stream(s);
2555             av_free(pb);
2556         }
2557         c->buffer_ptr = c->buffer;
2558     }
2559
2560     return 0;
2561  fail:
2562     c->stream->feed_opened = 0;
2563     close(c->feed_fd);
2564     /* wake up any waiting connections to stop waiting for feed */
2565     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2566         if (c1->state == HTTPSTATE_WAIT_FEED &&
2567             c1->stream->feed == c->stream->feed)
2568             c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2569     }
2570     return -1;
2571 }
2572
2573 /********************************************************************/
2574 /* RTSP handling */
2575
2576 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2577 {
2578     const char *str;
2579     time_t ti;
2580     char *p;
2581     char buf2[32];
2582
2583     switch(error_number) {
2584     case RTSP_STATUS_OK:
2585         str = "OK";
2586         break;
2587     case RTSP_STATUS_METHOD:
2588         str = "Method Not Allowed";
2589         break;
2590     case RTSP_STATUS_BANDWIDTH:
2591         str = "Not Enough Bandwidth";
2592         break;
2593     case RTSP_STATUS_SESSION:
2594         str = "Session Not Found";
2595         break;
2596     case RTSP_STATUS_STATE:
2597         str = "Method Not Valid in This State";
2598         break;
2599     case RTSP_STATUS_AGGREGATE:
2600         str = "Aggregate operation not allowed";
2601         break;
2602     case RTSP_STATUS_ONLY_AGGREGATE:
2603         str = "Only aggregate operation allowed";
2604         break;
2605     case RTSP_STATUS_TRANSPORT:
2606         str = "Unsupported transport";
2607         break;
2608     case RTSP_STATUS_INTERNAL:
2609         str = "Internal Server Error";
2610         break;
2611     case RTSP_STATUS_SERVICE:
2612         str = "Service Unavailable";
2613         break;
2614     case RTSP_STATUS_VERSION:
2615         str = "RTSP Version not supported";
2616         break;
2617     default:
2618         str = "Unknown Error";
2619         break;
2620     }
2621
2622     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2623     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2624
2625     /* output GMT time */
2626     ti = time(NULL);
2627     p = ctime(&ti);
2628     strcpy(buf2, p);
2629     p = buf2 + strlen(p) - 1;
2630     if (*p == '\n')
2631         *p = '\0';
2632     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2633 }
2634
2635 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2636 {
2637     rtsp_reply_header(c, error_number);
2638     url_fprintf(c->pb, "\r\n");
2639 }
2640
2641 static int rtsp_parse_request(HTTPContext *c)
2642 {
2643     const char *p, *p1, *p2;
2644     char cmd[32];
2645     char url[1024];
2646     char protocol[32];
2647     char line[1024];
2648     int len;
2649     RTSPMessageHeader header1, *header = &header1;
2650
2651     c->buffer_ptr[0] = '\0';
2652     p = c->buffer;
2653
2654     get_word(cmd, sizeof(cmd), &p);
2655     get_word(url, sizeof(url), &p);
2656     get_word(protocol, sizeof(protocol), &p);
2657
2658     av_strlcpy(c->method, cmd, sizeof(c->method));
2659     av_strlcpy(c->url, url, sizeof(c->url));
2660     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2661
2662     if (url_open_dyn_buf(&c->pb) < 0) {
2663         /* XXX: cannot do more */
2664         c->pb = NULL; /* safety */
2665         return -1;
2666     }
2667
2668     /* check version name */
2669     if (strcmp(protocol, "RTSP/1.0") != 0) {
2670         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2671         goto the_end;
2672     }
2673
2674     /* parse each header line */
2675     memset(header, 0, sizeof(*header));
2676     /* skip to next line */
2677     while (*p != '\n' && *p != '\0')
2678         p++;
2679     if (*p == '\n')
2680         p++;
2681     while (*p != '\0') {
2682         p1 = strchr(p, '\n');
2683         if (!p1)
2684             break;
2685         p2 = p1;
2686         if (p2 > p && p2[-1] == '\r')
2687             p2--;
2688         /* skip empty line */
2689         if (p2 == p)
2690             break;
2691         len = p2 - p;
2692         if (len > sizeof(line) - 1)
2693             len = sizeof(line) - 1;
2694         memcpy(line, p, len);
2695         line[len] = '\0';
2696         rtsp_parse_line(header, line);
2697         p = p1 + 1;
2698     }
2699
2700     /* handle sequence number */
2701     c->seq = header->seq;
2702
2703     if (!strcmp(cmd, "DESCRIBE"))
2704         rtsp_cmd_describe(c, url);
2705     else if (!strcmp(cmd, "OPTIONS"))
2706         rtsp_cmd_options(c, url);
2707     else if (!strcmp(cmd, "SETUP"))
2708         rtsp_cmd_setup(c, url, header);
2709     else if (!strcmp(cmd, "PLAY"))
2710         rtsp_cmd_play(c, url, header);
2711     else if (!strcmp(cmd, "PAUSE"))
2712         rtsp_cmd_pause(c, url, header);
2713     else if (!strcmp(cmd, "TEARDOWN"))
2714         rtsp_cmd_teardown(c, url, header);
2715     else
2716         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2717
2718  the_end:
2719     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2720     c->pb = NULL; /* safety */
2721     if (len < 0) {
2722         /* XXX: cannot do more */
2723         return -1;
2724     }
2725     c->buffer_ptr = c->pb_buffer;
2726     c->buffer_end = c->pb_buffer + len;
2727     c->state = RTSPSTATE_SEND_REPLY;
2728     return 0;
2729 }
2730
2731 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2732                                    struct in_addr my_ip)
2733 {
2734     AVFormatContext *avc;
2735     AVStream avs[MAX_STREAMS];
2736     int i;
2737
2738     avc =  avformat_alloc_context();
2739     if (avc == NULL) {
2740         return -1;
2741     }
2742     av_metadata_set(&avc->metadata, "title",
2743                     stream->title[0] ? stream->title : "No Title");
2744     avc->nb_streams = stream->nb_streams;
2745     if (stream->is_multicast) {
2746         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2747                  inet_ntoa(stream->multicast_ip),
2748                  stream->multicast_port, stream->multicast_ttl);
2749     }
2750
2751     for(i = 0; i < stream->nb_streams; i++) {
2752         avc->streams[i] = &avs[i];
2753         avc->streams[i]->codec = stream->streams[i]->codec;
2754     }
2755     *pbuffer = av_mallocz(2048);
2756     avf_sdp_create(&avc, 1, *pbuffer, 2048);
2757     av_free(avc);
2758
2759     return strlen(*pbuffer);
2760 }
2761
2762 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2763 {
2764 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2765     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2766     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2767     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2768     url_fprintf(c->pb, "\r\n");
2769 }
2770
2771 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2772 {
2773     FFStream *stream;
2774     char path1[1024];
2775     const char *path;
2776     uint8_t *content;
2777     int content_length, len;
2778     struct sockaddr_in my_addr;
2779
2780     /* find which url is asked */
2781     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2782     path = path1;
2783     if (*path == '/')
2784         path++;
2785
2786     for(stream = first_stream; stream != NULL; stream = stream->next) {
2787         if (!stream->is_feed &&
2788             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2789             !strcmp(path, stream->filename)) {
2790             goto found;
2791         }
2792     }
2793     /* no stream found */
2794     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2795     return;
2796
2797  found:
2798     /* prepare the media description in sdp format */
2799
2800     /* get the host IP */
2801     len = sizeof(my_addr);
2802     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2803     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2804     if (content_length < 0) {
2805         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2806         return;
2807     }
2808     rtsp_reply_header(c, RTSP_STATUS_OK);
2809     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2810     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2811     url_fprintf(c->pb, "\r\n");
2812     put_buffer(c->pb, content, content_length);
2813 }
2814
2815 static HTTPContext *find_rtp_session(const char *session_id)
2816 {
2817     HTTPContext *c;
2818
2819     if (session_id[0] == '\0')
2820         return NULL;
2821
2822     for(c = first_http_ctx; c != NULL; c = c->next) {
2823         if (!strcmp(c->session_id, session_id))
2824             return c;
2825     }
2826     return NULL;
2827 }
2828
2829 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2830 {
2831     RTSPTransportField *th;
2832     int i;
2833
2834     for(i=0;i<h->nb_transports;i++) {
2835         th = &h->transports[i];
2836         if (th->lower_transport == lower_transport)
2837             return th;
2838     }
2839     return NULL;
2840 }
2841
2842 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2843                            RTSPMessageHeader *h)
2844 {
2845     FFStream *stream;
2846     int stream_index, port;
2847     char buf[1024];
2848     char path1[1024];
2849     const char *path;
2850     HTTPContext *rtp_c;
2851     RTSPTransportField *th;
2852     struct sockaddr_in dest_addr;
2853     RTSPActionServerSetup setup;
2854
2855     /* find which url is asked */
2856     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2857     path = path1;
2858     if (*path == '/')
2859         path++;
2860
2861     /* now check each stream */
2862     for(stream = first_stream; stream != NULL; stream = stream->next) {
2863         if (!stream->is_feed &&
2864             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2865             /* accept aggregate filenames only if single stream */
2866             if (!strcmp(path, stream->filename)) {
2867                 if (stream->nb_streams != 1) {
2868                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2869                     return;
2870                 }
2871                 stream_index = 0;
2872                 goto found;
2873             }
2874
2875             for(stream_index = 0; stream_index < stream->nb_streams;
2876                 stream_index++) {
2877                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2878                          stream->filename, stream_index);
2879                 if (!strcmp(path, buf))
2880                     goto found;
2881             }
2882         }
2883     }
2884     /* no stream found */
2885     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2886     return;
2887  found:
2888
2889     /* generate session id if needed */
2890     if (h->session_id[0] == '\0')
2891         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2892                  av_lfg_get(&random_state), av_lfg_get(&random_state));
2893
2894     /* find rtp session, and create it if none found */
2895     rtp_c = find_rtp_session(h->session_id);
2896     if (!rtp_c) {
2897         /* always prefer UDP */
2898         th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2899         if (!th) {
2900             th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2901             if (!th) {
2902                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2903                 return;
2904             }
2905         }
2906
2907         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2908                                    th->lower_transport);
2909         if (!rtp_c) {
2910             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2911             return;
2912         }
2913
2914         /* open input stream */
2915         if (open_input_stream(rtp_c, "") < 0) {
2916             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2917             return;
2918         }
2919     }
2920
2921     /* test if stream is OK (test needed because several SETUP needs
2922        to be done for a given file) */
2923     if (rtp_c->stream != stream) {
2924         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2925         return;
2926     }
2927
2928     /* test if stream is already set up */
2929     if (rtp_c->rtp_ctx[stream_index]) {
2930         rtsp_reply_error(c, RTSP_STATUS_STATE);
2931         return;
2932     }
2933
2934     /* check transport */
2935     th = find_transport(h, rtp_c->rtp_protocol);
2936     if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2937                 th->client_port_min <= 0)) {
2938         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2939         return;
2940     }
2941
2942     /* setup default options */
2943     setup.transport_option[0] = '\0';
2944     dest_addr = rtp_c->from_addr;
2945     dest_addr.sin_port = htons(th->client_port_min);
2946
2947     /* setup stream */
2948     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2949         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2950         return;
2951     }
2952
2953     /* now everything is OK, so we can send the connection parameters */
2954     rtsp_reply_header(c, RTSP_STATUS_OK);
2955     /* session ID */
2956     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2957
2958     switch(rtp_c->rtp_protocol) {
2959     case RTSP_LOWER_TRANSPORT_UDP:
2960         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2961         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2962                     "client_port=%d-%d;server_port=%d-%d",
2963                     th->client_port_min, th->client_port_min + 1,
2964                     port, port + 1);
2965         break;
2966     case RTSP_LOWER_TRANSPORT_TCP:
2967         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2968                     stream_index * 2, stream_index * 2 + 1);
2969         break;
2970     default:
2971         break;
2972     }
2973     if (setup.transport_option[0] != '\0')
2974         url_fprintf(c->pb, ";%s", setup.transport_option);
2975     url_fprintf(c->pb, "\r\n");
2976
2977
2978     url_fprintf(c->pb, "\r\n");
2979 }
2980
2981
2982 /* find an rtp connection by using the session ID. Check consistency
2983    with filename */
2984 static HTTPContext *find_rtp_session_with_url(const char *url,
2985                                               const char *session_id)
2986 {
2987     HTTPContext *rtp_c;
2988     char path1[1024];
2989     const char *path;
2990     char buf[1024];
2991     int s;
2992
2993     rtp_c = find_rtp_session(session_id);
2994     if (!rtp_c)
2995         return NULL;
2996
2997     /* find which url is asked */
2998     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2999     path = path1;
3000     if (*path == '/')
3001         path++;
3002     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3003     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3004       snprintf(buf, sizeof(buf), "%s/streamid=%d",
3005         rtp_c->stream->filename, s);
3006       if(!strncmp(path, buf, sizeof(buf))) {
3007     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3008         return rtp_c;
3009       }
3010     }
3011     return NULL;
3012 }
3013
3014 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3015 {
3016     HTTPContext *rtp_c;
3017
3018     rtp_c = find_rtp_session_with_url(url, h->session_id);
3019     if (!rtp_c) {
3020         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3021         return;
3022     }
3023
3024     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3025         rtp_c->state != HTTPSTATE_WAIT_FEED &&
3026         rtp_c->state != HTTPSTATE_READY) {
3027         rtsp_reply_error(c, RTSP_STATUS_STATE);
3028         return;
3029     }
3030
3031     rtp_c->state = HTTPSTATE_SEND_DATA;
3032
3033     /* now everything is OK, so we can send the connection parameters */
3034     rtsp_reply_header(c, RTSP_STATUS_OK);
3035     /* session ID */
3036     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3037     url_fprintf(c->pb, "\r\n");
3038 }
3039
3040 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3041 {
3042     HTTPContext *rtp_c;
3043
3044     rtp_c = find_rtp_session_with_url(url, h->session_id);
3045     if (!rtp_c) {
3046         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3047         return;
3048     }
3049
3050     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3051         rtp_c->state != HTTPSTATE_WAIT_FEED) {
3052         rtsp_reply_error(c, RTSP_STATUS_STATE);
3053         return;
3054     }
3055
3056     rtp_c->state = HTTPSTATE_READY;
3057     rtp_c->first_pts = AV_NOPTS_VALUE;
3058     /* now everything is OK, so we can send the connection parameters */
3059     rtsp_reply_header(c, RTSP_STATUS_OK);
3060     /* session ID */
3061     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3062     url_fprintf(c->pb, "\r\n");
3063 }
3064
3065 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3066 {
3067     HTTPContext *rtp_c;
3068     char session_id[32];
3069
3070     rtp_c = find_rtp_session_with_url(url, h->session_id);
3071     if (!rtp_c) {
3072         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3073         return;
3074     }
3075
3076     av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3077
3078     /* abort the session */
3079     close_connection(rtp_c);
3080
3081     /* now everything is OK, so we can send the connection parameters */
3082     rtsp_reply_header(c, RTSP_STATUS_OK);
3083     /* session ID */
3084     url_fprintf(c->pb, "Session: %s\r\n", session_id);
3085     url_fprintf(c->pb, "\r\n");
3086 }
3087
3088
3089 /********************************************************************/
3090 /* RTP handling */
3091
3092 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3093                                        FFStream *stream, const char *session_id,
3094                                        enum RTSPLowerTransport rtp_protocol)
3095 {
3096     HTTPContext *c = NULL;
3097     const char *proto_str;
3098
3099     /* XXX: should output a warning page when coming
3100        close to the connection limit */
3101     if (nb_connections >= nb_max_connections)
3102         goto fail;
3103
3104     /* add a new connection */
3105     c = av_mallocz(sizeof(HTTPContext));
3106     if (!c)
3107         goto fail;
3108
3109     c->fd = -1;
3110     c->poll_entry = NULL;
3111     c->from_addr = *from_addr;
3112     c->buffer_size = IOBUFFER_INIT_SIZE;
3113     c->buffer = av_malloc(c->buffer_size);
3114     if (!c->buffer)
3115         goto fail;
3116     nb_connections++;
3117     c->stream = stream;
3118     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3119     c->state = HTTPSTATE_READY;
3120     c->is_packetized = 1;
3121     c->rtp_protocol = rtp_protocol;
3122
3123     /* protocol is shown in statistics */
3124     switch(c->rtp_protocol) {
3125     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3126         proto_str = "MCAST";
3127         break;
3128     case RTSP_LOWER_TRANSPORT_UDP:
3129         proto_str = "UDP";
3130         break;
3131     case RTSP_LOWER_TRANSPORT_TCP:
3132         proto_str = "TCP";
3133         break;
3134     default:
3135         proto_str = "???";
3136         break;
3137     }
3138     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3139     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3140
3141     current_bandwidth += stream->bandwidth;
3142
3143     c->next = first_http_ctx;
3144     first_http_ctx = c;
3145     return c;
3146
3147  fail:
3148     if (c) {
3149         av_free(c->buffer);
3150         av_free(c);
3151     }
3152     return NULL;
3153 }
3154
3155 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3156    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3157    used. */
3158 static int rtp_new_av_stream(HTTPContext *c,
3159                              int stream_index, struct sockaddr_in *dest_addr,
3160                              HTTPContext *rtsp_c)
3161 {
3162     AVFormatContext *ctx;
3163     AVStream *st;
3164     char *ipaddr;
3165     URLContext *h = NULL;
3166     uint8_t *dummy_buf;
3167     int max_packet_size;
3168
3169     /* now we can open the relevant output stream */
3170     ctx = avformat_alloc_context();
3171     if (!ctx)
3172         return -1;
3173     ctx->oformat = guess_format("rtp", NULL, NULL);
3174
3175     st = av_mallocz(sizeof(AVStream));
3176     if (!st)
3177         goto fail;
3178     st->codec= avcodec_alloc_context();
3179     ctx->nb_streams = 1;
3180     ctx->streams[0] = st;
3181
3182     if (!c->stream->feed ||
3183         c->stream->feed == c->stream)
3184         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3185     else
3186         memcpy(st,
3187                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3188                sizeof(AVStream));
3189     st->priv_data = NULL;
3190
3191     /* build destination RTP address */
3192     ipaddr = inet_ntoa(dest_addr->sin_addr);
3193
3194     switch(c->rtp_protocol) {
3195     case RTSP_LOWER_TRANSPORT_UDP:
3196     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3197         /* RTP/UDP case */
3198
3199         /* XXX: also pass as parameter to function ? */
3200         if (c->stream->is_multicast) {
3201             int ttl;
3202             ttl = c->stream->multicast_ttl;
3203             if (!ttl)
3204                 ttl = 16;
3205             snprintf(ctx->filename, sizeof(ctx->filename),
3206                      "rtp://%s:%d?multicast=1&ttl=%d",
3207                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3208         } else {
3209             snprintf(ctx->filename, sizeof(ctx->filename),
3210                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3211         }
3212
3213         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3214             goto fail;
3215         c->rtp_handles[stream_index] = h;
3216         max_packet_size = url_get_max_packet_size(h);
3217         break;
3218     case RTSP_LOWER_TRANSPORT_TCP:
3219         /* RTP/TCP case */
3220         c->rtsp_c = rtsp_c;
3221         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3222         break;
3223     default:
3224         goto fail;
3225     }
3226
3227     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3228              ipaddr, ntohs(dest_addr->sin_port),
3229              c->stream->filename, stream_index, c->protocol);
3230
3231     /* normally, no packets should be output here, but the packet size may be checked */
3232     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3233         /* XXX: close stream */
3234         goto fail;
3235     }
3236     av_set_parameters(ctx, NULL);
3237     if (av_write_header(ctx) < 0) {
3238     fail:
3239         if (h)
3240             url_close(h);
3241         av_free(ctx);
3242         return -1;
3243     }
3244     url_close_dyn_buf(ctx->pb, &dummy_buf);
3245     av_free(dummy_buf);
3246
3247     c->rtp_ctx[stream_index] = ctx;
3248     return 0;
3249 }
3250
3251 /********************************************************************/
3252 /* ffserver initialization */
3253
3254 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3255 {
3256     AVStream *fst;
3257
3258     fst = av_mallocz(sizeof(AVStream));
3259     if (!fst)
3260         return NULL;
3261     fst->codec= avcodec_alloc_context();
3262     fst->priv_data = av_mallocz(sizeof(FeedData));
3263     memcpy(fst->codec, codec, sizeof(AVCodecContext));
3264     fst->index = stream->nb_streams;
3265     av_set_pts_info(fst, 33, 1, 90000);
3266     stream->streams[stream->nb_streams++] = fst;
3267     return fst;
3268 }
3269
3270 /* return the stream number in the feed */
3271 static int add_av_stream(FFStream *feed, AVStream *st)
3272 {
3273     AVStream *fst;
3274     AVCodecContext *av, *av1;
3275     int i;
3276
3277     av = st->codec;
3278     for(i=0;i<feed->nb_streams;i++) {
3279         st = feed->streams[i];
3280         av1 = st->codec;
3281         if (av1->codec_id == av->codec_id &&
3282             av1->codec_type == av->codec_type &&
3283             av1->bit_rate == av->bit_rate) {
3284
3285             switch(av->codec_type) {
3286             case CODEC_TYPE_AUDIO:
3287                 if (av1->channels == av->channels &&
3288                     av1->sample_rate == av->sample_rate)
3289                     goto found;
3290                 break;
3291             case CODEC_TYPE_VIDEO:
3292                 if (av1->width == av->width &&
3293                     av1->height == av->height &&
3294                     av1->time_base.den == av->time_base.den &&
3295                     av1->time_base.num == av->time_base.num &&
3296                     av1->gop_size == av->gop_size)
3297                     goto found;
3298                 break;
3299             default:
3300                 abort();
3301             }
3302         }
3303     }
3304
3305     fst = add_av_stream1(feed, av);
3306     if (!fst)
3307         return -1;
3308     return feed->nb_streams - 1;
3309  found:
3310     return i;
3311 }
3312
3313 static void remove_stream(FFStream *stream)
3314 {
3315     FFStream **ps;
3316     ps = &first_stream;
3317     while (*ps != NULL) {
3318         if (*ps == stream)
3319             *ps = (*ps)->next;
3320         else
3321             ps = &(*ps)->next;
3322     }
3323 }
3324
3325 /* specific mpeg4 handling : we extract the raw parameters */
3326 static void extract_mpeg4_header(AVFormatContext *infile)
3327 {
3328     int mpeg4_count, i, size;
3329     AVPacket pkt;
3330     AVStream *st;
3331     const uint8_t *p;
3332
3333     mpeg4_count = 0;
3334     for(i=0;i<infile->nb_streams;i++) {
3335         st = infile->streams[i];
3336         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3337             st->codec->extradata_size == 0) {
3338             mpeg4_count++;
3339         }
3340     }
3341     if (!mpeg4_count)
3342         return;
3343
3344     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3345     while (mpeg4_count > 0) {
3346         if (av_read_packet(infile, &pkt) < 0)
3347             break;
3348         st = infile->streams[pkt.stream_index];
3349         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3350             st->codec->extradata_size == 0) {
3351             av_freep(&st->codec->extradata);
3352             /* fill extradata with the header */
3353             /* XXX: we make hard suppositions here ! */
3354             p = pkt.data;
3355             while (p < pkt.data + pkt.size - 4) {
3356                 /* stop when vop header is found */
3357                 if (p[0] == 0x00 && p[1] == 0x00 &&
3358                     p[2] == 0x01 && p[3] == 0xb6) {
3359                     size = p - pkt.data;
3360                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3361                     st->codec->extradata = av_malloc(size);
3362                     st->codec->extradata_size = size;
3363                     memcpy(st->codec->extradata, pkt.data, size);
3364                     break;
3365                 }
3366                 p++;
3367             }
3368             mpeg4_count--;
3369         }
3370         av_free_packet(&pkt);
3371     }
3372 }
3373
3374 /* compute the needed AVStream for each file */
3375 static void build_file_streams(void)
3376 {
3377     FFStream *stream, *stream_next;
3378     AVFormatContext *infile;
3379     int i, ret;
3380
3381     /* gather all streams */
3382     for(stream = first_stream; stream != NULL; stream = stream_next) {
3383         stream_next = stream->next;
3384         if (stream->stream_type == STREAM_TYPE_LIVE &&
3385             !stream->feed) {
3386             /* the stream comes from a file */
3387             /* try to open the file */
3388             /* open stream */
3389             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3390             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3391                 /* specific case : if transport stream output to RTP,
3392                    we use a raw transport stream reader */
3393                 stream->ap_in->mpeg2ts_raw = 1;
3394                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3395             }
3396
3397             http_log("Opening file '%s'\n", stream->feed_filename);
3398             if ((ret = av_open_input_file(&infile, stream->feed_filename,
3399                                           stream->ifmt, 0, stream->ap_in)) < 0) {
3400                 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3401                 /* remove stream (no need to spend more time on it) */
3402             fail:
3403                 remove_stream(stream);
3404             } else {
3405                 /* find all the AVStreams inside and reference them in
3406                    'stream' */
3407                 if (av_find_stream_info(infile) < 0) {
3408                     http_log("Could not find codec parameters from '%s'\n",
3409                              stream->feed_filename);
3410                     av_close_input_file(infile);
3411                     goto fail;
3412                 }
3413                 extract_mpeg4_header(infile);
3414
3415                 for(i=0;i<infile->nb_streams;i++)
3416                     add_av_stream1(stream, infile->streams[i]->codec);
3417
3418                 av_close_input_file(infile);
3419             }
3420         }
3421     }
3422 }
3423
3424 /* compute the needed AVStream for each feed */
3425 static void build_feed_streams(void)
3426 {
3427     FFStream *stream, *feed;
3428     int i;
3429
3430     /* gather all streams */
3431     for(stream = first_stream; stream != NULL; stream = stream->next) {
3432         feed = stream->feed;
3433         if (feed) {
3434             if (!stream->is_feed) {
3435                 /* we handle a stream coming from a feed */
3436                 for(i=0;i<stream->nb_streams;i++)
3437                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3438             }
3439         }
3440     }
3441
3442     /* gather all streams */
3443     for(stream = first_stream; stream != NULL; stream = stream->next) {
3444         feed = stream->feed;
3445         if (feed) {
3446             if (stream->is_feed) {
3447                 for(i=0;i<stream->nb_streams;i++)
3448                     stream->feed_streams[i] = i;
3449             }
3450         }
3451     }
3452
3453     /* create feed files if needed */
3454     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3455         int fd;
3456
3457         if (url_exist(feed->feed_filename)) {
3458             /* See if it matches */
3459             AVFormatContext *s;
3460             int matches = 0;
3461
3462             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3463                 /* Now see if it matches */
3464                 if (s->nb_streams == feed->nb_streams) {
3465                     matches = 1;
3466                     for(i=0;i<s->nb_streams;i++) {
3467                         AVStream *sf, *ss;
3468                         sf = feed->streams[i];
3469                         ss = s->streams[i];
3470
3471                         if (sf->index != ss->index ||
3472                             sf->id != ss->id) {
3473                             http_log("Index & Id do not match for stream %d (%s)\n",
3474                                    i, feed->feed_filename);
3475                             matches = 0;
3476                         } else {
3477                             AVCodecContext *ccf, *ccs;
3478
3479                             ccf = sf->codec;
3480                             ccs = ss->codec;
3481 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3482
3483                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3484                                 http_log("Codecs do not match for stream %d\n", i);
3485                                 matches = 0;
3486                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3487                                 http_log("Codec bitrates do not match for stream %d\n", i);
3488                                 matches = 0;
3489                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3490                                 if (CHECK_CODEC(time_base.den) ||
3491                                     CHECK_CODEC(time_base.num) ||
3492                                     CHECK_CODEC(width) ||
3493                                     CHECK_CODEC(height)) {
3494                                     http_log("Codec width, height and framerate do not match for stream %d\n", i);
3495                                     matches = 0;
3496                                 }
3497                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3498                                 if (CHECK_CODEC(sample_rate) ||
3499                                     CHECK_CODEC(channels) ||
3500                                     CHECK_CODEC(frame_size)) {
3501                                     http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3502                                     matches = 0;
3503                                 }
3504                             } else {
3505                                 http_log("Unknown codec type\n");
3506                                 matches = 0;
3507                             }
3508                         }
3509                         if (!matches)
3510                             break;
3511                     }
3512                 } else
3513                     http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3514                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3515
3516                 av_close_input_file(s);
3517             } else
3518                 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3519                         feed->feed_filename);
3520
3521             if (!matches) {
3522                 if (feed->readonly) {
3523                     http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3524                         feed->feed_filename);
3525                     exit(1);
3526                 }
3527                 unlink(feed->feed_filename);
3528             }
3529         }
3530         if (!url_exist(feed->feed_filename)) {
3531             AVFormatContext s1 = {0}, *s = &s1;
3532
3533             if (feed->readonly) {
3534                 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3535                     feed->feed_filename);
3536                 exit(1);
3537             }
3538
3539             /* only write the header of the ffm file */
3540             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3541                 http_log("Could not open output feed file '%s'\n",
3542                          feed->feed_filename);
3543                 exit(1);
3544             }
3545             s->oformat = feed->fmt;
3546             s->nb_streams = feed->nb_streams;
3547             for(i=0;i<s->nb_streams;i++) {
3548                 AVStream *st;
3549                 st = feed->streams[i];
3550                 s->streams[i] = st;
3551             }
3552             av_set_parameters(s, NULL);
3553             if (av_write_header(s) < 0) {
3554                 http_log("Container doesn't supports the required parameters\n");
3555                 exit(1);
3556             }
3557             /* XXX: need better api */
3558             av_freep(&s->priv_data);
3559             url_fclose(s->pb);
3560         }
3561         /* get feed size and write index */
3562         fd = open(feed->feed_filename, O_RDONLY);
3563         if (fd < 0) {
3564             http_log("Could not open output feed file '%s'\n",
3565                     feed->feed_filename);
3566             exit(1);
3567         }
3568
3569         feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3570         feed->feed_size = lseek(fd, 0, SEEK_END);
3571         /* ensure that we do not wrap before the end of file */
3572         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3573             feed->feed_max_size = feed->feed_size;
3574
3575         close(fd);
3576     }
3577 }
3578
3579 /* compute the bandwidth used by each stream */
3580 static void compute_bandwidth(void)
3581 {
3582     unsigned bandwidth;
3583     int i;
3584     FFStream *stream;
3585
3586     for(stream = first_stream; stream != NULL; stream = stream->next) {
3587         bandwidth = 0;
3588         for(i=0;i<stream->nb_streams;i++) {
3589             AVStream *st = stream->streams[i];
3590             switch(st->codec->codec_type) {
3591             case CODEC_TYPE_AUDIO:
3592             case CODEC_TYPE_VIDEO:
3593                 bandwidth += st->codec->bit_rate;
3594                 break;
3595             default:
3596                 break;
3597             }
3598         }
3599         stream->bandwidth = (bandwidth + 999) / 1000;
3600     }
3601 }
3602
3603 /* add a codec and set the default parameters */
3604 static void add_codec(FFStream *stream, AVCodecContext *av)
3605 {
3606     AVStream *st;
3607
3608     /* compute default parameters */
3609     switch(av->codec_type) {
3610     case CODEC_TYPE_AUDIO:
3611         if (av->bit_rate == 0)
3612             av->bit_rate = 64000;
3613         if (av->sample_rate == 0)
3614             av->sample_rate = 22050;
3615         if (av->channels == 0)
3616             av->channels = 1;
3617         break;
3618     case CODEC_TYPE_VIDEO:
3619         if (av->bit_rate == 0)
3620             av->bit_rate = 64000;
3621         if (av->time_base.num == 0){
3622             av->time_base.den = 5;
3623             av->time_base.num = 1;
3624         }
3625         if (av->width == 0 || av->height == 0) {
3626             av->width = 160;
3627             av->height = 128;
3628         }
3629         /* Bitrate tolerance is less for streaming */
3630         if (av->bit_rate_tolerance == 0)
3631             av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3632                       (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3633         if (av->qmin == 0)
3634             av->qmin = 3;
3635         if (av->qmax == 0)
3636             av->qmax = 31;
3637         if (av->max_qdiff == 0)
3638             av->max_qdiff = 3;
3639         av->qcompress = 0.5;
3640         av->qblur = 0.5;
3641
3642         if (!av->nsse_weight)
3643             av->nsse_weight = 8;
3644
3645         av->frame_skip_cmp = FF_CMP_DCTMAX;
3646         av->me_method = ME_EPZS;
3647         av->rc_buffer_aggressivity = 1.0;
3648
3649         if (!av->rc_eq)
3650             av->rc_eq = "tex^qComp";
3651         if (!av->i_quant_factor)
3652             av->i_quant_factor = -0.8;
3653         if (!av->b_quant_factor)
3654             av->b_quant_factor = 1.25;
3655         if (!av->b_quant_offset)
3656             av->b_quant_offset = 1.25;
3657         if (!av->rc_max_rate)
3658             av->rc_max_rate = av->bit_rate * 2;
3659
3660         if (av->rc_max_rate && !av->rc_buffer_size) {
3661             av->rc_buffer_size = av->rc_max_rate;
3662         }
3663
3664
3665         break;
3666     default:
3667         abort();
3668     }
3669
3670     st = av_mallocz(sizeof(AVStream));
3671     if (!st)
3672         return;
3673     st->codec = avcodec_alloc_context();
3674     stream->streams[stream->nb_streams++] = st;
3675     memcpy(st->codec, av, sizeof(AVCodecContext));
3676 }
3677
3678 static enum CodecID opt_audio_codec(const char *arg)
3679 {
3680     AVCodec *p= avcodec_find_encoder_by_name(arg);
3681
3682     if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3683         return CODEC_ID_NONE;
3684
3685     return p->id;
3686 }
3687
3688 static enum CodecID opt_video_codec(const char *arg)
3689 {
3690     AVCodec *p= avcodec_find_encoder_by_name(arg);
3691
3692     if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3693         return CODEC_ID_NONE;
3694
3695     return p->id;
3696 }
3697
3698 /* simplistic plugin support */
3699
3700 #if HAVE_DLOPEN
3701 static void load_module(const char *filename)
3702 {
3703     void *dll;
3704     void (*init_func)(void);
3705     dll = dlopen(filename, RTLD_NOW);
3706     if (!dll) {
3707         fprintf(stderr, "Could not load module '%s' - %s\n",
3708                 filename, dlerror());
3709         return;
3710     }
3711
3712     init_func = dlsym(dll, "ffserver_module_init");
3713     if (!init_func) {
3714         fprintf(stderr,
3715                 "%s: init function 'ffserver_module_init()' not found\n",
3716                 filename);
3717         dlclose(dll);
3718     }
3719
3720     init_func();
3721 }
3722 #endif
3723
3724 static int ffserver_opt_default(const char *opt, const char *arg,
3725                        AVCodecContext *avctx, int type)
3726 {
3727     int ret = 0;
3728     const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3729     if(o)
3730         ret = av_set_string3(avctx, opt, arg, 1, NULL);
3731     return ret;
3732 }
3733
3734 static int parse_ffconfig(const char *filename)
3735 {
3736     FILE *f;
3737     char line[1024];
3738     char cmd[64];
3739     char arg[1024];
3740     const char *p;
3741     int val, errors, line_num;
3742     FFStream **last_stream, *stream, *redirect;
3743     FFStream **last_feed, *feed, *s;
3744     AVCodecContext audio_enc, video_enc;
3745     enum CodecID audio_id, video_id;
3746
3747     f = fopen(filename, "r");
3748     if (!f) {
3749         perror(filename);
3750         return -1;
3751     }
3752
3753     errors = 0;
3754     line_num = 0;
3755     first_stream = NULL;
3756     last_stream = &first_stream;
3757     first_feed = NULL;
3758     last_feed = &first_feed;
3759     stream = NULL;
3760     feed = NULL;
3761     redirect = NULL;
3762     audio_id = CODEC_ID_NONE;
3763     video_id = CODEC_ID_NONE;
3764     for(;;) {
3765         if (fgets(line, sizeof(line), f) == NULL)
3766             break;
3767         line_num++;
3768         p = line;
3769         while (isspace(*p))
3770             p++;
3771         if (*p == '\0' || *p == '#')
3772             continue;
3773
3774         get_arg(cmd, sizeof(cmd), &p);
3775
3776         if (!strcasecmp(cmd, "Port")) {
3777             get_arg(arg, sizeof(arg), &p);
3778             val = atoi(arg);
3779             if (val < 1 || val > 65536) {
3780                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3781                         filename, line_num, arg);
3782                 errors++;
3783             }
3784             my_http_addr.sin_port = htons(val);
3785         } else if (!strcasecmp(cmd, "BindAddress")) {
3786             get_arg(arg, sizeof(arg), &p);
3787             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3788                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3789                         filename, line_num, arg);
3790                 errors++;
3791             }
3792         } else if (!strcasecmp(cmd, "NoDaemon")) {
3793             ffserver_daemon = 0;
3794         } else if (!strcasecmp(cmd, "RTSPPort")) {
3795             get_arg(arg, sizeof(arg), &p);
3796             val = atoi(arg);
3797             if (val < 1 || val > 65536) {
3798                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3799                         filename, line_num, arg);
3800                 errors++;
3801             }
3802             my_rtsp_addr.sin_port = htons(atoi(arg));
3803         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3804             get_arg(arg, sizeof(arg), &p);
3805             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3806                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3807                         filename, line_num, arg);
3808                 errors++;
3809             }
3810         } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3811             get_arg(arg, sizeof(arg), &p);
3812             val = atoi(arg);
3813             if (val < 1 || val > 65536) {
3814                 fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3815                         filename, line_num, arg);
3816                 errors++;
3817             }
3818             nb_max_http_connections = val;
3819         } else if (!strcasecmp(cmd, "MaxClients")) {
3820             get_arg(arg, sizeof(arg), &p);
3821             val = atoi(arg);
3822             if (val < 1 || val > nb_max_http_connections) {
3823                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3824                         filename, line_num, arg);
3825                 errors++;
3826             } else {
3827                 nb_max_connections = val;
3828             }
3829         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3830             int64_t llval;
3831             get_arg(arg, sizeof(arg), &p);
3832             llval = atoll(arg);
3833             if (llval < 10 || llval > 10000000) {
3834                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3835                         filename, line_num, arg);
3836                 errors++;
3837             } else
3838                 max_bandwidth = llval;
3839         } else if (!strcasecmp(cmd, "CustomLog")) {
3840             if (!ffserver_debug)
3841                 get_arg(logfilename, sizeof(logfilename), &p);
3842         } else if (!strcasecmp(cmd, "<Feed")) {
3843             /*********************************************/
3844             /* Feed related options */
3845             char *q;
3846             if (stream || feed) {
3847                 fprintf(stderr, "%s:%d: Already in a tag\n",
3848                         filename, line_num);
3849             } else {
3850                 feed = av_mallocz(sizeof(FFStream));
3851                 get_arg(feed->filename, sizeof(feed->filename), &p);
3852                 q = strrchr(feed->filename, '>');
3853                 if (*q)
3854                     *q = '\0';
3855
3856                 for (s = first_feed; s; s = s->next) {
3857                     if (!strcmp(feed->filename, s->filename)) {
3858                         fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3859                                 filename, line_num, s->filename);
3860                         errors++;
3861                     }
3862                 }
3863
3864                 feed->fmt = guess_format("ffm", NULL, NULL);
3865                 /* defaut feed file */
3866                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3867                          "/tmp/%s.ffm", feed->filename);
3868                 feed->feed_max_size = 5 * 1024 * 1024;
3869                 feed->is_feed = 1;
3870                 feed->feed = feed; /* self feeding :-) */
3871
3872                 /* add in stream list */
3873                 *last_stream = feed;
3874                 last_stream = &feed->next;
3875                 /* add in feed list */
3876                 *last_feed = feed;
3877                 last_feed = &feed->next_feed;
3878             }
3879         } else if (!strcasecmp(cmd, "Launch")) {
3880             if (feed) {
3881                 int i;
3882
3883                 feed->child_argv = av_mallocz(64 * sizeof(char *));
3884
3885                 for (i = 0; i < 62; i++) {
3886                     get_arg(arg, sizeof(arg), &p);
3887                     if (!arg[0])
3888                         break;
3889
3890                     feed->child_argv[i] = av_strdup(arg);
3891                 }
3892
3893                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3894
3895                 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3896                     "http://%s:%d/%s",
3897                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3898                     inet_ntoa(my_http_addr.sin_addr),
3899                     ntohs(my_http_addr.sin_port), feed->filename);
3900             }
3901         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3902             if (feed) {
3903                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3904                 feed->readonly = 1;
3905             } else if (stream) {
3906                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3907             }
3908         } else if (!strcasecmp(cmd, "File")) {
3909             if (feed) {
3910                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3911             } else if (stream)
3912                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3913         } else if (!strcasecmp(cmd, "Truncate")) {
3914             if (feed) {
3915                 get_arg(arg, sizeof(arg), &p);
3916                 feed->truncate = strtod(arg, NULL);
3917             }
3918         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3919             if (feed) {
3920                 char *p1;
3921                 double fsize;
3922
3923                 get_arg(arg, sizeof(arg), &p);
3924                 p1 = arg;
3925                 fsize = strtod(p1, &p1);
3926                 switch(toupper(*p1)) {
3927                 case 'K':
3928                     fsize *= 1024;
3929                     break;
3930                 case 'M':
3931                     fsize *= 1024 * 1024;
3932                     break;
3933                 case 'G':
3934                     fsize *= 1024 * 1024 * 1024;
3935                     break;
3936                 }
3937                 feed->feed_max_size = (int64_t)fsize;
3938                 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
3939                     fprintf(stderr, "%s:%d: Feed max file size is too small, "
3940                             "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
3941                     errors++;
3942                 }
3943             }
3944         } else if (!strcasecmp(cmd, "</Feed>")) {
3945             if (!feed) {
3946                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3947                         filename, line_num);
3948                 errors++;
3949             }
3950             feed = NULL;
3951         } else if (!strcasecmp(cmd, "<Stream")) {
3952             /*********************************************/
3953             /* Stream related options */
3954             char *q;
3955             if (stream || feed) {
3956                 fprintf(stderr, "%s:%d: Already in a tag\n",
3957                         filename, line_num);
3958             } else {
3959                 FFStream *s;
3960                 const AVClass *class;
3961                 stream = av_mallocz(sizeof(FFStream));
3962                 get_arg(stream->filename, sizeof(stream->filename), &p);
3963                 q = strrchr(stream->filename, '>');
3964                 if (*q)
3965                     *q = '\0';
3966
3967                 for (s = first_stream; s; s = s->next) {
3968                     if (!strcmp(stream->filename, s->filename)) {
3969                         fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
3970                                 filename, line_num, s->filename);
3971                         errors++;
3972                     }
3973                 }
3974
3975                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3976                 /* fetch avclass so AVOption works
3977                  * FIXME try to use avcodec_get_context_defaults2
3978                  * without changing defaults too much */
3979                 avcodec_get_context_defaults(&video_enc);
3980                 class = video_enc.av_class;
3981                 memset(&audio_enc, 0, sizeof(AVCodecContext));
3982                 memset(&video_enc, 0, sizeof(AVCodecContext));
3983                 audio_enc.av_class = class;
3984                 video_enc.av_class = class;
3985                 audio_id = CODEC_ID_NONE;
3986                 video_id = CODEC_ID_NONE;
3987                 if (stream->fmt) {
3988                     audio_id = stream->fmt->audio_codec;
3989                     video_id = stream->fmt->video_codec;
3990                 }
3991
3992                 *last_stream = stream;
3993                 last_stream = &stream->next;
3994             }
3995         } else if (!strcasecmp(cmd, "Feed")) {
3996             get_arg(arg, sizeof(arg), &p);
3997             if (stream) {
3998                 FFStream *sfeed;
3999
4000                 sfeed = first_feed;
4001                 while (sfeed != NULL) {
4002                     if (!strcmp(sfeed->filename, arg))
4003                         break;
4004                     sfeed = sfeed->next_feed;
4005                 }
4006                 if (!sfeed)
4007                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4008                             filename, line_num, arg);
4009                 else
4010                     stream->feed = sfeed;
4011             }
4012         } else if (!strcasecmp(cmd, "Format")) {
4013             get_arg(arg, sizeof(arg), &p);
4014             if (stream) {
4015                 if (!strcmp(arg, "status")) {
4016                     stream->stream_type = STREAM_TYPE_STATUS;
4017                     stream->fmt = NULL;
4018                 } else {
4019                     stream->stream_type = STREAM_TYPE_LIVE;
4020                     /* jpeg cannot be used here, so use single frame jpeg */
4021                     if (!strcmp(arg, "jpeg"))
4022                         strcpy(arg, "mjpeg");
4023                     stream->fmt = guess_stream_format(arg, NULL, NULL);
4024                     if (!stream->fmt) {
4025                         fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4026                                 filename, line_num, arg);
4027                         errors++;
4028                     }
4029                 }
4030                 if (stream->fmt) {
4031                     audio_id = stream->fmt->audio_codec;
4032                     video_id = stream->fmt->video_codec;
4033                 }
4034             }
4035         } else if (!strcasecmp(cmd, "InputFormat")) {
4036             get_arg(arg, sizeof(arg), &p);
4037             if (stream) {
4038                 stream->ifmt = av_find_input_format(arg);
4039                 if (!stream->ifmt) {
4040                     fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4041                             filename, line_num, arg);
4042                 }
4043             }
4044         } else if (!strcasecmp(cmd, "FaviconURL")) {
4045             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4046                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4047             } else {
4048                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4049                             filename, line_num);
4050                 errors++;
4051             }
4052         } else if (!strcasecmp(cmd, "Author")) {
4053             if (stream)
4054                 get_arg(stream->author, sizeof(stream->author), &p);
4055         } else if (!strcasecmp(cmd, "Comment")) {
4056             if (stream)
4057                 get_arg(stream->comment, sizeof(stream->comment), &p);
4058         } else if (!strcasecmp(cmd, "Copyright")) {
4059             if (stream)
4060                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4061         } else if (!strcasecmp(cmd, "Title")) {
4062             if (stream)
4063                 get_arg(stream->title, sizeof(stream->title), &p);
4064         } else if (!strcasecmp(cmd, "Preroll")) {
4065             get_arg(arg, sizeof(arg), &p);
4066             if (stream)
4067                 stream->prebuffer = atof(arg) * 1000;
4068         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4069             if (stream)
4070                 stream->send_on_key = 1;
4071         } else if (!strcasecmp(cmd, "AudioCodec")) {
4072             get_arg(arg, sizeof(arg), &p);
4073             audio_id = opt_audio_codec(arg);
4074             if (audio_id == CODEC_ID_NONE) {
4075                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4076                         filename, line_num, arg);
4077                 errors++;
4078             }
4079         } else if (!strcasecmp(cmd, "VideoCodec")) {
4080             get_arg(arg, sizeof(arg), &p);
4081             video_id = opt_video_codec(arg);
4082             if (video_id == CODEC_ID_NONE) {
4083                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4084                         filename, line_num, arg);
4085                 errors++;
4086             }
4087         } else if (!strcasecmp(cmd, "MaxTime")) {
4088             get_arg(arg, sizeof(arg), &p);
4089             if (stream)
4090                 stream->max_time = atof(arg) * 1000;
4091         } else if (!strcasecmp(cmd, "AudioBitRate")) {
4092             get_arg(arg, sizeof(arg), &p);
4093             if (stream)
4094                 audio_enc.bit_rate = atoi(arg) * 1000;
4095         } else if (!strcasecmp(cmd, "AudioChannels")) {
4096             get_arg(arg, sizeof(arg), &p);
4097             if (stream)
4098                 audio_enc.channels = atoi(arg);
4099         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4100             get_arg(arg, sizeof(arg), &p);
4101             if (stream)
4102                 audio_enc.sample_rate = atoi(arg);
4103         } else if (!strcasecmp(cmd, "AudioQuality")) {
4104             get_arg(arg, sizeof(arg), &p);
4105             if (stream) {
4106 //                audio_enc.quality = atof(arg) * 1000;
4107             }
4108         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4109             if (stream) {
4110                 int minrate, maxrate;
4111
4112                 get_arg(arg, sizeof(arg), &p);
4113
4114                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4115                     video_enc.rc_min_rate = minrate * 1000;
4116                     video_enc.rc_max_rate = maxrate * 1000;
4117                 } else {
4118                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4119                             filename, line_num, arg);
4120                     errors++;
4121                 }
4122             }
4123         } else if (!strcasecmp(cmd, "Debug")) {
4124             if (stream) {
4125                 get_arg(arg, sizeof(arg), &p);
4126                 video_enc.debug = strtol(arg,0,0);
4127             }
4128         } else if (!strcasecmp(cmd, "Strict")) {
4129             if (stream) {
4130                 get_arg(arg, sizeof(arg), &p);
4131                 video_enc.strict_std_compliance = atoi(arg);
4132             }
4133         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4134             if (stream) {
4135                 get_arg(arg, sizeof(arg), &p);
4136                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4137             }
4138         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4139             if (stream) {
4140                 get_arg(arg, sizeof(arg), &p);
4141                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4142             }
4143         } else if (!strcasecmp(cmd, "VideoBitRate")) {
4144             get_arg(arg, sizeof(arg), &p);
4145             if (stream) {
4146                 video_enc.bit_rate = atoi(arg) * 1000;
4147             }
4148         } else if (!strcasecmp(cmd, "VideoSize")) {
4149             get_arg(arg, sizeof(arg), &p);
4150             if (stream) {
4151                 av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4152                 if ((video_enc.width % 16) != 0 ||
4153                     (video_enc.height % 16) != 0) {
4154                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4155                             filename, line_num);
4156                     errors++;
4157                 }
4158             }
4159         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4160             get_arg(arg, sizeof(arg), &p);
4161             if (stream) {
4162                 AVRational frame_rate;
4163                 if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4164                     fprintf(stderr, "Incorrect frame rate\n");
4165                     errors++;
4166                 } else {
4167                     video_enc.time_base.num = frame_rate.den;
4168                     video_enc.time_base.den = frame_rate.num;
4169                 }
4170             }
4171         } else if (!strcasecmp(cmd, "VideoGopSize")) {
4172             get_arg(arg, sizeof(arg), &p);
4173             if (stream)
4174                 video_enc.gop_size = atoi(arg);
4175         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4176             if (stream)
4177                 video_enc.gop_size = 1;
4178         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4179             if (stream)
4180                 video_enc.mb_decision = FF_MB_DECISION_BITS;
4181         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4182             if (stream) {
4183                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4184                 video_enc.flags |= CODEC_FLAG_4MV;
4185             }
4186         } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4187                    !strcasecmp(cmd, "AVOptionAudio")) {
4188             char arg2[1024];
4189             AVCodecContext *avctx;
4190             int type;
4191             get_arg(arg, sizeof(arg), &p);
4192             get_arg(arg2, sizeof(arg2), &p);
4193             if (!strcasecmp(cmd, "AVOptionVideo")) {
4194                 avctx = &video_enc;
4195                 type = AV_OPT_FLAG_VIDEO_PARAM;
4196             } else {
4197                 avctx = &audio_enc;
4198                 type = AV_OPT_FLAG_AUDIO_PARAM;
4199             }
4200             if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4201                 fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4202                 errors++;
4203             }
4204         } else if (!strcasecmp(cmd, "VideoTag")) {
4205             get_arg(arg, sizeof(arg), &p);
4206             if ((strlen(arg) == 4) && stream)
4207                 video_enc.codec_tag = AV_RL32(arg);
4208         } else if (!strcasecmp(cmd, "BitExact")) {
4209             if (stream)
4210                 video_enc.flags |= CODEC_FLAG_BITEXACT;
4211         } else if (!strcasecmp(cmd, "DctFastint")) {
4212             if (stream)
4213                 video_enc.dct_algo  = FF_DCT_FASTINT;
4214         } else if (!strcasecmp(cmd, "IdctSimple")) {
4215             if (stream)
4216                 video_enc.idct_algo = FF_IDCT_SIMPLE;
4217         } else if (!strcasecmp(cmd, "Qscale")) {
4218             get_arg(arg, sizeof(arg), &p);
4219             if (stream) {
4220                 video_enc.flags |= CODEC_FLAG_QSCALE;
4221                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4222             }
4223         } else if (!strcasecmp(cmd, "VideoQDiff")) {
4224             get_arg(arg, sizeof(arg), &p);
4225             if (stream) {
4226                 video_enc.max_qdiff = atoi(arg);
4227                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4228                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4229                             filename, line_num);
4230                     errors++;
4231                 }
4232             }
4233         } else if (!strcasecmp(cmd, "VideoQMax")) {
4234             get_arg(arg, sizeof(arg), &p);
4235             if (stream) {
4236                 video_enc.qmax = atoi(arg);
4237                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4238                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4239                             filename, line_num);
4240                     errors++;
4241                 }
4242             }
4243         } else if (!strcasecmp(cmd, "VideoQMin")) {
4244             get_arg(arg, sizeof(arg), &p);
4245             if (stream) {
4246                 video_enc.qmin = atoi(arg);
4247                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4248                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4249                             filename, line_num);
4250                     errors++;
4251                 }
4252             }
4253         } else if (!strcasecmp(cmd, "LumaElim")) {
4254             get_arg(arg, sizeof(arg), &p);
4255             if (stream)
4256                 video_enc.luma_elim_threshold = atoi(arg);
4257         } else if (!strcasecmp(cmd, "ChromaElim")) {
4258             get_arg(arg, sizeof(arg), &p);
4259             if (stream)
4260                 video_enc.chroma_elim_threshold = atoi(arg);
4261         } else if (!strcasecmp(cmd, "LumiMask")) {
4262             get_arg(arg, sizeof(arg), &p);
4263             if (stream)
4264                 video_enc.lumi_masking = atof(arg);
4265         } else if (!strcasecmp(cmd, "DarkMask")) {
4266             get_arg(arg, sizeof(arg), &p);
4267             if (stream)
4268                 video_enc.dark_masking = atof(arg);
4269         } else if (!strcasecmp(cmd, "NoVideo")) {
4270             video_id = CODEC_ID_NONE;
4271         } else if (!strcasecmp(cmd, "NoAudio")) {
4272             audio_id = CODEC_ID_NONE;
4273         } else if (!strcasecmp(cmd, "ACL")) {
4274             IPAddressACL acl;
4275
4276             get_arg(arg, sizeof(arg), &p);
4277             if (strcasecmp(arg, "allow") == 0)
4278                 acl.action = IP_ALLOW;
4279             else if (strcasecmp(arg, "deny") == 0)
4280                 acl.action = IP_DENY;
4281             else {
4282                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4283                         filename, line_num, arg);
4284                 errors++;
4285             }
4286
4287             get_arg(arg, sizeof(arg), &p);
4288
4289             if (resolve_host(&acl.first, arg) != 0) {
4290                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4291                         filename, line_num, arg);
4292                 errors++;
4293             } else
4294                 acl.last = acl.first;
4295
4296             get_arg(arg, sizeof(arg), &p);
4297
4298             if (arg[0]) {
4299                 if (resolve_host(&acl.last, arg) != 0) {
4300                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4301                             filename, line_num, arg);
4302                     errors++;
4303                 }
4304             }
4305
4306             if (!errors) {
4307                 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4308                 IPAddressACL **naclp = 0;
4309
4310                 acl.next = 0;
4311                 *nacl = acl;
4312
4313                 if (stream)
4314                     naclp = &stream->acl;
4315                 else if (feed)
4316                     naclp = &feed->acl;
4317                 else {
4318                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4319                             filename, line_num);
4320                     errors++;
4321                 }
4322
4323                 if (naclp) {
4324                     while (*naclp)
4325                         naclp = &(*naclp)->next;
4326
4327                     *naclp = nacl;
4328                 }
4329             }
4330         } else if (!strcasecmp(cmd, "RTSPOption")) {
4331             get_arg(arg, sizeof(arg), &p);
4332             if (stream) {
4333                 av_freep(&stream->rtsp_option);
4334                 stream->rtsp_option = av_strdup(arg);
4335             }
4336         } else if (!strcasecmp(cmd, "MulticastAddress")) {
4337             get_arg(arg, sizeof(arg), &p);
4338             if (stream) {
4339                 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4340                     fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4341                             filename, line_num, arg);
4342                     errors++;
4343                 }
4344                 stream->is_multicast = 1;
4345                 stream->loop = 1; /* default is looping */
4346             }
4347         } else if (!strcasecmp(cmd, "MulticastPort")) {
4348             get_arg(arg, sizeof(arg), &p);
4349             if (stream)
4350                 stream->multicast_port = atoi(arg);
4351         } else if (!strcasecmp(cmd, "MulticastTTL")) {
4352             get_arg(arg, sizeof(arg), &p);
4353             if (stream)
4354                 stream->multicast_ttl = atoi(arg);
4355         } else if (!strcasecmp(cmd, "NoLoop")) {
4356             if (stream)
4357                 stream->loop = 0;
4358         } else if (!strcasecmp(cmd, "</Stream>")) {
4359             if (!stream) {
4360                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4361                         filename, line_num);
4362                 errors++;
4363             } else {
4364                 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4365                     if (audio_id != CODEC_ID_NONE) {
4366                         audio_enc.codec_type = CODEC_TYPE_AUDIO;
4367                         audio_enc.codec_id = audio_id;
4368                         add_codec(stream, &audio_enc);
4369                     }
4370                     if (video_id != CODEC_ID_NONE) {
4371                         video_enc.codec_type = CODEC_TYPE_VIDEO;
4372                         video_enc.codec_id = video_id;
4373                         add_codec(stream, &video_enc);
4374                     }
4375                 }
4376                 stream = NULL;
4377             }
4378         } else if (!strcasecmp(cmd, "<Redirect")) {
4379             /*********************************************/
4380             char *q;
4381             if (stream || feed || redirect) {
4382                 fprintf(stderr, "%s:%d: Already in a tag\n",
4383                         filename, line_num);
4384                 errors++;
4385             } else {
4386                 redirect = av_mallocz(sizeof(FFStream));
4387                 *last_stream = redirect;
4388                 last_stream = &redirect->next;
4389
4390                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4391                 q = strrchr(redirect->filename, '>');
4392                 if (*q)
4393                     *q = '\0';
4394                 redirect->stream_type = STREAM_TYPE_REDIRECT;
4395             }
4396         } else if (!strcasecmp(cmd, "URL")) {
4397             if (redirect)
4398                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4399         } else if (!strcasecmp(cmd, "</Redirect>")) {
4400             if (!redirect) {
4401                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4402                         filename, line_num);
4403                 errors++;
4404             } else {
4405                 if (!redirect->feed_filename[0]) {
4406                     fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4407                             filename, line_num);
4408                     errors++;
4409                 }
4410                 redirect = NULL;
4411             }
4412         } else if (!strcasecmp(cmd, "LoadModule")) {
4413             get_arg(arg, sizeof(arg), &p);
4414 #if HAVE_DLOPEN
4415             load_module(arg);
4416 #else
4417             fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4418                     filename, line_num, arg);
4419             errors++;
4420 #endif
4421         } else {
4422             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4423                     filename, line_num, cmd);
4424         }
4425     }
4426
4427     fclose(f);
4428     if (errors)
4429         return -1;
4430     else
4431         return 0;
4432 }
4433
4434 static void handle_child_exit(int sig)
4435 {
4436     pid_t pid;
4437     int status;
4438
4439     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4440         FFStream *feed;
4441
4442         for (feed = first_feed; feed; feed = feed->next) {
4443             if (feed->pid == pid) {
4444                 int uptime = time(0) - feed->pid_start;
4445
4446                 feed->pid = 0;
4447                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4448
4449                 if (uptime < 30)
4450                     /* Turn off any more restarts */
4451                     feed->child_argv = 0;
4452             }
4453         }
4454     }
4455
4456     need_to_start_children = 1;
4457 }
4458
4459 static void opt_debug(void)
4460 {
4461     ffserver_debug = 1;
4462     ffserver_daemon = 0;
4463     logfilename[0] = '-';
4464 }
4465
4466 static void opt_show_help(void)
4467 {
4468     printf("usage: ffserver [options]\n"
4469            "Hyper fast multi format Audio/Video streaming server\n");
4470     printf("\n");
4471     show_help_options(options, "Main options:\n", 0, 0);
4472 }
4473
4474 static const OptionDef options[] = {
4475     { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4476     { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4477     { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4478     { "formats"  , OPT_EXIT, {(void*)show_formats  }, "show available formats" },
4479     { "codecs"   , OPT_EXIT, {(void*)show_codecs   }, "show available codecs" },
4480     { "bsfs"     , OPT_EXIT, {(void*)show_bsfs     }, "show available bit stream filters" },
4481     { "protocols", OPT_EXIT, {(void*)show_protocols}, "show available protocols" },
4482     { "loglevel", HAS_ARG | OPT_FUNC2, {(void*)opt_loglevel}, "set libav* logging level", "loglevel" },
4483     { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4484     { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4485     { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4486     { NULL },
4487 };
4488
4489 int main(int argc, char **argv)
4490 {
4491     struct sigaction sigact;
4492
4493     av_register_all();
4494
4495     show_banner();
4496
4497     config_filename = "/etc/ffserver.conf";
4498
4499     my_program_name = argv[0];
4500     my_program_dir = getcwd(0, 0);
4501     ffserver_daemon = 1;
4502
4503     parse_options(argc, argv, options, NULL);
4504
4505     unsetenv("http_proxy");             /* Kill the http_proxy */
4506
4507     av_lfg_init(&random_state, ff_random_get_seed());
4508
4509     memset(&sigact, 0, sizeof(sigact));
4510     sigact.sa_handler = handle_child_exit;
4511     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4512     sigaction(SIGCHLD, &sigact, 0);
4513
4514     if (parse_ffconfig(config_filename) < 0) {
4515         fprintf(stderr, "Incorrect config file - exiting.\n");
4516         exit(1);
4517     }
4518
4519     /* open log file if needed */
4520     if (logfilename[0] != '\0') {
4521         if (!strcmp(logfilename, "-"))
4522             logfile = stdout;
4523         else
4524             logfile = fopen(logfilename, "a");
4525         av_log_set_callback(http_av_log);
4526     }
4527
4528     build_file_streams();
4529
4530     build_feed_streams();
4531
4532     compute_bandwidth();
4533
4534     /* put the process in background and detach it from its TTY */
4535     if (ffserver_daemon) {
4536         int pid;
4537
4538         pid = fork();
4539         if (pid < 0) {
4540             perror("fork");
4541             exit(1);
4542         } else if (pid > 0) {
4543             /* parent : exit */
4544             exit(0);
4545         } else {
4546             /* child */
4547             setsid();
4548             close(0);
4549             open("/dev/null", O_RDWR);
4550             if (strcmp(logfilename, "-") != 0) {
4551                 close(1);
4552                 dup(0);
4553             }
4554             close(2);
4555             dup(0);
4556         }
4557     }
4558
4559     /* signal init */
4560     signal(SIGPIPE, SIG_IGN);
4561
4562     if (ffserver_daemon)
4563         chdir("/");
4564
4565     if (http_server() < 0) {
4566         http_log("Could not start server\n");
4567         exit(1);
4568     }
4569
4570     return 0;
4571 }