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