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