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