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