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