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