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