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