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