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