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