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