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