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