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