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