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