OSDN Git Service

Check return value of ffm_write_write_index and ffm_read_write_index.
[coroid/libav_saccubus.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     if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2417         http_log("Error reading write index from feed file: %s\n", strerror(errno));
2418         return -1;
2419     }
2420     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2421     lseek(fd, 0, SEEK_SET);
2422
2423     /* init buffer input */
2424     c->buffer_ptr = c->buffer;
2425     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2426     c->stream->feed_opened = 1;
2427     return 0;
2428 }
2429
2430 static int http_receive_data(HTTPContext *c)
2431 {
2432     HTTPContext *c1;
2433
2434     if (c->buffer_end > c->buffer_ptr) {
2435         int len;
2436
2437         len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2438         if (len < 0) {
2439             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2440                 ff_neterrno() != FF_NETERROR(EINTR))
2441                 /* error : close connection */
2442                 goto fail;
2443         } else if (len == 0)
2444             /* end of connection : close it */
2445             goto fail;
2446         else {
2447             c->buffer_ptr += len;
2448             c->data_count += len;
2449             update_datarate(&c->datarate, c->data_count);
2450         }
2451     }
2452
2453     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2454         if (c->buffer[0] != 'f' ||
2455             c->buffer[1] != 'm') {
2456             http_log("Feed stream has become desynchronized -- disconnecting\n");
2457             goto fail;
2458         }
2459     }
2460
2461     if (c->buffer_ptr >= c->buffer_end) {
2462         FFStream *feed = c->stream;
2463         /* a packet has been received : write it in the store, except
2464            if header */
2465         if (c->data_count > FFM_PACKET_SIZE) {
2466
2467             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2468             /* XXX: use llseek or url_seek */
2469             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2470             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2471                 http_log("Error writing to feed file: %s\n", strerror(errno));
2472                 goto fail;
2473             }
2474
2475             feed->feed_write_index += FFM_PACKET_SIZE;
2476             /* update file size */
2477             if (feed->feed_write_index > c->stream->feed_size)
2478                 feed->feed_size = feed->feed_write_index;
2479
2480             /* handle wrap around if max file size reached */
2481             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2482                 feed->feed_write_index = FFM_PACKET_SIZE;
2483
2484             /* write index */
2485             if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2486                 http_log("Error writing index to feed file: %s\n", strerror(errno));
2487                 goto fail;
2488             }
2489
2490             /* wake up any waiting connections */
2491             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2492                 if (c1->state == HTTPSTATE_WAIT_FEED &&
2493                     c1->stream->feed == c->stream->feed)
2494                     c1->state = HTTPSTATE_SEND_DATA;
2495             }
2496         } else {
2497             /* We have a header in our hands that contains useful data */
2498             AVFormatContext *s = NULL;
2499             ByteIOContext *pb;
2500             AVInputFormat *fmt_in;
2501             int i;
2502
2503             /* use feed output format name to find corresponding input format */
2504             fmt_in = av_find_input_format(feed->fmt->name);
2505             if (!fmt_in)
2506                 goto fail;
2507
2508             url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2509             pb->is_streamed = 1;
2510
2511             if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2512                 av_free(pb);
2513                 goto fail;
2514             }
2515
2516             /* Now we have the actual streams */
2517             if (s->nb_streams != feed->nb_streams) {
2518                 av_close_input_stream(s);
2519                 av_free(pb);
2520                 goto fail;
2521             }
2522
2523             for (i = 0; i < s->nb_streams; i++) {
2524                 AVStream *fst = feed->streams[i];
2525                 AVStream *st = s->streams[i];
2526                 memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2527                 if (fst->codec->extradata_size) {
2528                     fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2529                     if (!fst->codec->extradata)
2530                         goto fail;
2531                     memcpy(fst->codec->extradata, st->codec->extradata,
2532                            fst->codec->extradata_size);
2533                 }
2534             }
2535
2536             av_close_input_stream(s);
2537             av_free(pb);
2538         }
2539         c->buffer_ptr = c->buffer;
2540     }
2541
2542     return 0;
2543  fail:
2544     c->stream->feed_opened = 0;
2545     close(c->feed_fd);
2546     /* wake up any waiting connections to stop waiting for feed */
2547     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2548         if (c1->state == HTTPSTATE_WAIT_FEED &&
2549             c1->stream->feed == c->stream->feed)
2550             c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2551     }
2552     return -1;
2553 }
2554
2555 /********************************************************************/
2556 /* RTSP handling */
2557
2558 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2559 {
2560     const char *str;
2561     time_t ti;
2562     char *p;
2563     char buf2[32];
2564
2565     switch(error_number) {
2566     case RTSP_STATUS_OK:
2567         str = "OK";
2568         break;
2569     case RTSP_STATUS_METHOD:
2570         str = "Method Not Allowed";
2571         break;
2572     case RTSP_STATUS_BANDWIDTH:
2573         str = "Not Enough Bandwidth";
2574         break;
2575     case RTSP_STATUS_SESSION:
2576         str = "Session Not Found";
2577         break;
2578     case RTSP_STATUS_STATE:
2579         str = "Method Not Valid in This State";
2580         break;
2581     case RTSP_STATUS_AGGREGATE:
2582         str = "Aggregate operation not allowed";
2583         break;
2584     case RTSP_STATUS_ONLY_AGGREGATE:
2585         str = "Only aggregate operation allowed";
2586         break;
2587     case RTSP_STATUS_TRANSPORT:
2588         str = "Unsupported transport";
2589         break;
2590     case RTSP_STATUS_INTERNAL:
2591         str = "Internal Server Error";
2592         break;
2593     case RTSP_STATUS_SERVICE:
2594         str = "Service Unavailable";
2595         break;
2596     case RTSP_STATUS_VERSION:
2597         str = "RTSP Version not supported";
2598         break;
2599     default:
2600         str = "Unknown Error";
2601         break;
2602     }
2603
2604     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2605     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2606
2607     /* output GMT time */
2608     ti = time(NULL);
2609     p = ctime(&ti);
2610     strcpy(buf2, p);
2611     p = buf2 + strlen(p) - 1;
2612     if (*p == '\n')
2613         *p = '\0';
2614     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2615 }
2616
2617 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2618 {
2619     rtsp_reply_header(c, error_number);
2620     url_fprintf(c->pb, "\r\n");
2621 }
2622
2623 static int rtsp_parse_request(HTTPContext *c)
2624 {
2625     const char *p, *p1, *p2;
2626     char cmd[32];
2627     char url[1024];
2628     char protocol[32];
2629     char line[1024];
2630     int len;
2631     RTSPHeader header1, *header = &header1;
2632
2633     c->buffer_ptr[0] = '\0';
2634     p = c->buffer;
2635
2636     get_word(cmd, sizeof(cmd), &p);
2637     get_word(url, sizeof(url), &p);
2638     get_word(protocol, sizeof(protocol), &p);
2639
2640     av_strlcpy(c->method, cmd, sizeof(c->method));
2641     av_strlcpy(c->url, url, sizeof(c->url));
2642     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2643
2644     if (url_open_dyn_buf(&c->pb) < 0) {
2645         /* XXX: cannot do more */
2646         c->pb = NULL; /* safety */
2647         return -1;
2648     }
2649
2650     /* check version name */
2651     if (strcmp(protocol, "RTSP/1.0") != 0) {
2652         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2653         goto the_end;
2654     }
2655
2656     /* parse each header line */
2657     memset(header, 0, sizeof(RTSPHeader));
2658     /* skip to next line */
2659     while (*p != '\n' && *p != '\0')
2660         p++;
2661     if (*p == '\n')
2662         p++;
2663     while (*p != '\0') {
2664         p1 = strchr(p, '\n');
2665         if (!p1)
2666             break;
2667         p2 = p1;
2668         if (p2 > p && p2[-1] == '\r')
2669             p2--;
2670         /* skip empty line */
2671         if (p2 == p)
2672             break;
2673         len = p2 - p;
2674         if (len > sizeof(line) - 1)
2675             len = sizeof(line) - 1;
2676         memcpy(line, p, len);
2677         line[len] = '\0';
2678         rtsp_parse_line(header, line);
2679         p = p1 + 1;
2680     }
2681
2682     /* handle sequence number */
2683     c->seq = header->seq;
2684
2685     if (!strcmp(cmd, "DESCRIBE"))
2686         rtsp_cmd_describe(c, url);
2687     else if (!strcmp(cmd, "OPTIONS"))
2688         rtsp_cmd_options(c, url);
2689     else if (!strcmp(cmd, "SETUP"))
2690         rtsp_cmd_setup(c, url, header);
2691     else if (!strcmp(cmd, "PLAY"))
2692         rtsp_cmd_play(c, url, header);
2693     else if (!strcmp(cmd, "PAUSE"))
2694         rtsp_cmd_pause(c, url, header);
2695     else if (!strcmp(cmd, "TEARDOWN"))
2696         rtsp_cmd_teardown(c, url, header);
2697     else
2698         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2699
2700  the_end:
2701     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2702     c->pb = NULL; /* safety */
2703     if (len < 0) {
2704         /* XXX: cannot do more */
2705         return -1;
2706     }
2707     c->buffer_ptr = c->pb_buffer;
2708     c->buffer_end = c->pb_buffer + len;
2709     c->state = RTSPSTATE_SEND_REPLY;
2710     return 0;
2711 }
2712
2713 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2714                                    struct in_addr my_ip)
2715 {
2716     AVFormatContext *avc;
2717     AVStream avs[MAX_STREAMS];
2718     int i;
2719
2720     avc =  avformat_alloc_context();
2721     if (avc == NULL) {
2722         return -1;
2723     }
2724     if (stream->title[0] != 0) {
2725         av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2726     } else {
2727         av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2728     }
2729     avc->nb_streams = stream->nb_streams;
2730     if (stream->is_multicast) {
2731         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2732                  inet_ntoa(stream->multicast_ip),
2733                  stream->multicast_port, stream->multicast_ttl);
2734     }
2735
2736     for(i = 0; i < stream->nb_streams; i++) {
2737         avc->streams[i] = &avs[i];
2738         avc->streams[i]->codec = stream->streams[i]->codec;
2739     }
2740     *pbuffer = av_mallocz(2048);
2741     avf_sdp_create(&avc, 1, *pbuffer, 2048);
2742     av_free(avc);
2743
2744     return strlen(*pbuffer);
2745 }
2746
2747 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2748 {
2749 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2750     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2751     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2752     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2753     url_fprintf(c->pb, "\r\n");
2754 }
2755
2756 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2757 {
2758     FFStream *stream;
2759     char path1[1024];
2760     const char *path;
2761     uint8_t *content;
2762     int content_length, len;
2763     struct sockaddr_in my_addr;
2764
2765     /* find which url is asked */
2766     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2767     path = path1;
2768     if (*path == '/')
2769         path++;
2770
2771     for(stream = first_stream; stream != NULL; stream = stream->next) {
2772         if (!stream->is_feed &&
2773             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2774             !strcmp(path, stream->filename)) {
2775             goto found;
2776         }
2777     }
2778     /* no stream found */
2779     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2780     return;
2781
2782  found:
2783     /* prepare the media description in sdp format */
2784
2785     /* get the host IP */
2786     len = sizeof(my_addr);
2787     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2788     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2789     if (content_length < 0) {
2790         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2791         return;
2792     }
2793     rtsp_reply_header(c, RTSP_STATUS_OK);
2794     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2795     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2796     url_fprintf(c->pb, "\r\n");
2797     put_buffer(c->pb, content, content_length);
2798 }
2799
2800 static HTTPContext *find_rtp_session(const char *session_id)
2801 {
2802     HTTPContext *c;
2803
2804     if (session_id[0] == '\0')
2805         return NULL;
2806
2807     for(c = first_http_ctx; c != NULL; c = c->next) {
2808         if (!strcmp(c->session_id, session_id))
2809             return c;
2810     }
2811     return NULL;
2812 }
2813
2814 static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPLowerTransport lower_transport)
2815 {
2816     RTSPTransportField *th;
2817     int i;
2818
2819     for(i=0;i<h->nb_transports;i++) {
2820         th = &h->transports[i];
2821         if (th->lower_transport == lower_transport)
2822             return th;
2823     }
2824     return NULL;
2825 }
2826
2827 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2828                            RTSPHeader *h)
2829 {
2830     FFStream *stream;
2831     int stream_index, port;
2832     char buf[1024];
2833     char path1[1024];
2834     const char *path;
2835     HTTPContext *rtp_c;
2836     RTSPTransportField *th;
2837     struct sockaddr_in dest_addr;
2838     RTSPActionServerSetup setup;
2839
2840     /* find which url is asked */
2841     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2842     path = path1;
2843     if (*path == '/')
2844         path++;
2845
2846     /* now check each stream */
2847     for(stream = first_stream; stream != NULL; stream = stream->next) {
2848         if (!stream->is_feed &&
2849             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2850             /* accept aggregate filenames only if single stream */
2851             if (!strcmp(path, stream->filename)) {
2852                 if (stream->nb_streams != 1) {
2853                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2854                     return;
2855                 }
2856                 stream_index = 0;
2857                 goto found;
2858             }
2859
2860             for(stream_index = 0; stream_index < stream->nb_streams;
2861                 stream_index++) {
2862                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2863                          stream->filename, stream_index);
2864                 if (!strcmp(path, buf))
2865                     goto found;
2866             }
2867         }
2868     }
2869     /* no stream found */
2870     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2871     return;
2872  found:
2873
2874     /* generate session id if needed */
2875     if (h->session_id[0] == '\0')
2876         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2877                  av_random(&random_state), av_random(&random_state));
2878
2879     /* find rtp session, and create it if none found */
2880     rtp_c = find_rtp_session(h->session_id);
2881     if (!rtp_c) {
2882         /* always prefer UDP */
2883         th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2884         if (!th) {
2885             th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2886             if (!th) {
2887                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2888                 return;
2889             }
2890         }
2891
2892         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2893                                    th->lower_transport);
2894         if (!rtp_c) {
2895             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2896             return;
2897         }
2898
2899         /* open input stream */
2900         if (open_input_stream(rtp_c, "") < 0) {
2901             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2902             return;
2903         }
2904     }
2905
2906     /* test if stream is OK (test needed because several SETUP needs
2907        to be done for a given file) */
2908     if (rtp_c->stream != stream) {
2909         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2910         return;
2911     }
2912
2913     /* test if stream is already set up */
2914     if (rtp_c->rtp_ctx[stream_index]) {
2915         rtsp_reply_error(c, RTSP_STATUS_STATE);
2916         return;
2917     }
2918
2919     /* check transport */
2920     th = find_transport(h, rtp_c->rtp_protocol);
2921     if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2922                 th->client_port_min <= 0)) {
2923         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2924         return;
2925     }
2926
2927     /* setup default options */
2928     setup.transport_option[0] = '\0';
2929     dest_addr = rtp_c->from_addr;
2930     dest_addr.sin_port = htons(th->client_port_min);
2931
2932     /* setup stream */
2933     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2934         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2935         return;
2936     }
2937
2938     /* now everything is OK, so we can send the connection parameters */
2939     rtsp_reply_header(c, RTSP_STATUS_OK);
2940     /* session ID */
2941     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2942
2943     switch(rtp_c->rtp_protocol) {
2944     case RTSP_LOWER_TRANSPORT_UDP:
2945         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2946         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2947                     "client_port=%d-%d;server_port=%d-%d",
2948                     th->client_port_min, th->client_port_min + 1,
2949                     port, port + 1);
2950         break;
2951     case RTSP_LOWER_TRANSPORT_TCP:
2952         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2953                     stream_index * 2, stream_index * 2 + 1);
2954         break;
2955     default:
2956         break;
2957     }
2958     if (setup.transport_option[0] != '\0')
2959         url_fprintf(c->pb, ";%s", setup.transport_option);
2960     url_fprintf(c->pb, "\r\n");
2961
2962
2963     url_fprintf(c->pb, "\r\n");
2964 }
2965
2966
2967 /* find an rtp connection by using the session ID. Check consistency
2968    with filename */
2969 static HTTPContext *find_rtp_session_with_url(const char *url,
2970                                               const char *session_id)
2971 {
2972     HTTPContext *rtp_c;
2973     char path1[1024];
2974     const char *path;
2975     char buf[1024];
2976     int s;
2977
2978     rtp_c = find_rtp_session(session_id);
2979     if (!rtp_c)
2980         return NULL;
2981
2982     /* find which url is asked */
2983     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2984     path = path1;
2985     if (*path == '/')
2986         path++;
2987     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2988     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2989       snprintf(buf, sizeof(buf), "%s/streamid=%d",
2990         rtp_c->stream->filename, s);
2991       if(!strncmp(path, buf, sizeof(buf))) {
2992     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2993         return rtp_c;
2994       }
2995     }
2996     return NULL;
2997 }
2998
2999 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
3000 {
3001     HTTPContext *rtp_c;
3002
3003     rtp_c = find_rtp_session_with_url(url, h->session_id);
3004     if (!rtp_c) {
3005         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3006         return;
3007     }
3008
3009     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3010         rtp_c->state != HTTPSTATE_WAIT_FEED &&
3011         rtp_c->state != HTTPSTATE_READY) {
3012         rtsp_reply_error(c, RTSP_STATUS_STATE);
3013         return;
3014     }
3015
3016 #if 0
3017     /* XXX: seek in stream */
3018     if (h->range_start != AV_NOPTS_VALUE) {
3019         printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
3020         av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
3021     }
3022 #endif
3023
3024     rtp_c->state = HTTPSTATE_SEND_DATA;
3025
3026     /* now everything is OK, so we can send the connection parameters */
3027     rtsp_reply_header(c, RTSP_STATUS_OK);
3028     /* session ID */
3029     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3030     url_fprintf(c->pb, "\r\n");
3031 }
3032
3033 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3034 {
3035     HTTPContext *rtp_c;
3036
3037     rtp_c = find_rtp_session_with_url(url, h->session_id);
3038     if (!rtp_c) {
3039         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3040         return;
3041     }
3042
3043     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3044         rtp_c->state != HTTPSTATE_WAIT_FEED) {
3045         rtsp_reply_error(c, RTSP_STATUS_STATE);
3046         return;
3047     }
3048
3049     rtp_c->state = HTTPSTATE_READY;
3050     rtp_c->first_pts = AV_NOPTS_VALUE;
3051     /* now everything is OK, so we can send the connection parameters */
3052     rtsp_reply_header(c, RTSP_STATUS_OK);
3053     /* session ID */
3054     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3055     url_fprintf(c->pb, "\r\n");
3056 }
3057
3058 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3059 {
3060     HTTPContext *rtp_c;
3061     char session_id[32];
3062
3063     rtp_c = find_rtp_session_with_url(url, h->session_id);
3064     if (!rtp_c) {
3065         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3066         return;
3067     }
3068
3069     av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3070
3071     /* abort the session */
3072     close_connection(rtp_c);
3073
3074     /* now everything is OK, so we can send the connection parameters */
3075     rtsp_reply_header(c, RTSP_STATUS_OK);
3076     /* session ID */
3077     url_fprintf(c->pb, "Session: %s\r\n", session_id);
3078     url_fprintf(c->pb, "\r\n");
3079 }
3080
3081
3082 /********************************************************************/
3083 /* RTP handling */
3084
3085 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3086                                        FFStream *stream, const char *session_id,
3087                                        enum RTSPLowerTransport rtp_protocol)
3088 {
3089     HTTPContext *c = NULL;
3090     const char *proto_str;
3091
3092     /* XXX: should output a warning page when coming
3093        close to the connection limit */
3094     if (nb_connections >= nb_max_connections)
3095         goto fail;
3096
3097     /* add a new connection */
3098     c = av_mallocz(sizeof(HTTPContext));
3099     if (!c)
3100         goto fail;
3101
3102     c->fd = -1;
3103     c->poll_entry = NULL;
3104     c->from_addr = *from_addr;
3105     c->buffer_size = IOBUFFER_INIT_SIZE;
3106     c->buffer = av_malloc(c->buffer_size);
3107     if (!c->buffer)
3108         goto fail;
3109     nb_connections++;
3110     c->stream = stream;
3111     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3112     c->state = HTTPSTATE_READY;
3113     c->is_packetized = 1;
3114     c->rtp_protocol = rtp_protocol;
3115
3116     /* protocol is shown in statistics */
3117     switch(c->rtp_protocol) {
3118     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3119         proto_str = "MCAST";
3120         break;
3121     case RTSP_LOWER_TRANSPORT_UDP:
3122         proto_str = "UDP";
3123         break;
3124     case RTSP_LOWER_TRANSPORT_TCP:
3125         proto_str = "TCP";
3126         break;
3127     default:
3128         proto_str = "???";
3129         break;
3130     }
3131     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3132     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3133
3134     current_bandwidth += stream->bandwidth;
3135
3136     c->next = first_http_ctx;
3137     first_http_ctx = c;
3138     return c;
3139
3140  fail:
3141     if (c) {
3142         av_free(c->buffer);
3143         av_free(c);
3144     }
3145     return NULL;
3146 }
3147
3148 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3149    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3150    used. */
3151 static int rtp_new_av_stream(HTTPContext *c,
3152                              int stream_index, struct sockaddr_in *dest_addr,
3153                              HTTPContext *rtsp_c)
3154 {
3155     AVFormatContext *ctx;
3156     AVStream *st;
3157     char *ipaddr;
3158     URLContext *h = NULL;
3159     uint8_t *dummy_buf;
3160     int max_packet_size;
3161
3162     /* now we can open the relevant output stream */
3163     ctx = avformat_alloc_context();
3164     if (!ctx)
3165         return -1;
3166     ctx->oformat = guess_format("rtp", NULL, NULL);
3167
3168     st = av_mallocz(sizeof(AVStream));
3169     if (!st)
3170         goto fail;
3171     st->codec= avcodec_alloc_context();
3172     ctx->nb_streams = 1;
3173     ctx->streams[0] = st;
3174
3175     if (!c->stream->feed ||
3176         c->stream->feed == c->stream)
3177         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3178     else
3179         memcpy(st,
3180                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3181                sizeof(AVStream));
3182     st->priv_data = NULL;
3183
3184     /* build destination RTP address */
3185     ipaddr = inet_ntoa(dest_addr->sin_addr);
3186
3187     switch(c->rtp_protocol) {
3188     case RTSP_LOWER_TRANSPORT_UDP:
3189     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3190         /* RTP/UDP case */
3191
3192         /* XXX: also pass as parameter to function ? */
3193         if (c->stream->is_multicast) {
3194             int ttl;
3195             ttl = c->stream->multicast_ttl;
3196             if (!ttl)
3197                 ttl = 16;
3198             snprintf(ctx->filename, sizeof(ctx->filename),
3199                      "rtp://%s:%d?multicast=1&ttl=%d",
3200                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3201         } else {
3202             snprintf(ctx->filename, sizeof(ctx->filename),
3203                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3204         }
3205
3206         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3207             goto fail;
3208         c->rtp_handles[stream_index] = h;
3209         max_packet_size = url_get_max_packet_size(h);
3210         break;
3211     case RTSP_LOWER_TRANSPORT_TCP:
3212         /* RTP/TCP case */
3213         c->rtsp_c = rtsp_c;
3214         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3215         break;
3216     default:
3217         goto fail;
3218     }
3219
3220     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3221              ipaddr, ntohs(dest_addr->sin_port),
3222              c->stream->filename, stream_index, c->protocol);
3223
3224     /* normally, no packets should be output here, but the packet size may be checked */
3225     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3226         /* XXX: close stream */
3227         goto fail;
3228     }
3229     av_set_parameters(ctx, NULL);
3230     if (av_write_header(ctx) < 0) {
3231     fail:
3232         if (h)
3233             url_close(h);
3234         av_free(ctx);
3235         return -1;
3236     }
3237     url_close_dyn_buf(ctx->pb, &dummy_buf);
3238     av_free(dummy_buf);
3239
3240     c->rtp_ctx[stream_index] = ctx;
3241     return 0;
3242 }
3243
3244 /********************************************************************/
3245 /* ffserver initialization */
3246
3247 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3248 {
3249     AVStream *fst;
3250
3251     fst = av_mallocz(sizeof(AVStream));
3252     if (!fst)
3253         return NULL;
3254     fst->codec= avcodec_alloc_context();
3255     fst->priv_data = av_mallocz(sizeof(FeedData));
3256     memcpy(fst->codec, codec, sizeof(AVCodecContext));
3257     fst->index = stream->nb_streams;
3258     av_set_pts_info(fst, 33, 1, 90000);
3259     stream->streams[stream->nb_streams++] = fst;
3260     return fst;
3261 }
3262
3263 /* return the stream number in the feed */
3264 static int add_av_stream(FFStream *feed, AVStream *st)
3265 {
3266     AVStream *fst;
3267     AVCodecContext *av, *av1;
3268     int i;
3269
3270     av = st->codec;
3271     for(i=0;i<feed->nb_streams;i++) {
3272         st = feed->streams[i];
3273         av1 = st->codec;
3274         if (av1->codec_id == av->codec_id &&
3275             av1->codec_type == av->codec_type &&
3276             av1->bit_rate == av->bit_rate) {
3277
3278             switch(av->codec_type) {
3279             case CODEC_TYPE_AUDIO:
3280                 if (av1->channels == av->channels &&
3281                     av1->sample_rate == av->sample_rate)
3282                     goto found;
3283                 break;
3284             case CODEC_TYPE_VIDEO:
3285                 if (av1->width == av->width &&
3286                     av1->height == av->height &&
3287                     av1->time_base.den == av->time_base.den &&
3288                     av1->time_base.num == av->time_base.num &&
3289                     av1->gop_size == av->gop_size)
3290                     goto found;
3291                 break;
3292             default:
3293                 abort();
3294             }
3295         }
3296     }
3297
3298     fst = add_av_stream1(feed, av);
3299     if (!fst)
3300         return -1;
3301     return feed->nb_streams - 1;
3302  found:
3303     return i;
3304 }
3305
3306 static void remove_stream(FFStream *stream)
3307 {
3308     FFStream **ps;
3309     ps = &first_stream;
3310     while (*ps != NULL) {
3311         if (*ps == stream)
3312             *ps = (*ps)->next;
3313         else
3314             ps = &(*ps)->next;
3315     }
3316 }
3317
3318 /* specific mpeg4 handling : we extract the raw parameters */
3319 static void extract_mpeg4_header(AVFormatContext *infile)
3320 {
3321     int mpeg4_count, i, size;
3322     AVPacket pkt;
3323     AVStream *st;
3324     const uint8_t *p;
3325
3326     mpeg4_count = 0;
3327     for(i=0;i<infile->nb_streams;i++) {
3328         st = infile->streams[i];
3329         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3330             st->codec->extradata_size == 0) {
3331             mpeg4_count++;
3332         }
3333     }
3334     if (!mpeg4_count)
3335         return;
3336
3337     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3338     while (mpeg4_count > 0) {
3339         if (av_read_packet(infile, &pkt) < 0)
3340             break;
3341         st = infile->streams[pkt.stream_index];
3342         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3343             st->codec->extradata_size == 0) {
3344             av_freep(&st->codec->extradata);
3345             /* fill extradata with the header */
3346             /* XXX: we make hard suppositions here ! */
3347             p = pkt.data;
3348             while (p < pkt.data + pkt.size - 4) {
3349                 /* stop when vop header is found */
3350                 if (p[0] == 0x00 && p[1] == 0x00 &&
3351                     p[2] == 0x01 && p[3] == 0xb6) {
3352                     size = p - pkt.data;
3353                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3354                     st->codec->extradata = av_malloc(size);
3355                     st->codec->extradata_size = size;
3356                     memcpy(st->codec->extradata, pkt.data, size);
3357                     break;
3358                 }
3359                 p++;
3360             }
3361             mpeg4_count--;
3362         }
3363         av_free_packet(&pkt);
3364     }
3365 }
3366
3367 /* compute the needed AVStream for each file */
3368 static void build_file_streams(void)
3369 {
3370     FFStream *stream, *stream_next;
3371     AVFormatContext *infile;
3372     int i, ret;
3373
3374     /* gather all streams */
3375     for(stream = first_stream; stream != NULL; stream = stream_next) {
3376         stream_next = stream->next;
3377         if (stream->stream_type == STREAM_TYPE_LIVE &&
3378             !stream->feed) {
3379             /* the stream comes from a file */
3380             /* try to open the file */
3381             /* open stream */
3382             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3383             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3384                 /* specific case : if transport stream output to RTP,
3385                    we use a raw transport stream reader */
3386                 stream->ap_in->mpeg2ts_raw = 1;
3387                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3388             }
3389
3390             if ((ret = av_open_input_file(&infile, stream->feed_filename,
3391                                           stream->ifmt, 0, stream->ap_in)) < 0) {
3392                 http_log("could not open %s: %d\n", stream->feed_filename, ret);
3393                 /* remove stream (no need to spend more time on it) */
3394             fail:
3395                 remove_stream(stream);
3396             } else {
3397                 /* find all the AVStreams inside and reference them in
3398                    'stream' */
3399                 if (av_find_stream_info(infile) < 0) {
3400                     http_log("Could not find codec parameters from '%s'\n",
3401                              stream->feed_filename);
3402                     av_close_input_file(infile);
3403                     goto fail;
3404                 }
3405                 extract_mpeg4_header(infile);
3406
3407                 for(i=0;i<infile->nb_streams;i++)
3408                     add_av_stream1(stream, infile->streams[i]->codec);
3409
3410                 av_close_input_file(infile);
3411             }
3412         }
3413     }
3414 }
3415
3416 /* compute the needed AVStream for each feed */
3417 static void build_feed_streams(void)
3418 {
3419     FFStream *stream, *feed;
3420     int i;
3421
3422     /* gather all streams */
3423     for(stream = first_stream; stream != NULL; stream = stream->next) {
3424         feed = stream->feed;
3425         if (feed) {
3426             if (!stream->is_feed) {
3427                 /* we handle a stream coming from a feed */
3428                 for(i=0;i<stream->nb_streams;i++)
3429                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3430             }
3431         }
3432     }
3433
3434     /* gather all streams */
3435     for(stream = first_stream; stream != NULL; stream = stream->next) {
3436         feed = stream->feed;
3437         if (feed) {
3438             if (stream->is_feed) {
3439                 for(i=0;i<stream->nb_streams;i++)
3440                     stream->feed_streams[i] = i;
3441             }
3442         }
3443     }
3444
3445     /* create feed files if needed */
3446     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3447         int fd;
3448
3449         if (url_exist(feed->feed_filename)) {
3450             /* See if it matches */
3451             AVFormatContext *s;
3452             int matches = 0;
3453
3454             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3455                 /* Now see if it matches */
3456                 if (s->nb_streams == feed->nb_streams) {
3457                     matches = 1;
3458                     for(i=0;i<s->nb_streams;i++) {
3459                         AVStream *sf, *ss;
3460                         sf = feed->streams[i];
3461                         ss = s->streams[i];
3462
3463                         if (sf->index != ss->index ||
3464                             sf->id != ss->id) {
3465                             http_log("Index & Id do not match for stream %d (%s)\n",
3466                                    i, feed->feed_filename);
3467                             matches = 0;
3468                         } else {
3469                             AVCodecContext *ccf, *ccs;
3470
3471                             ccf = sf->codec;
3472                             ccs = ss->codec;
3473 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3474
3475                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3476                                 http_log("Codecs do not match for stream %d\n", i);
3477                                 matches = 0;
3478                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3479                                 http_log("Codec bitrates do not match for stream %d\n", i);
3480                                 matches = 0;
3481                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3482                                 if (CHECK_CODEC(time_base.den) ||
3483                                     CHECK_CODEC(time_base.num) ||
3484                                     CHECK_CODEC(width) ||
3485                                     CHECK_CODEC(height)) {
3486                                     http_log("Codec width, height and framerate do not match for stream %d\n", i);
3487                                     matches = 0;
3488                                 }
3489                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3490                                 if (CHECK_CODEC(sample_rate) ||
3491                                     CHECK_CODEC(channels) ||
3492                                     CHECK_CODEC(frame_size)) {
3493                                     http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3494                                     matches = 0;
3495                                 }
3496                             } else {
3497                                 http_log("Unknown codec type\n");
3498                                 matches = 0;
3499                             }
3500                         }
3501                         if (!matches)
3502                             break;
3503                     }
3504                 } else
3505                     http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3506                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3507
3508                 av_close_input_file(s);
3509             } else
3510                 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3511                         feed->feed_filename);
3512
3513             if (!matches) {
3514                 if (feed->readonly) {
3515                     http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3516                         feed->feed_filename);
3517                     exit(1);
3518                 }
3519                 unlink(feed->feed_filename);
3520             }
3521         }
3522         if (!url_exist(feed->feed_filename)) {
3523             AVFormatContext s1 = {0}, *s = &s1;
3524
3525             if (feed->readonly) {
3526                 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3527                     feed->feed_filename);
3528                 exit(1);
3529             }
3530
3531             /* only write the header of the ffm file */
3532             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3533                 http_log("Could not open output feed file '%s'\n",
3534                          feed->feed_filename);
3535                 exit(1);
3536             }
3537             s->oformat = feed->fmt;
3538             s->nb_streams = feed->nb_streams;
3539             for(i=0;i<s->nb_streams;i++) {
3540                 AVStream *st;
3541                 st = feed->streams[i];
3542                 s->streams[i] = st;
3543             }
3544             av_set_parameters(s, NULL);
3545             if (av_write_header(s) < 0) {
3546                 http_log("Container doesn't supports the required parameters\n");
3547                 exit(1);
3548             }
3549             /* XXX: need better api */
3550             av_freep(&s->priv_data);
3551             url_fclose(s->pb);
3552         }
3553         /* get feed size and write index */
3554         fd = open(feed->feed_filename, O_RDONLY);
3555         if (fd < 0) {
3556             http_log("Could not open output feed file '%s'\n",
3557                     feed->feed_filename);
3558             exit(1);
3559         }
3560
3561         feed->feed_write_index = ffm_read_write_index(fd);
3562         feed->feed_size = lseek(fd, 0, SEEK_END);
3563         /* ensure that we do not wrap before the end of file */
3564         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3565             feed->feed_max_size = feed->feed_size;
3566
3567         close(fd);
3568     }
3569 }
3570
3571 /* compute the bandwidth used by each stream */
3572 static void compute_bandwidth(void)
3573 {
3574     unsigned bandwidth;
3575     int i;
3576     FFStream *stream;
3577
3578     for(stream = first_stream; stream != NULL; stream = stream->next) {
3579         bandwidth = 0;
3580         for(i=0;i<stream->nb_streams;i++) {
3581             AVStream *st = stream->streams[i];
3582             switch(st->codec->codec_type) {
3583             case CODEC_TYPE_AUDIO:
3584             case CODEC_TYPE_VIDEO:
3585                 bandwidth += st->codec->bit_rate;
3586                 break;
3587             default:
3588                 break;
3589             }
3590         }
3591         stream->bandwidth = (bandwidth + 999) / 1000;
3592     }
3593 }
3594
3595 static void get_arg(char *buf, int buf_size, const char **pp)
3596 {
3597     const char *p;
3598     char *q;
3599     int quote;
3600
3601     p = *pp;
3602     while (isspace(*p)) p++;
3603     q = buf;
3604     quote = 0;
3605     if (*p == '\"' || *p == '\'')
3606         quote = *p++;
3607     for(;;) {
3608         if (quote) {
3609             if (*p == quote)
3610                 break;
3611         } else {
3612             if (isspace(*p))
3613                 break;
3614         }
3615         if (*p == '\0')
3616             break;
3617         if ((q - buf) < buf_size - 1)
3618             *q++ = *p;
3619         p++;
3620     }
3621     *q = '\0';
3622     if (quote && *p == quote)
3623         p++;
3624     *pp = p;
3625 }
3626
3627 /* add a codec and set the default parameters */
3628 static void add_codec(FFStream *stream, AVCodecContext *av)
3629 {
3630     AVStream *st;
3631
3632     /* compute default parameters */
3633     switch(av->codec_type) {
3634     case CODEC_TYPE_AUDIO:
3635         if (av->bit_rate == 0)
3636             av->bit_rate = 64000;
3637         if (av->sample_rate == 0)
3638             av->sample_rate = 22050;
3639         if (av->channels == 0)
3640             av->channels = 1;
3641         break;
3642     case CODEC_TYPE_VIDEO:
3643         if (av->bit_rate == 0)
3644             av->bit_rate = 64000;
3645         if (av->time_base.num == 0){
3646             av->time_base.den = 5;
3647             av->time_base.num = 1;
3648         }
3649         if (av->width == 0 || av->height == 0) {
3650             av->width = 160;
3651             av->height = 128;
3652         }
3653         /* Bitrate tolerance is less for streaming */
3654         if (av->bit_rate_tolerance == 0)
3655             av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3656                       (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3657         if (av->qmin == 0)
3658             av->qmin = 3;
3659         if (av->qmax == 0)
3660             av->qmax = 31;
3661         if (av->max_qdiff == 0)
3662             av->max_qdiff = 3;
3663         av->qcompress = 0.5;
3664         av->qblur = 0.5;
3665
3666         if (!av->nsse_weight)
3667             av->nsse_weight = 8;
3668
3669         av->frame_skip_cmp = FF_CMP_DCTMAX;
3670         av->me_method = ME_EPZS;
3671         av->rc_buffer_aggressivity = 1.0;
3672
3673         if (!av->rc_eq)
3674             av->rc_eq = "tex^qComp";
3675         if (!av->i_quant_factor)
3676             av->i_quant_factor = -0.8;
3677         if (!av->b_quant_factor)
3678             av->b_quant_factor = 1.25;
3679         if (!av->b_quant_offset)
3680             av->b_quant_offset = 1.25;
3681         if (!av->rc_max_rate)
3682             av->rc_max_rate = av->bit_rate * 2;
3683
3684         if (av->rc_max_rate && !av->rc_buffer_size) {
3685             av->rc_buffer_size = av->rc_max_rate;
3686         }
3687
3688
3689         break;
3690     default:
3691         abort();
3692     }
3693
3694     st = av_mallocz(sizeof(AVStream));
3695     if (!st)
3696         return;
3697     st->codec = avcodec_alloc_context();
3698     stream->streams[stream->nb_streams++] = st;
3699     memcpy(st->codec, av, sizeof(AVCodecContext));
3700 }
3701
3702 static enum CodecID opt_audio_codec(const char *arg)
3703 {
3704     AVCodec *p= avcodec_find_encoder_by_name(arg);
3705
3706     if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3707         return CODEC_ID_NONE;
3708
3709     return p->id;
3710 }
3711
3712 static enum CodecID opt_video_codec(const char *arg)
3713 {
3714     AVCodec *p= avcodec_find_encoder_by_name(arg);
3715
3716     if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3717         return CODEC_ID_NONE;
3718
3719     return p->id;
3720 }
3721
3722 /* simplistic plugin support */
3723
3724 #if HAVE_DLOPEN
3725 static void load_module(const char *filename)
3726 {
3727     void *dll;
3728     void (*init_func)(void);
3729     dll = dlopen(filename, RTLD_NOW);
3730     if (!dll) {
3731         fprintf(stderr, "Could not load module '%s' - %s\n",
3732                 filename, dlerror());
3733         return;
3734     }
3735
3736     init_func = dlsym(dll, "ffserver_module_init");
3737     if (!init_func) {
3738         fprintf(stderr,
3739                 "%s: init function 'ffserver_module_init()' not found\n",
3740                 filename);
3741         dlclose(dll);
3742     }
3743
3744     init_func();
3745 }
3746 #endif
3747
3748 static int ffserver_opt_default(const char *opt, const char *arg,
3749                        AVCodecContext *avctx, int type)
3750 {
3751     int ret = 0;
3752     const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3753     if(o)
3754         ret = av_set_string3(avctx, opt, arg, 1, NULL);
3755     return ret;
3756 }
3757
3758 static int parse_ffconfig(const char *filename)
3759 {
3760     FILE *f;
3761     char line[1024];
3762     char cmd[64];
3763     char arg[1024];
3764     const char *p;
3765     int val, errors, line_num;
3766     FFStream **last_stream, *stream, *redirect;
3767     FFStream **last_feed, *feed;
3768     AVCodecContext audio_enc, video_enc;
3769     enum CodecID audio_id, video_id;
3770
3771     f = fopen(filename, "r");
3772     if (!f) {
3773         perror(filename);
3774         return -1;
3775     }
3776
3777     errors = 0;
3778     line_num = 0;
3779     first_stream = NULL;
3780     last_stream = &first_stream;
3781     first_feed = NULL;
3782     last_feed = &first_feed;
3783     stream = NULL;
3784     feed = NULL;
3785     redirect = NULL;
3786     audio_id = CODEC_ID_NONE;
3787     video_id = CODEC_ID_NONE;
3788     for(;;) {
3789         if (fgets(line, sizeof(line), f) == NULL)
3790             break;
3791         line_num++;
3792         p = line;
3793         while (isspace(*p))
3794             p++;
3795         if (*p == '\0' || *p == '#')
3796             continue;
3797
3798         get_arg(cmd, sizeof(cmd), &p);
3799
3800         if (!strcasecmp(cmd, "Port")) {
3801             get_arg(arg, sizeof(arg), &p);
3802             val = atoi(arg);
3803             if (val < 1 || val > 65536) {
3804                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3805                         filename, line_num, arg);
3806                 errors++;
3807             }
3808             my_http_addr.sin_port = htons(val);
3809         } else if (!strcasecmp(cmd, "BindAddress")) {
3810             get_arg(arg, sizeof(arg), &p);
3811             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3812                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3813                         filename, line_num, arg);
3814                 errors++;
3815             }
3816         } else if (!strcasecmp(cmd, "NoDaemon")) {
3817             ffserver_daemon = 0;
3818         } else if (!strcasecmp(cmd, "RTSPPort")) {
3819             get_arg(arg, sizeof(arg), &p);
3820             val = atoi(arg);
3821             if (val < 1 || val > 65536) {
3822                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3823                         filename, line_num, arg);
3824                 errors++;
3825             }
3826             my_rtsp_addr.sin_port = htons(atoi(arg));
3827         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3828             get_arg(arg, sizeof(arg), &p);
3829             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3830                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3831                         filename, line_num, arg);
3832                 errors++;
3833             }
3834         } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3835             get_arg(arg, sizeof(arg), &p);
3836             val = atoi(arg);
3837             if (val < 1 || val > 65536) {
3838                 fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3839                         filename, line_num, arg);
3840                 errors++;
3841             }
3842             nb_max_http_connections = val;
3843         } else if (!strcasecmp(cmd, "MaxClients")) {
3844             get_arg(arg, sizeof(arg), &p);
3845             val = atoi(arg);
3846             if (val < 1 || val > nb_max_http_connections) {
3847                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3848                         filename, line_num, arg);
3849                 errors++;
3850             } else {
3851                 nb_max_connections = val;
3852             }
3853         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3854             int64_t llval;
3855             get_arg(arg, sizeof(arg), &p);
3856             llval = atoll(arg);
3857             if (llval < 10 || llval > 10000000) {
3858                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3859                         filename, line_num, arg);
3860                 errors++;
3861             } else
3862                 max_bandwidth = llval;
3863         } else if (!strcasecmp(cmd, "CustomLog")) {
3864             if (!ffserver_debug)
3865                 get_arg(logfilename, sizeof(logfilename), &p);
3866         } else if (!strcasecmp(cmd, "<Feed")) {
3867             /*********************************************/
3868             /* Feed related options */
3869             char *q;
3870             if (stream || feed) {
3871                 fprintf(stderr, "%s:%d: Already in a tag\n",
3872                         filename, line_num);
3873             } else {
3874                 feed = av_mallocz(sizeof(FFStream));
3875                 /* add in stream list */
3876                 *last_stream = feed;
3877                 last_stream = &feed->next;
3878                 /* add in feed list */
3879                 *last_feed = feed;
3880                 last_feed = &feed->next_feed;
3881
3882                 get_arg(feed->filename, sizeof(feed->filename), &p);
3883                 q = strrchr(feed->filename, '>');
3884                 if (*q)
3885                     *q = '\0';
3886                 feed->fmt = guess_format("ffm", NULL, NULL);
3887                 /* defaut feed file */
3888                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3889                          "/tmp/%s.ffm", feed->filename);
3890                 feed->feed_max_size = 5 * 1024 * 1024;
3891                 feed->is_feed = 1;
3892                 feed->feed = feed; /* self feeding :-) */
3893             }
3894         } else if (!strcasecmp(cmd, "Launch")) {
3895             if (feed) {
3896                 int i;
3897
3898                 feed->child_argv = av_mallocz(64 * sizeof(char *));
3899
3900                 for (i = 0; i < 62; i++) {
3901                     get_arg(arg, sizeof(arg), &p);
3902                     if (!arg[0])
3903                         break;
3904
3905                     feed->child_argv[i] = av_strdup(arg);
3906                 }
3907
3908                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3909
3910                 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3911                     "http://%s:%d/%s",
3912                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3913                     inet_ntoa(my_http_addr.sin_addr),
3914                     ntohs(my_http_addr.sin_port), feed->filename);
3915             }
3916         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3917             if (feed) {
3918                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3919                 feed->readonly = 1;
3920             } else if (stream) {
3921                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3922             }
3923         } else if (!strcasecmp(cmd, "File")) {
3924             if (feed) {
3925                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3926             } else if (stream)
3927                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3928         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3929             if (feed) {
3930                 char *p1;
3931                 double fsize;
3932
3933                 get_arg(arg, sizeof(arg), &p);
3934                 p1 = arg;
3935                 fsize = strtod(p1, &p1);
3936                 switch(toupper(*p1)) {
3937                 case 'K':
3938                     fsize *= 1024;
3939                     break;
3940                 case 'M':
3941                     fsize *= 1024 * 1024;
3942                     break;
3943                 case 'G':
3944                     fsize *= 1024 * 1024 * 1024;
3945                     break;
3946                 }
3947                 feed->feed_max_size = (int64_t)fsize;
3948             }
3949         } else if (!strcasecmp(cmd, "</Feed>")) {
3950             if (!feed) {
3951                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3952                         filename, line_num);
3953                 errors++;
3954             }
3955             feed = NULL;
3956         } else if (!strcasecmp(cmd, "<Stream")) {
3957             /*********************************************/
3958             /* Stream related options */
3959             char *q;
3960             if (stream || feed) {
3961                 fprintf(stderr, "%s:%d: Already in a tag\n",
3962                         filename, line_num);
3963             } else {
3964                 const AVClass *class;
3965                 stream = av_mallocz(sizeof(FFStream));
3966                 *last_stream = stream;
3967                 last_stream = &stream->next;
3968
3969                 get_arg(stream->filename, sizeof(stream->filename), &p);
3970                 q = strrchr(stream->filename, '>');
3971                 if (*q)
3972                     *q = '\0';
3973                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3974                 /* fetch avclass so AVOption works
3975                  * FIXME try to use avcodec_get_context_defaults2
3976                  * without changing defaults too much */
3977                 avcodec_get_context_defaults(&video_enc);
3978                 class = video_enc.av_class;
3979                 memset(&audio_enc, 0, sizeof(AVCodecContext));
3980                 memset(&video_enc, 0, sizeof(AVCodecContext));
3981                 audio_enc.av_class = class;
3982                 video_enc.av_class = class;
3983                 audio_id = CODEC_ID_NONE;
3984                 video_id = CODEC_ID_NONE;
3985                 if (stream->fmt) {
3986                     audio_id = stream->fmt->audio_codec;
3987                     video_id = stream->fmt->video_codec;
3988                 }
3989             }
3990         } else if (!strcasecmp(cmd, "Feed")) {
3991             get_arg(arg, sizeof(arg), &p);
3992             if (stream) {
3993                 FFStream *sfeed;
3994
3995                 sfeed = first_feed;
3996                 while (sfeed != NULL) {
3997                     if (!strcmp(sfeed->filename, arg))
3998                         break;
3999                     sfeed = sfeed->next_feed;
4000                 }
4001                 if (!sfeed)
4002                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4003                             filename, line_num, arg);
4004                 else
4005                     stream->feed = sfeed;
4006             }
4007         } else if (!strcasecmp(cmd, "Format")) {
4008             get_arg(arg, sizeof(arg), &p);
4009             if (stream) {
4010                 if (!strcmp(arg, "status")) {
4011                     stream->stream_type = STREAM_TYPE_STATUS;
4012                     stream->fmt = NULL;
4013                 } else {
4014                     stream->stream_type = STREAM_TYPE_LIVE;
4015                     /* jpeg cannot be used here, so use single frame jpeg */
4016                     if (!strcmp(arg, "jpeg"))
4017                         strcpy(arg, "mjpeg");
4018                     stream->fmt = guess_stream_format(arg, NULL, NULL);
4019                     if (!stream->fmt) {
4020                         fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4021                                 filename, line_num, arg);
4022                         errors++;
4023                     }
4024                 }
4025                 if (stream->fmt) {
4026                     audio_id = stream->fmt->audio_codec;
4027                     video_id = stream->fmt->video_codec;
4028                 }
4029             }
4030         } else if (!strcasecmp(cmd, "InputFormat")) {
4031             get_arg(arg, sizeof(arg), &p);
4032             if (stream) {
4033                 stream->ifmt = av_find_input_format(arg);
4034                 if (!stream->ifmt) {
4035                     fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4036                             filename, line_num, arg);
4037                 }
4038             }
4039         } else if (!strcasecmp(cmd, "FaviconURL")) {
4040             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4041                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4042             } else {
4043                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4044                             filename, line_num);
4045                 errors++;
4046             }
4047         } else if (!strcasecmp(cmd, "Author")) {
4048             if (stream)
4049                 get_arg(stream->author, sizeof(stream->author), &p);
4050         } else if (!strcasecmp(cmd, "Comment")) {
4051             if (stream)
4052                 get_arg(stream->comment, sizeof(stream->comment), &p);
4053         } else if (!strcasecmp(cmd, "Copyright")) {
4054             if (stream)
4055                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4056         } else if (!strcasecmp(cmd, "Title")) {
4057             if (stream)
4058                 get_arg(stream->title, sizeof(stream->title), &p);
4059         } else if (!strcasecmp(cmd, "Preroll")) {
4060             get_arg(arg, sizeof(arg), &p);
4061             if (stream)
4062                 stream->prebuffer = atof(arg) * 1000;
4063         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4064             if (stream)
4065                 stream->send_on_key = 1;
4066         } else if (!strcasecmp(cmd, "AudioCodec")) {
4067             get_arg(arg, sizeof(arg), &p);
4068             audio_id = opt_audio_codec(arg);
4069             if (audio_id == CODEC_ID_NONE) {
4070                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4071                         filename, line_num, arg);
4072                 errors++;
4073             }
4074         } else if (!strcasecmp(cmd, "VideoCodec")) {
4075             get_arg(arg, sizeof(arg), &p);
4076             video_id = opt_video_codec(arg);
4077             if (video_id == CODEC_ID_NONE) {
4078                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4079                         filename, line_num, arg);
4080                 errors++;
4081             }
4082         } else if (!strcasecmp(cmd, "MaxTime")) {
4083             get_arg(arg, sizeof(arg), &p);
4084             if (stream)
4085                 stream->max_time = atof(arg) * 1000;
4086         } else if (!strcasecmp(cmd, "AudioBitRate")) {
4087             get_arg(arg, sizeof(arg), &p);
4088             if (stream)
4089                 audio_enc.bit_rate = atoi(arg) * 1000;
4090         } else if (!strcasecmp(cmd, "AudioChannels")) {
4091             get_arg(arg, sizeof(arg), &p);
4092             if (stream)
4093                 audio_enc.channels = atoi(arg);
4094         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4095             get_arg(arg, sizeof(arg), &p);
4096             if (stream)
4097                 audio_enc.sample_rate = atoi(arg);
4098         } else if (!strcasecmp(cmd, "AudioQuality")) {
4099             get_arg(arg, sizeof(arg), &p);
4100             if (stream) {
4101 //                audio_enc.quality = atof(arg) * 1000;
4102             }
4103         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4104             if (stream) {
4105                 int minrate, maxrate;
4106
4107                 get_arg(arg, sizeof(arg), &p);
4108
4109                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4110                     video_enc.rc_min_rate = minrate * 1000;
4111                     video_enc.rc_max_rate = maxrate * 1000;
4112                 } else {
4113                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4114                             filename, line_num, arg);
4115                     errors++;
4116                 }
4117             }
4118         } else if (!strcasecmp(cmd, "Debug")) {
4119             if (stream) {
4120                 get_arg(arg, sizeof(arg), &p);
4121                 video_enc.debug = strtol(arg,0,0);
4122             }
4123         } else if (!strcasecmp(cmd, "Strict")) {
4124             if (stream) {
4125                 get_arg(arg, sizeof(arg), &p);
4126                 video_enc.strict_std_compliance = atoi(arg);
4127             }
4128         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4129             if (stream) {
4130                 get_arg(arg, sizeof(arg), &p);
4131                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4132             }
4133         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4134             if (stream) {
4135                 get_arg(arg, sizeof(arg), &p);
4136                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4137             }
4138         } else if (!strcasecmp(cmd, "VideoBitRate")) {
4139             get_arg(arg, sizeof(arg), &p);
4140             if (stream) {
4141                 video_enc.bit_rate = atoi(arg) * 1000;
4142             }
4143         } else if (!strcasecmp(cmd, "VideoSize")) {
4144             get_arg(arg, sizeof(arg), &p);
4145             if (stream) {
4146                 av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4147                 if ((video_enc.width % 16) != 0 ||
4148                     (video_enc.height % 16) != 0) {
4149                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4150                             filename, line_num);
4151                     errors++;
4152                 }
4153             }
4154         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4155             get_arg(arg, sizeof(arg), &p);
4156             if (stream) {
4157                 AVRational frame_rate;
4158                 if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4159                     fprintf(stderr, "Incorrect frame rate\n");
4160                     errors++;
4161                 } else {
4162                     video_enc.time_base.num = frame_rate.den;
4163                     video_enc.time_base.den = frame_rate.num;
4164                 }
4165             }
4166         } else if (!strcasecmp(cmd, "VideoGopSize")) {
4167             get_arg(arg, sizeof(arg), &p);
4168             if (stream)
4169                 video_enc.gop_size = atoi(arg);
4170         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4171             if (stream)
4172                 video_enc.gop_size = 1;
4173         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4174             if (stream)
4175                 video_enc.mb_decision = FF_MB_DECISION_BITS;
4176         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4177             if (stream) {
4178                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4179                 video_enc.flags |= CODEC_FLAG_4MV;
4180             }
4181         } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4182                    !strcasecmp(cmd, "AVOptionAudio")) {
4183             char arg2[1024];
4184             AVCodecContext *avctx;
4185             int type;
4186             get_arg(arg, sizeof(arg), &p);
4187             get_arg(arg2, sizeof(arg2), &p);
4188             if (!strcasecmp(cmd, "AVOptionVideo")) {
4189                 avctx = &video_enc;
4190                 type = AV_OPT_FLAG_VIDEO_PARAM;
4191             } else {
4192                 avctx = &audio_enc;
4193                 type = AV_OPT_FLAG_AUDIO_PARAM;
4194             }
4195             if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4196                 fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4197                 errors++;
4198             }
4199         } else if (!strcasecmp(cmd, "VideoTag")) {
4200             get_arg(arg, sizeof(arg), &p);
4201             if ((strlen(arg) == 4) && stream)
4202                 video_enc.codec_tag = AV_RL32(arg);
4203         } else if (!strcasecmp(cmd, "BitExact")) {
4204             if (stream)
4205                 video_enc.flags |= CODEC_FLAG_BITEXACT;
4206         } else if (!strcasecmp(cmd, "DctFastint")) {
4207             if (stream)
4208                 video_enc.dct_algo  = FF_DCT_FASTINT;
4209         } else if (!strcasecmp(cmd, "IdctSimple")) {
4210             if (stream)
4211                 video_enc.idct_algo = FF_IDCT_SIMPLE;
4212         } else if (!strcasecmp(cmd, "Qscale")) {
4213             get_arg(arg, sizeof(arg), &p);
4214             if (stream) {
4215                 video_enc.flags |= CODEC_FLAG_QSCALE;
4216                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4217             }
4218         } else if (!strcasecmp(cmd, "VideoQDiff")) {
4219             get_arg(arg, sizeof(arg), &p);
4220             if (stream) {
4221                 video_enc.max_qdiff = atoi(arg);
4222                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4223                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4224                             filename, line_num);
4225                     errors++;
4226                 }
4227             }
4228         } else if (!strcasecmp(cmd, "VideoQMax")) {
4229             get_arg(arg, sizeof(arg), &p);
4230             if (stream) {
4231                 video_enc.qmax = atoi(arg);
4232                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4233                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4234                             filename, line_num);
4235                     errors++;
4236                 }
4237             }
4238         } else if (!strcasecmp(cmd, "VideoQMin")) {
4239             get_arg(arg, sizeof(arg), &p);
4240             if (stream) {
4241                 video_enc.qmin = atoi(arg);
4242                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4243                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4244                             filename, line_num);
4245                     errors++;
4246                 }
4247             }
4248         } else if (!strcasecmp(cmd, "LumaElim")) {
4249             get_arg(arg, sizeof(arg), &p);
4250             if (stream)
4251                 video_enc.luma_elim_threshold = atoi(arg);
4252         } else if (!strcasecmp(cmd, "ChromaElim")) {
4253             get_arg(arg, sizeof(arg), &p);
4254             if (stream)
4255                 video_enc.chroma_elim_threshold = atoi(arg);
4256         } else if (!strcasecmp(cmd, "LumiMask")) {
4257             get_arg(arg, sizeof(arg), &p);
4258             if (stream)
4259                 video_enc.lumi_masking = atof(arg);
4260         } else if (!strcasecmp(cmd, "DarkMask")) {
4261             get_arg(arg, sizeof(arg), &p);
4262             if (stream)
4263                 video_enc.dark_masking = atof(arg);
4264         } else if (!strcasecmp(cmd, "NoVideo")) {
4265             video_id = CODEC_ID_NONE;
4266         } else if (!strcasecmp(cmd, "NoAudio")) {
4267             audio_id = CODEC_ID_NONE;
4268         } else if (!strcasecmp(cmd, "ACL")) {
4269             IPAddressACL acl;
4270
4271             get_arg(arg, sizeof(arg), &p);
4272             if (strcasecmp(arg, "allow") == 0)
4273                 acl.action = IP_ALLOW;
4274             else if (strcasecmp(arg, "deny") == 0)
4275                 acl.action = IP_DENY;
4276             else {
4277                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4278                         filename, line_num, arg);
4279                 errors++;
4280             }
4281
4282             get_arg(arg, sizeof(arg), &p);
4283
4284             if (resolve_host(&acl.first, arg) != 0) {
4285                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4286                         filename, line_num, arg);
4287                 errors++;
4288             } else
4289                 acl.last = acl.first;
4290
4291             get_arg(arg, sizeof(arg), &p);
4292
4293             if (arg[0]) {
4294                 if (resolve_host(&acl.last, arg) != 0) {
4295                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4296                             filename, line_num, arg);
4297                     errors++;
4298                 }
4299             }
4300
4301             if (!errors) {
4302                 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4303                 IPAddressACL **naclp = 0;
4304
4305                 acl.next = 0;
4306                 *nacl = acl;
4307
4308                 if (stream)
4309                     naclp = &stream->acl;
4310                 else if (feed)
4311                     naclp = &feed->acl;
4312                 else {
4313                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4314                             filename, line_num);
4315                     errors++;
4316                 }
4317
4318                 if (naclp) {
4319                     while (*naclp)
4320                         naclp = &(*naclp)->next;
4321
4322                     *naclp = nacl;
4323                 }
4324             }
4325         } else if (!strcasecmp(cmd, "RTSPOption")) {
4326             get_arg(arg, sizeof(arg), &p);
4327             if (stream) {
4328                 av_freep(&stream->rtsp_option);
4329                 stream->rtsp_option = av_strdup(arg);
4330             }
4331         } else if (!strcasecmp(cmd, "MulticastAddress")) {
4332             get_arg(arg, sizeof(arg), &p);
4333             if (stream) {
4334                 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4335                     fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4336                             filename, line_num, arg);
4337                     errors++;
4338                 }
4339                 stream->is_multicast = 1;
4340                 stream->loop = 1; /* default is looping */
4341             }
4342         } else if (!strcasecmp(cmd, "MulticastPort")) {
4343             get_arg(arg, sizeof(arg), &p);
4344             if (stream)
4345                 stream->multicast_port = atoi(arg);
4346         } else if (!strcasecmp(cmd, "MulticastTTL")) {
4347             get_arg(arg, sizeof(arg), &p);
4348             if (stream)
4349                 stream->multicast_ttl = atoi(arg);
4350         } else if (!strcasecmp(cmd, "NoLoop")) {
4351             if (stream)
4352                 stream->loop = 0;
4353         } else if (!strcasecmp(cmd, "</Stream>")) {
4354             if (!stream) {
4355                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4356                         filename, line_num);
4357                 errors++;
4358             } else {
4359                 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4360                     if (audio_id != CODEC_ID_NONE) {
4361                         audio_enc.codec_type = CODEC_TYPE_AUDIO;
4362                         audio_enc.codec_id = audio_id;
4363                         add_codec(stream, &audio_enc);
4364                     }
4365                     if (video_id != CODEC_ID_NONE) {
4366                         video_enc.codec_type = CODEC_TYPE_VIDEO;
4367                         video_enc.codec_id = video_id;
4368                         add_codec(stream, &video_enc);
4369                     }
4370                 }
4371                 stream = NULL;
4372             }
4373         } else if (!strcasecmp(cmd, "<Redirect")) {
4374             /*********************************************/
4375             char *q;
4376             if (stream || feed || redirect) {
4377                 fprintf(stderr, "%s:%d: Already in a tag\n",
4378                         filename, line_num);
4379                 errors++;
4380             } else {
4381                 redirect = av_mallocz(sizeof(FFStream));
4382                 *last_stream = redirect;
4383                 last_stream = &redirect->next;
4384
4385                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4386                 q = strrchr(redirect->filename, '>');
4387                 if (*q)
4388                     *q = '\0';
4389                 redirect->stream_type = STREAM_TYPE_REDIRECT;
4390             }
4391         } else if (!strcasecmp(cmd, "URL")) {
4392             if (redirect)
4393                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4394         } else if (!strcasecmp(cmd, "</Redirect>")) {
4395             if (!redirect) {
4396                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4397                         filename, line_num);
4398                 errors++;
4399             } else {
4400                 if (!redirect->feed_filename[0]) {
4401                     fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4402                             filename, line_num);
4403                     errors++;
4404                 }
4405                 redirect = NULL;
4406             }
4407         } else if (!strcasecmp(cmd, "LoadModule")) {
4408             get_arg(arg, sizeof(arg), &p);
4409 #if HAVE_DLOPEN
4410             load_module(arg);
4411 #else
4412             fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4413                     filename, line_num, arg);
4414             errors++;
4415 #endif
4416         } else {
4417             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4418                     filename, line_num, cmd);
4419             errors++;
4420         }
4421     }
4422
4423     fclose(f);
4424     if (errors)
4425         return -1;
4426     else
4427         return 0;
4428 }
4429
4430 static void handle_child_exit(int sig)
4431 {
4432     pid_t pid;
4433     int status;
4434
4435     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4436         FFStream *feed;
4437
4438         for (feed = first_feed; feed; feed = feed->next) {
4439             if (feed->pid == pid) {
4440                 int uptime = time(0) - feed->pid_start;
4441
4442                 feed->pid = 0;
4443                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4444
4445                 if (uptime < 30)
4446                     /* Turn off any more restarts */
4447                     feed->child_argv = 0;
4448             }
4449         }
4450     }
4451
4452     need_to_start_children = 1;
4453 }
4454
4455 static void opt_debug(void)
4456 {
4457     ffserver_debug = 1;
4458     ffserver_daemon = 0;
4459     logfilename[0] = '-';
4460 }
4461
4462 static void opt_show_help(void)
4463 {
4464     printf("usage: ffserver [options]\n"
4465            "Hyper fast multi format Audio/Video streaming server\n");
4466     printf("\n");
4467     show_help_options(options, "Main options:\n", 0, 0);
4468 }
4469
4470 static const OptionDef options[] = {
4471     { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4472     { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4473     { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4474     { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4475     { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4476     { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4477     { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4478     { NULL },
4479 };
4480
4481 int main(int argc, char **argv)
4482 {
4483     struct sigaction sigact;
4484
4485     av_register_all();
4486
4487     show_banner();
4488
4489     config_filename = "/etc/ffserver.conf";
4490
4491     my_program_name = argv[0];
4492     my_program_dir = getcwd(0, 0);
4493     ffserver_daemon = 1;
4494
4495     parse_options(argc, argv, options, NULL);
4496
4497     unsetenv("http_proxy");             /* Kill the http_proxy */
4498
4499     av_random_init(&random_state, av_gettime() + (getpid() << 16));
4500
4501     memset(&sigact, 0, sizeof(sigact));
4502     sigact.sa_handler = handle_child_exit;
4503     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4504     sigaction(SIGCHLD, &sigact, 0);
4505
4506     if (parse_ffconfig(config_filename) < 0) {
4507         fprintf(stderr, "Incorrect config file - exiting.\n");
4508         exit(1);
4509     }
4510
4511     /* open log file if needed */
4512     if (logfilename[0] != '\0') {
4513         if (!strcmp(logfilename, "-"))
4514             logfile = stdout;
4515         else
4516             logfile = fopen(logfilename, "a");
4517         av_log_set_callback(http_av_log);
4518     }
4519
4520     build_file_streams();
4521
4522     build_feed_streams();
4523
4524     compute_bandwidth();
4525
4526     /* put the process in background and detach it from its TTY */
4527     if (ffserver_daemon) {
4528         int pid;
4529
4530         pid = fork();
4531         if (pid < 0) {
4532             perror("fork");
4533             exit(1);
4534         } else if (pid > 0) {
4535             /* parent : exit */
4536             exit(0);
4537         } else {
4538             /* child */
4539             setsid();
4540             close(0);
4541             open("/dev/null", O_RDWR);
4542             if (strcmp(logfilename, "-") != 0) {
4543                 close(1);
4544                 dup(0);
4545             }
4546             close(2);
4547             dup(0);
4548         }
4549     }
4550
4551     /* signal init */
4552     signal(SIGPIPE, SIG_IGN);
4553
4554     if (ffserver_daemon)
4555         chdir("/");
4556
4557     if (http_server() < 0) {
4558         http_log("Could not start server\n");
4559         exit(1);
4560     }
4561
4562     return 0;
4563 }