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