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