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