Tell configure about hppa, s390, mipsel, m68k and ia64 architectures.
[ffmpeg.git] / ffserver.c
1 /*
2  * Multiple format streaming server
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #define HAVE_AV_CONFIG_H
20 #include "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->time_base.den / st->codec->time_base.num);
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 1
1944     if (c->fmt_in->iformat->read_seek) {
1945         c->fmt_in->iformat->read_seek(c->fmt_in, 0, stream_pos, 0);
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             AVStream *src;
2002             st = av_mallocz(sizeof(AVStream));
2003             st->codec= avcodec_alloc_context();
2004             c->fmt_ctx.streams[i] = st;
2005             /* if file or feed, then just take streams from FFStream struct */
2006             if (!c->stream->feed || 
2007                 c->stream->feed == c->stream)
2008                 src = c->stream->streams[i];
2009             else
2010                 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2011
2012             *st = *src;
2013             st->priv_data = 0;
2014             st->codec->frame_number = 0; /* XXX: should be done in
2015                                            AVStream, not in codec */
2016             /* I'm pretty sure that this is not correct...
2017              * However, without it, we crash
2018              */
2019             st->codec->coded_frame = &dummy_frame;
2020         }
2021         c->got_key_frame = 0;
2022
2023         /* prepare header and save header data in a stream */
2024         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2025             /* XXX: potential leak */
2026             return -1;
2027         }
2028         c->fmt_ctx.pb.is_streamed = 1;
2029
2030         av_set_parameters(&c->fmt_ctx, NULL);
2031         av_write_header(&c->fmt_ctx);
2032
2033         len = url_close_dyn_buf(&c->fmt_ctx.pb, &c->pb_buffer);
2034         c->buffer_ptr = c->pb_buffer;
2035         c->buffer_end = c->pb_buffer + len;
2036
2037         c->state = HTTPSTATE_SEND_DATA;
2038         c->last_packet_sent = 0;
2039         break;
2040     case HTTPSTATE_SEND_DATA:
2041         /* find a new packet */
2042         {
2043             AVPacket pkt;
2044             
2045             /* read a packet from the input stream */
2046             if (c->stream->feed) {
2047                 ffm_set_write_index(c->fmt_in, 
2048                                     c->stream->feed->feed_write_index,
2049                                     c->stream->feed->feed_size);
2050             }
2051
2052             if (c->stream->max_time && 
2053                 c->stream->max_time + c->start_time - cur_time < 0) {
2054                 /* We have timed out */
2055                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2056             } else {
2057             redo:
2058                 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2059                     if (c->stream->feed && c->stream->feed->feed_opened) {
2060                         /* if coming from feed, it means we reached the end of the
2061                            ffm file, so must wait for more data */
2062                         c->state = HTTPSTATE_WAIT_FEED;
2063                         return 1; /* state changed */
2064                     } else {
2065                         if (c->stream->loop) {
2066                             av_close_input_file(c->fmt_in);
2067                             c->fmt_in = NULL;
2068                             if (open_input_stream(c, "") < 0)
2069                                 goto no_loop;
2070                             goto redo;
2071                         } else {
2072                         no_loop:
2073                             /* must send trailer now because eof or error */
2074                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2075                         }
2076                     }
2077                 } else {
2078                     /* update first pts if needed */
2079                     if (c->first_pts == AV_NOPTS_VALUE) {
2080                         c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2081                         c->start_time = cur_time;
2082                     }
2083                     /* send it to the appropriate stream */
2084                     if (c->stream->feed) {
2085                         /* if coming from a feed, select the right stream */
2086                         if (c->switch_pending) {
2087                             c->switch_pending = 0;
2088                             for(i=0;i<c->stream->nb_streams;i++) {
2089                                 if (c->switch_feed_streams[i] == pkt.stream_index) {
2090                                     if (pkt.flags & PKT_FLAG_KEY) {
2091                                         do_switch_stream(c, i);
2092                                     }
2093                                 }
2094                                 if (c->switch_feed_streams[i] >= 0) {
2095                                     c->switch_pending = 1;
2096                                 }
2097                             }
2098                         }
2099                         for(i=0;i<c->stream->nb_streams;i++) {
2100                             if (c->feed_streams[i] == pkt.stream_index) {
2101                                 pkt.stream_index = i;
2102                                 if (pkt.flags & PKT_FLAG_KEY) {
2103                                     c->got_key_frame |= 1 << i;
2104                                 }
2105                                 /* See if we have all the key frames, then 
2106                                  * we start to send. This logic is not quite
2107                                  * right, but it works for the case of a 
2108                                  * single video stream with one or more
2109                                  * audio streams (for which every frame is 
2110                                  * typically a key frame). 
2111                                  */
2112                                 if (!c->stream->send_on_key || 
2113                                     ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
2114                                     goto send_it;
2115                                 }
2116                             }
2117                         }
2118                     } else {
2119                         AVCodecContext *codec;
2120                         
2121                     send_it:
2122                         /* specific handling for RTP: we use several
2123                            output stream (one for each RTP
2124                            connection). XXX: need more abstract handling */
2125                         if (c->is_packetized) {
2126                             AVStream *st;
2127                             /* compute send time and duration */
2128                             st = c->fmt_in->streams[pkt.stream_index];
2129                             c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2130                             if (st->start_time != AV_NOPTS_VALUE)
2131                                 c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2132                             c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2133 #if 0
2134                             printf("index=%d pts=%0.3f duration=%0.6f\n",
2135                                    pkt.stream_index,
2136                                    (double)c->cur_pts / 
2137                                    AV_TIME_BASE,
2138                                    (double)c->cur_frame_duration / 
2139                                    AV_TIME_BASE);
2140 #endif
2141                             /* find RTP context */
2142                             c->packet_stream_index = pkt.stream_index;
2143                             ctx = c->rtp_ctx[c->packet_stream_index];
2144                             if(!ctx) {
2145                               av_free_packet(&pkt);
2146                               break;
2147                             }
2148                             codec = ctx->streams[0]->codec;
2149                             /* only one stream per RTP connection */
2150                             pkt.stream_index = 0;
2151                         } else {
2152                             ctx = &c->fmt_ctx;
2153                             /* Fudge here */
2154                             codec = ctx->streams[pkt.stream_index]->codec;
2155                         }
2156                         
2157                         codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2158                         if (c->is_packetized) {
2159                             int max_packet_size;
2160                             if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2161                                 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2162                             else
2163                                 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2164                             ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2165                         } else {
2166                             ret = url_open_dyn_buf(&ctx->pb);
2167                         }
2168                         if (ret < 0) {
2169                             /* XXX: potential leak */
2170                             return -1;
2171                         }
2172                         if (av_write_frame(ctx, &pkt)) {
2173                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2174                         }
2175                         
2176                         len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2177                         c->cur_frame_bytes = len;
2178                         c->buffer_ptr = c->pb_buffer;
2179                         c->buffer_end = c->pb_buffer + len;
2180                         
2181                         codec->frame_number++;
2182                         if (len == 0)
2183                             goto redo;
2184                     }
2185                     av_free_packet(&pkt);
2186                 }
2187             }
2188         }
2189         break;
2190     default:
2191     case HTTPSTATE_SEND_DATA_TRAILER:
2192         /* last packet test ? */
2193         if (c->last_packet_sent || c->is_packetized)
2194             return -1;
2195         ctx = &c->fmt_ctx;
2196         /* prepare header */
2197         if (url_open_dyn_buf(&ctx->pb) < 0) {
2198             /* XXX: potential leak */
2199             return -1;
2200         }
2201         av_write_trailer(ctx);
2202         len = url_close_dyn_buf(&ctx->pb, &c->pb_buffer);
2203         c->buffer_ptr = c->pb_buffer;
2204         c->buffer_end = c->pb_buffer + len;
2205
2206         c->last_packet_sent = 1;
2207         break;
2208     }
2209     return 0;
2210 }
2211
2212 /* in bit/s */
2213 #define SHORT_TERM_BANDWIDTH 8000000
2214
2215 /* should convert the format at the same time */
2216 /* send data starting at c->buffer_ptr to the output connection
2217    (either UDP or TCP connection) */
2218 static int http_send_data(HTTPContext *c)
2219 {
2220     int len, ret;
2221
2222     for(;;) {
2223         if (c->buffer_ptr >= c->buffer_end) {
2224             ret = http_prepare_data(c);
2225             if (ret < 0)
2226                 return -1;
2227             else if (ret != 0) {
2228                 /* state change requested */
2229                 break;
2230             }
2231         } else {
2232             if (c->is_packetized) {
2233                 /* RTP data output */
2234                 len = c->buffer_end - c->buffer_ptr;
2235                 if (len < 4) {
2236                     /* fail safe - should never happen */
2237                 fail1:
2238                     c->buffer_ptr = c->buffer_end;
2239                     return 0;
2240                 }
2241                 len = (c->buffer_ptr[0] << 24) |
2242                     (c->buffer_ptr[1] << 16) |
2243                     (c->buffer_ptr[2] << 8) |
2244                     (c->buffer_ptr[3]);
2245                 if (len > (c->buffer_end - c->buffer_ptr))
2246                     goto fail1;
2247                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2248                     /* nothing to send yet: we can wait */
2249                     return 0;
2250                 }
2251
2252                 c->data_count += len;
2253                 update_datarate(&c->datarate, c->data_count);
2254                 if (c->stream)
2255                     c->stream->bytes_served += len;
2256
2257                 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2258                     /* RTP packets are sent inside the RTSP TCP connection */
2259                     ByteIOContext pb1, *pb = &pb1;
2260                     int interleaved_index, size;
2261                     uint8_t header[4];
2262                     HTTPContext *rtsp_c;
2263                     
2264                     rtsp_c = c->rtsp_c;
2265                     /* if no RTSP connection left, error */
2266                     if (!rtsp_c)
2267                         return -1;
2268                     /* if already sending something, then wait. */
2269                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) {
2270                         break;
2271                     }
2272                     if (url_open_dyn_buf(pb) < 0)
2273                         goto fail1;
2274                     interleaved_index = c->packet_stream_index * 2;
2275                     /* RTCP packets are sent at odd indexes */
2276                     if (c->buffer_ptr[1] == 200)
2277                         interleaved_index++;
2278                     /* write RTSP TCP header */
2279                     header[0] = '$';
2280                     header[1] = interleaved_index;
2281                     header[2] = len >> 8;
2282                     header[3] = len;
2283                     put_buffer(pb, header, 4);
2284                     /* write RTP packet data */
2285                     c->buffer_ptr += 4;
2286                     put_buffer(pb, c->buffer_ptr, len);
2287                     size = url_close_dyn_buf(pb, &c->packet_buffer);
2288                     /* prepare asynchronous TCP sending */
2289                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
2290                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
2291                     c->buffer_ptr += len;
2292                     
2293                     /* send everything we can NOW */
2294                     len = write(rtsp_c->fd, rtsp_c->packet_buffer_ptr, 
2295                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr);
2296                     if (len > 0) {
2297                         rtsp_c->packet_buffer_ptr += len;
2298                     }
2299                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2300                         /* if we could not send all the data, we will
2301                            send it later, so a new state is needed to
2302                            "lock" the RTSP TCP connection */
2303                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
2304                         break;
2305                     } else {
2306                         /* all data has been sent */
2307                         av_freep(&c->packet_buffer);
2308                     }
2309                 } else {
2310                     /* send RTP packet directly in UDP */
2311                     c->buffer_ptr += 4;
2312                     url_write(c->rtp_handles[c->packet_stream_index], 
2313                               c->buffer_ptr, len);
2314                     c->buffer_ptr += len;
2315                     /* here we continue as we can send several packets per 10 ms slot */
2316                 }
2317             } else {
2318                 /* TCP data output */
2319                 len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2320                 if (len < 0) {
2321                     if (errno != EAGAIN && errno != EINTR) {
2322                         /* error : close connection */
2323                         return -1;
2324                     } else {
2325                         return 0;
2326                     }
2327                 } else {
2328                     c->buffer_ptr += len;
2329                 }
2330                 c->data_count += len;
2331                 update_datarate(&c->datarate, c->data_count);
2332                 if (c->stream)
2333                     c->stream->bytes_served += len;
2334                 break;
2335             }
2336         }
2337     } /* for(;;) */
2338     return 0;
2339 }
2340
2341 static int http_start_receive_data(HTTPContext *c)
2342 {
2343     int fd;
2344
2345     if (c->stream->feed_opened)
2346         return -1;
2347
2348     /* Don't permit writing to this one */
2349     if (c->stream->readonly)
2350         return -1;
2351
2352     /* open feed */
2353     fd = open(c->stream->feed_filename, O_RDWR);
2354     if (fd < 0)
2355         return -1;
2356     c->feed_fd = fd;
2357     
2358     c->stream->feed_write_index = ffm_read_write_index(fd);
2359     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2360     lseek(fd, 0, SEEK_SET);
2361
2362     /* init buffer input */
2363     c->buffer_ptr = c->buffer;
2364     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2365     c->stream->feed_opened = 1;
2366     return 0;
2367 }
2368     
2369 static int http_receive_data(HTTPContext *c)
2370 {
2371     HTTPContext *c1;
2372
2373     if (c->buffer_end > c->buffer_ptr) {
2374         int len;
2375
2376         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
2377         if (len < 0) {
2378             if (errno != EAGAIN && errno != EINTR) {
2379                 /* error : close connection */
2380                 goto fail;
2381             }
2382         } else if (len == 0) {
2383             /* end of connection : close it */
2384             goto fail;
2385         } else {
2386             c->buffer_ptr += len;
2387             c->data_count += len;
2388             update_datarate(&c->datarate, c->data_count);
2389         }
2390     }
2391
2392     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2393         if (c->buffer[0] != 'f' ||
2394             c->buffer[1] != 'm') {
2395             http_log("Feed stream has become desynchronized -- disconnecting\n");
2396             goto fail;
2397         }
2398     }
2399
2400     if (c->buffer_ptr >= c->buffer_end) {
2401         FFStream *feed = c->stream;
2402         /* a packet has been received : write it in the store, except
2403            if header */
2404         if (c->data_count > FFM_PACKET_SIZE) {
2405             
2406             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
2407             /* XXX: use llseek or url_seek */
2408             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2409             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2410             
2411             feed->feed_write_index += FFM_PACKET_SIZE;
2412             /* update file size */
2413             if (feed->feed_write_index > c->stream->feed_size)
2414                 feed->feed_size = feed->feed_write_index;
2415
2416             /* handle wrap around if max file size reached */
2417             if (feed->feed_write_index >= c->stream->feed_max_size)
2418                 feed->feed_write_index = FFM_PACKET_SIZE;
2419
2420             /* write index */
2421             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2422
2423             /* wake up any waiting connections */
2424             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2425                 if (c1->state == HTTPSTATE_WAIT_FEED && 
2426                     c1->stream->feed == c->stream->feed) {
2427                     c1->state = HTTPSTATE_SEND_DATA;
2428                 }
2429             }
2430         } else {
2431             /* We have a header in our hands that contains useful data */
2432             AVFormatContext s;
2433             AVInputFormat *fmt_in;
2434             ByteIOContext *pb = &s.pb;
2435             int i;
2436
2437             memset(&s, 0, sizeof(s));
2438
2439             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2440             pb->buf_end = c->buffer_end;        /* ?? */
2441             pb->is_streamed = 1;
2442
2443             /* use feed output format name to find corresponding input format */
2444             fmt_in = av_find_input_format(feed->fmt->name);
2445             if (!fmt_in)
2446                 goto fail;
2447
2448             if (fmt_in->priv_data_size > 0) {
2449                 s.priv_data = av_mallocz(fmt_in->priv_data_size);
2450                 if (!s.priv_data)
2451                     goto fail;
2452             } else
2453                 s.priv_data = NULL;
2454
2455             if (fmt_in->read_header(&s, 0) < 0) {
2456                 av_freep(&s.priv_data);
2457                 goto fail;
2458             }
2459
2460             /* Now we have the actual streams */
2461             if (s.nb_streams != feed->nb_streams) {
2462                 av_freep(&s.priv_data);
2463                 goto fail;
2464             }
2465             for (i = 0; i < s.nb_streams; i++) {
2466                 memcpy(feed->streams[i]->codec, 
2467                        s.streams[i]->codec, sizeof(AVCodecContext));
2468             } 
2469             av_freep(&s.priv_data);
2470         }
2471         c->buffer_ptr = c->buffer;
2472     }
2473
2474     return 0;
2475  fail:
2476     c->stream->feed_opened = 0;
2477     close(c->feed_fd);
2478     return -1;
2479 }
2480
2481 /********************************************************************/
2482 /* RTSP handling */
2483
2484 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2485 {
2486     const char *str;
2487     time_t ti;
2488     char *p;
2489     char buf2[32];
2490
2491     switch(error_number) {
2492 #define DEF(n, c, s) case c: str = s; break; 
2493 #include "rtspcodes.h"
2494 #undef DEF
2495     default:
2496         str = "Unknown Error";
2497         break;
2498     }
2499      
2500     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2501     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2502
2503     /* output GMT time */
2504     ti = time(NULL);
2505     p = ctime(&ti);
2506     strcpy(buf2, p);
2507     p = buf2 + strlen(p) - 1;
2508     if (*p == '\n')
2509         *p = '\0';
2510     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2511 }
2512
2513 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2514 {
2515     rtsp_reply_header(c, error_number);
2516     url_fprintf(c->pb, "\r\n");
2517 }
2518
2519 static int rtsp_parse_request(HTTPContext *c)
2520 {
2521     const char *p, *p1, *p2;
2522     char cmd[32];
2523     char url[1024];
2524     char protocol[32];
2525     char line[1024];
2526     ByteIOContext pb1;
2527     int len;
2528     RTSPHeader header1, *header = &header1;
2529     
2530     c->buffer_ptr[0] = '\0';
2531     p = c->buffer;
2532     
2533     get_word(cmd, sizeof(cmd), &p);
2534     get_word(url, sizeof(url), &p);
2535     get_word(protocol, sizeof(protocol), &p);
2536
2537     pstrcpy(c->method, sizeof(c->method), cmd);
2538     pstrcpy(c->url, sizeof(c->url), url);
2539     pstrcpy(c->protocol, sizeof(c->protocol), protocol);
2540
2541     c->pb = &pb1;
2542     if (url_open_dyn_buf(c->pb) < 0) {
2543         /* XXX: cannot do more */
2544         c->pb = NULL; /* safety */
2545         return -1;
2546     }
2547
2548     /* check version name */
2549     if (strcmp(protocol, "RTSP/1.0") != 0) {
2550         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2551         goto the_end;
2552     }
2553
2554     /* parse each header line */
2555     memset(header, 0, sizeof(RTSPHeader));
2556     /* skip to next line */
2557     while (*p != '\n' && *p != '\0')
2558         p++;
2559     if (*p == '\n')
2560         p++;
2561     while (*p != '\0') {
2562         p1 = strchr(p, '\n');
2563         if (!p1)
2564             break;
2565         p2 = p1;
2566         if (p2 > p && p2[-1] == '\r')
2567             p2--;
2568         /* skip empty line */
2569         if (p2 == p)
2570             break;
2571         len = p2 - p;
2572         if (len > sizeof(line) - 1)
2573             len = sizeof(line) - 1;
2574         memcpy(line, p, len);
2575         line[len] = '\0';
2576         rtsp_parse_line(header, line);
2577         p = p1 + 1;
2578     }
2579
2580     /* handle sequence number */
2581     c->seq = header->seq;
2582
2583     if (!strcmp(cmd, "DESCRIBE")) {
2584         rtsp_cmd_describe(c, url);
2585     } else if (!strcmp(cmd, "OPTIONS")) {
2586         rtsp_cmd_options(c, url);
2587     } else if (!strcmp(cmd, "SETUP")) {
2588         rtsp_cmd_setup(c, url, header);
2589     } else if (!strcmp(cmd, "PLAY")) {
2590         rtsp_cmd_play(c, url, header);
2591     } else if (!strcmp(cmd, "PAUSE")) {
2592         rtsp_cmd_pause(c, url, header);
2593     } else if (!strcmp(cmd, "TEARDOWN")) {
2594         rtsp_cmd_teardown(c, url, header);
2595     } else {
2596         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2597     }
2598  the_end:
2599     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2600     c->pb = NULL; /* safety */
2601     if (len < 0) {
2602         /* XXX: cannot do more */
2603         return -1;
2604     }
2605     c->buffer_ptr = c->pb_buffer;
2606     c->buffer_end = c->pb_buffer + len;
2607     c->state = RTSPSTATE_SEND_REPLY;
2608     return 0;
2609 }
2610
2611 /* XXX: move that to rtsp.c, but would need to replace FFStream by
2612    AVFormatContext */
2613 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, 
2614                                    struct in_addr my_ip)
2615 {
2616     ByteIOContext pb1, *pb = &pb1;
2617     int i, payload_type, port, private_payload_type, j;
2618     const char *ipstr, *title, *mediatype;
2619     AVStream *st;
2620     
2621     if (url_open_dyn_buf(pb) < 0)
2622         return -1;
2623     
2624     /* general media info */
2625
2626     url_fprintf(pb, "v=0\n");
2627     ipstr = inet_ntoa(my_ip);
2628     url_fprintf(pb, "o=- 0 0 IN IP4 %s\n", ipstr);
2629     title = stream->title;
2630     if (title[0] == '\0')
2631         title = "No Title";
2632     url_fprintf(pb, "s=%s\n", title);
2633     if (stream->comment[0] != '\0')
2634         url_fprintf(pb, "i=%s\n", stream->comment);
2635     if (stream->is_multicast) {
2636         url_fprintf(pb, "c=IN IP4 %s\n", inet_ntoa(stream->multicast_ip));
2637     }
2638     /* for each stream, we output the necessary info */
2639     private_payload_type = RTP_PT_PRIVATE;
2640     for(i = 0; i < stream->nb_streams; i++) {
2641         st = stream->streams[i];
2642         if (st->codec->codec_id == CODEC_ID_MPEG2TS) {
2643             mediatype = "video";
2644         } else {
2645             switch(st->codec->codec_type) {
2646             case CODEC_TYPE_AUDIO:
2647                 mediatype = "audio";
2648                 break;
2649             case CODEC_TYPE_VIDEO:
2650                 mediatype = "video";
2651                 break;
2652             default:
2653                 mediatype = "application";
2654                 break;
2655             }
2656         }
2657         /* NOTE: the port indication is not correct in case of
2658            unicast. It is not an issue because RTSP gives it */
2659         payload_type = rtp_get_payload_type(st->codec);
2660         if (payload_type < 0)
2661             payload_type = private_payload_type++;
2662         if (stream->is_multicast) {
2663             port = stream->multicast_port + 2 * i;
2664         } else {
2665             port = 0;
2666         }
2667         url_fprintf(pb, "m=%s %d RTP/AVP %d\n", 
2668                     mediatype, port, payload_type);
2669         if (payload_type >= RTP_PT_PRIVATE) {
2670             /* for private payload type, we need to give more info */
2671             switch(st->codec->codec_id) {
2672             case CODEC_ID_MPEG4:
2673                 {
2674                     uint8_t *data;
2675                     url_fprintf(pb, "a=rtpmap:%d MP4V-ES/%d\n", 
2676                                 payload_type, 90000);
2677                     /* we must also add the mpeg4 header */
2678                     data = st->codec->extradata;
2679                     if (data) {
2680                         url_fprintf(pb, "a=fmtp:%d config=", payload_type);
2681                         for(j=0;j<st->codec->extradata_size;j++) {
2682                             url_fprintf(pb, "%02x", data[j]);
2683                         }
2684                         url_fprintf(pb, "\n");
2685                     }
2686                 }
2687                 break;
2688             default:
2689                 /* XXX: add other codecs ? */
2690                 goto fail;
2691             }
2692         }
2693         url_fprintf(pb, "a=control:streamid=%d\n", i);
2694     }
2695     return url_close_dyn_buf(pb, pbuffer);
2696  fail:
2697     url_close_dyn_buf(pb, pbuffer);
2698     av_free(*pbuffer);
2699     return -1;
2700 }
2701
2702 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2703 {
2704 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2705     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2706     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2707     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2708     url_fprintf(c->pb, "\r\n");
2709 }
2710
2711 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2712 {
2713     FFStream *stream;
2714     char path1[1024];
2715     const char *path;
2716     uint8_t *content;
2717     int content_length, len;
2718     struct sockaddr_in my_addr;
2719     
2720     /* find which url is asked */
2721     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2722     path = path1;
2723     if (*path == '/')
2724         path++;
2725
2726     for(stream = first_stream; stream != NULL; stream = stream->next) {
2727         if (!stream->is_feed && stream->fmt == &rtp_mux &&
2728             !strcmp(path, stream->filename)) {
2729             goto found;
2730         }
2731     }
2732     /* no stream found */
2733     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2734     return;
2735
2736  found:
2737     /* prepare the media description in sdp format */
2738
2739     /* get the host IP */
2740     len = sizeof(my_addr);
2741     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2742     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2743     if (content_length < 0) {
2744         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2745         return;
2746     }
2747     rtsp_reply_header(c, RTSP_STATUS_OK);
2748     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2749     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2750     url_fprintf(c->pb, "\r\n");
2751     put_buffer(c->pb, content, content_length);
2752 }
2753
2754 static HTTPContext *find_rtp_session(const char *session_id)
2755 {
2756     HTTPContext *c;
2757
2758     if (session_id[0] == '\0')
2759         return NULL;
2760
2761     for(c = first_http_ctx; c != NULL; c = c->next) {
2762         if (!strcmp(c->session_id, session_id))
2763             return c;
2764     }
2765     return NULL;
2766 }
2767
2768 static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2769 {
2770     RTSPTransportField *th;
2771     int i;
2772
2773     for(i=0;i<h->nb_transports;i++) {
2774         th = &h->transports[i];
2775         if (th->protocol == protocol)
2776             return th;
2777     }
2778     return NULL;
2779 }
2780
2781 static void rtsp_cmd_setup(HTTPContext *c, const char *url, 
2782                            RTSPHeader *h)
2783 {
2784     FFStream *stream;
2785     int stream_index, port;
2786     char buf[1024];
2787     char path1[1024];
2788     const char *path;
2789     HTTPContext *rtp_c;
2790     RTSPTransportField *th;
2791     struct sockaddr_in dest_addr;
2792     RTSPActionServerSetup setup;
2793     
2794     /* find which url is asked */
2795     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2796     path = path1;
2797     if (*path == '/')
2798         path++;
2799
2800     /* now check each stream */
2801     for(stream = first_stream; stream != NULL; stream = stream->next) {
2802         if (!stream->is_feed && stream->fmt == &rtp_mux) {
2803             /* accept aggregate filenames only if single stream */
2804             if (!strcmp(path, stream->filename)) {
2805                 if (stream->nb_streams != 1) {
2806                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2807                     return;
2808                 }
2809                 stream_index = 0;
2810                 goto found;
2811             }
2812                 
2813             for(stream_index = 0; stream_index < stream->nb_streams;
2814                 stream_index++) {
2815                 snprintf(buf, sizeof(buf), "%s/streamid=%d", 
2816                          stream->filename, stream_index);
2817                 if (!strcmp(path, buf))
2818                     goto found;
2819             }
2820         }
2821     }
2822     /* no stream found */
2823     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2824     return;
2825  found:
2826
2827     /* generate session id if needed */
2828     if (h->session_id[0] == '\0') {
2829         snprintf(h->session_id, sizeof(h->session_id), 
2830                  "%08x%08x", (int)random(), (int)random());
2831     }
2832
2833     /* find rtp session, and create it if none found */
2834     rtp_c = find_rtp_session(h->session_id);
2835     if (!rtp_c) {
2836         /* always prefer UDP */
2837         th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2838         if (!th) {
2839             th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2840             if (!th) {
2841                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2842                 return;
2843             }
2844         }
2845
2846         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2847                                    th->protocol);
2848         if (!rtp_c) {
2849             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2850             return;
2851         }
2852
2853         /* open input stream */
2854         if (open_input_stream(rtp_c, "") < 0) {
2855             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2856             return;
2857         }
2858     }
2859     
2860     /* test if stream is OK (test needed because several SETUP needs
2861        to be done for a given file) */
2862     if (rtp_c->stream != stream) {
2863         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2864         return;
2865     }
2866     
2867     /* test if stream is already set up */
2868     if (rtp_c->rtp_ctx[stream_index]) {
2869         rtsp_reply_error(c, RTSP_STATUS_STATE);
2870         return;
2871     }
2872
2873     /* check transport */
2874     th = find_transport(h, rtp_c->rtp_protocol);
2875     if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP && 
2876                 th->client_port_min <= 0)) {
2877         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2878         return;
2879     }
2880
2881     /* setup default options */
2882     setup.transport_option[0] = '\0';
2883     dest_addr = rtp_c->from_addr;
2884     dest_addr.sin_port = htons(th->client_port_min);
2885     
2886     /* add transport option if needed */
2887     if (ff_rtsp_callback) {
2888         setup.ipaddr = ntohl(dest_addr.sin_addr.s_addr);
2889         if (ff_rtsp_callback(RTSP_ACTION_SERVER_SETUP, rtp_c->session_id, 
2890                              (char *)&setup, sizeof(setup),
2891                              stream->rtsp_option) < 0) {
2892             rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2893             return;
2894         }
2895         dest_addr.sin_addr.s_addr = htonl(setup.ipaddr);
2896     }
2897     
2898     /* setup stream */
2899     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2900         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2901         return;
2902     }
2903
2904     /* now everything is OK, so we can send the connection parameters */
2905     rtsp_reply_header(c, RTSP_STATUS_OK);
2906     /* session ID */
2907     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2908
2909     switch(rtp_c->rtp_protocol) {
2910     case RTSP_PROTOCOL_RTP_UDP:
2911         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2912         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2913                     "client_port=%d-%d;server_port=%d-%d",
2914                     th->client_port_min, th->client_port_min + 1,
2915                     port, port + 1);
2916         break;
2917     case RTSP_PROTOCOL_RTP_TCP:
2918         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2919                     stream_index * 2, stream_index * 2 + 1);
2920         break;
2921     default:
2922         break;
2923     }
2924     if (setup.transport_option[0] != '\0') {
2925         url_fprintf(c->pb, ";%s", setup.transport_option);
2926     }
2927     url_fprintf(c->pb, "\r\n");
2928     
2929
2930     url_fprintf(c->pb, "\r\n");
2931 }
2932
2933
2934 /* find an rtp connection by using the session ID. Check consistency
2935    with filename */
2936 static HTTPContext *find_rtp_session_with_url(const char *url, 
2937                                               const char *session_id)
2938 {
2939     HTTPContext *rtp_c;
2940     char path1[1024];
2941     const char *path;
2942     char buf[1024];
2943     int s;
2944
2945     rtp_c = find_rtp_session(session_id);
2946     if (!rtp_c)
2947         return NULL;
2948
2949     /* find which url is asked */
2950     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2951     path = path1;
2952     if (*path == '/')
2953         path++;
2954     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2955     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2956       snprintf(buf, sizeof(buf), "%s/streamid=%d",
2957         rtp_c->stream->filename, s);
2958       if(!strncmp(path, buf, sizeof(buf))) {
2959     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2960         return rtp_c;
2961       }
2962     }
2963     return NULL;
2964 }
2965
2966 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2967 {
2968     HTTPContext *rtp_c;
2969
2970     rtp_c = find_rtp_session_with_url(url, h->session_id);
2971     if (!rtp_c) {
2972         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2973         return;
2974     }
2975     
2976     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2977         rtp_c->state != HTTPSTATE_WAIT_FEED &&
2978         rtp_c->state != HTTPSTATE_READY) {
2979         rtsp_reply_error(c, RTSP_STATUS_STATE);
2980         return;
2981     }
2982
2983 #if 0
2984     /* XXX: seek in stream */
2985     if (h->range_start != AV_NOPTS_VALUE) {
2986         printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2987         av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2988     }
2989 #endif
2990
2991     rtp_c->state = HTTPSTATE_SEND_DATA;
2992     
2993     /* now everything is OK, so we can send the connection parameters */
2994     rtsp_reply_header(c, RTSP_STATUS_OK);
2995     /* session ID */
2996     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2997     url_fprintf(c->pb, "\r\n");
2998 }
2999
3000 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3001 {
3002     HTTPContext *rtp_c;
3003
3004     rtp_c = find_rtp_session_with_url(url, h->session_id);
3005     if (!rtp_c) {
3006         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3007         return;
3008     }
3009     
3010     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3011         rtp_c->state != HTTPSTATE_WAIT_FEED) {
3012         rtsp_reply_error(c, RTSP_STATUS_STATE);
3013         return;
3014     }
3015     
3016     rtp_c->state = HTTPSTATE_READY;
3017     rtp_c->first_pts = AV_NOPTS_VALUE;
3018     /* now everything is OK, so we can send the connection parameters */
3019     rtsp_reply_header(c, RTSP_STATUS_OK);
3020     /* session ID */
3021     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3022     url_fprintf(c->pb, "\r\n");
3023 }
3024
3025 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3026 {
3027     HTTPContext *rtp_c;
3028
3029     rtp_c = find_rtp_session_with_url(url, h->session_id);
3030     if (!rtp_c) {
3031         rtsp_reply_error(c, RTSP_STATUS_SESSION);
3032         return;
3033     }
3034     
3035     /* abort the session */
3036     close_connection(rtp_c);
3037
3038     if (ff_rtsp_callback) {
3039         ff_rtsp_callback(RTSP_ACTION_SERVER_TEARDOWN, rtp_c->session_id, 
3040                          NULL, 0,
3041                          rtp_c->stream->rtsp_option);
3042     }
3043
3044     /* now everything is OK, so we can send the connection parameters */
3045     rtsp_reply_header(c, RTSP_STATUS_OK);
3046     /* session ID */
3047     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3048     url_fprintf(c->pb, "\r\n");
3049 }
3050
3051
3052 /********************************************************************/
3053 /* RTP handling */
3054
3055 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, 
3056                                        FFStream *stream, const char *session_id,
3057                                        enum RTSPProtocol rtp_protocol)
3058 {
3059     HTTPContext *c = NULL;
3060     const char *proto_str;
3061     
3062     /* XXX: should output a warning page when coming
3063        close to the connection limit */
3064     if (nb_connections >= nb_max_connections)
3065         goto fail;
3066     
3067     /* add a new connection */
3068     c = av_mallocz(sizeof(HTTPContext));
3069     if (!c)
3070         goto fail;
3071     
3072     c->fd = -1;
3073     c->poll_entry = NULL;
3074     c->from_addr = *from_addr;
3075     c->buffer_size = IOBUFFER_INIT_SIZE;
3076     c->buffer = av_malloc(c->buffer_size);
3077     if (!c->buffer)
3078         goto fail;
3079     nb_connections++;
3080     c->stream = stream;
3081     pstrcpy(c->session_id, sizeof(c->session_id), session_id);
3082     c->state = HTTPSTATE_READY;
3083     c->is_packetized = 1;
3084     c->rtp_protocol = rtp_protocol;
3085
3086     /* protocol is shown in statistics */
3087     switch(c->rtp_protocol) {
3088     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3089         proto_str = "MCAST";
3090         break;
3091     case RTSP_PROTOCOL_RTP_UDP:
3092         proto_str = "UDP";
3093         break;
3094     case RTSP_PROTOCOL_RTP_TCP:
3095         proto_str = "TCP";
3096         break;
3097     default:
3098         proto_str = "???";
3099         break;
3100     }
3101     pstrcpy(c->protocol, sizeof(c->protocol), "RTP/");
3102     pstrcat(c->protocol, sizeof(c->protocol), proto_str);
3103
3104     current_bandwidth += stream->bandwidth;
3105
3106     c->next = first_http_ctx;
3107     first_http_ctx = c;
3108     return c;
3109         
3110  fail:
3111     if (c) {
3112         av_free(c->buffer);
3113         av_free(c);
3114     }
3115     return NULL;
3116 }
3117
3118 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3119    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3120    used. */
3121 static int rtp_new_av_stream(HTTPContext *c, 
3122                              int stream_index, struct sockaddr_in *dest_addr,
3123                              HTTPContext *rtsp_c)
3124 {
3125     AVFormatContext *ctx;
3126     AVStream *st;
3127     char *ipaddr;
3128     URLContext *h;
3129     uint8_t *dummy_buf;
3130     char buf2[32];
3131     int max_packet_size;
3132     
3133     /* now we can open the relevant output stream */
3134     ctx = av_alloc_format_context();
3135     if (!ctx)
3136         return -1;
3137     ctx->oformat = &rtp_mux;
3138
3139     st = av_mallocz(sizeof(AVStream));
3140     if (!st)
3141         goto fail;
3142     st->codec= avcodec_alloc_context();
3143     ctx->nb_streams = 1;
3144     ctx->streams[0] = st;
3145
3146     if (!c->stream->feed || 
3147         c->stream->feed == c->stream) {
3148         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3149     } else {
3150         memcpy(st, 
3151                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3152                sizeof(AVStream));
3153     }
3154     
3155     /* build destination RTP address */
3156     ipaddr = inet_ntoa(dest_addr->sin_addr);
3157
3158     switch(c->rtp_protocol) {
3159     case RTSP_PROTOCOL_RTP_UDP:
3160     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3161         /* RTP/UDP case */
3162         
3163         /* XXX: also pass as parameter to function ? */
3164         if (c->stream->is_multicast) {
3165             int ttl;
3166             ttl = c->stream->multicast_ttl;
3167             if (!ttl)
3168                 ttl = 16;
3169             snprintf(ctx->filename, sizeof(ctx->filename),
3170                      "rtp://%s:%d?multicast=1&ttl=%d", 
3171                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3172         } else {
3173             snprintf(ctx->filename, sizeof(ctx->filename),
3174                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3175         }
3176
3177         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3178             goto fail;
3179         c->rtp_handles[stream_index] = h;
3180         max_packet_size = url_get_max_packet_size(h);
3181         break;
3182     case RTSP_PROTOCOL_RTP_TCP:
3183         /* RTP/TCP case */
3184         c->rtsp_c = rtsp_c;
3185         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3186         break;
3187     default:
3188         goto fail;
3189     }
3190
3191     http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3192              ipaddr, ntohs(dest_addr->sin_port), 
3193              ctime1(buf2), 
3194              c->stream->filename, stream_index, c->protocol);
3195
3196     /* normally, no packets should be output here, but the packet size may be checked */
3197     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3198         /* XXX: close stream */
3199         goto fail;
3200     }
3201     av_set_parameters(ctx, NULL);
3202     if (av_write_header(ctx) < 0) {
3203     fail:
3204         if (h)
3205             url_close(h);
3206         av_free(ctx);
3207         return -1;
3208     }
3209     url_close_dyn_buf(&ctx->pb, &dummy_buf);
3210     av_free(dummy_buf);
3211     
3212     c->rtp_ctx[stream_index] = ctx;
3213     return 0;
3214 }
3215
3216 /********************************************************************/
3217 /* ffserver initialization */
3218
3219 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3220 {
3221     AVStream *fst;
3222
3223     fst = av_mallocz(sizeof(AVStream));
3224     if (!fst)
3225         return NULL;
3226     fst->codec= avcodec_alloc_context();
3227     fst->priv_data = av_mallocz(sizeof(FeedData));
3228     memcpy(fst->codec, codec, sizeof(AVCodecContext));
3229     fst->codec->coded_frame = &dummy_frame;
3230     fst->index = stream->nb_streams;
3231     av_set_pts_info(fst, 33, 1, 90000);
3232     stream->streams[stream->nb_streams++] = fst;
3233     return fst;
3234 }
3235
3236 /* return the stream number in the feed */
3237 static int add_av_stream(FFStream *feed, AVStream *st)
3238 {
3239     AVStream *fst;
3240     AVCodecContext *av, *av1;
3241     int i;
3242
3243     av = st->codec;
3244     for(i=0;i<feed->nb_streams;i++) {
3245         st = feed->streams[i];
3246         av1 = st->codec;
3247         if (av1->codec_id == av->codec_id &&
3248             av1->codec_type == av->codec_type &&
3249             av1->bit_rate == av->bit_rate) {
3250
3251             switch(av->codec_type) {
3252             case CODEC_TYPE_AUDIO:
3253                 if (av1->channels == av->channels &&
3254                     av1->sample_rate == av->sample_rate)
3255                     goto found;
3256                 break;
3257             case CODEC_TYPE_VIDEO:
3258                 if (av1->width == av->width &&
3259                     av1->height == av->height &&
3260                     av1->time_base.den == av->time_base.den &&
3261                     av1->time_base.num == av->time_base.num &&
3262                     av1->gop_size == av->gop_size)
3263                     goto found;
3264                 break;
3265             default:
3266                 av_abort();
3267             }
3268         }
3269     }
3270     
3271     fst = add_av_stream1(feed, av);
3272     if (!fst)
3273         return -1;
3274     return feed->nb_streams - 1;
3275  found:
3276     return i;
3277 }
3278
3279 static void remove_stream(FFStream *stream)
3280 {
3281     FFStream **ps;
3282     ps = &first_stream;
3283     while (*ps != NULL) {
3284         if (*ps == stream) {
3285             *ps = (*ps)->next;
3286         } else {
3287             ps = &(*ps)->next;
3288         }
3289     }
3290 }
3291
3292 /* specific mpeg4 handling : we extract the raw parameters */
3293 static void extract_mpeg4_header(AVFormatContext *infile)
3294 {
3295     int mpeg4_count, i, size;
3296     AVPacket pkt;
3297     AVStream *st;
3298     const uint8_t *p;
3299
3300     mpeg4_count = 0;
3301     for(i=0;i<infile->nb_streams;i++) {
3302         st = infile->streams[i];
3303         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3304             st->codec->extradata_size == 0) {
3305             mpeg4_count++;
3306         }
3307     }
3308     if (!mpeg4_count)
3309         return;
3310
3311     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3312     while (mpeg4_count > 0) {
3313         if (av_read_packet(infile, &pkt) < 0)
3314             break;
3315         st = infile->streams[pkt.stream_index];
3316         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3317             st->codec->extradata_size == 0) {
3318             av_freep(&st->codec->extradata);
3319             /* fill extradata with the header */
3320             /* XXX: we make hard suppositions here ! */
3321             p = pkt.data;
3322             while (p < pkt.data + pkt.size - 4) {
3323                 /* stop when vop header is found */
3324                 if (p[0] == 0x00 && p[1] == 0x00 && 
3325                     p[2] == 0x01 && p[3] == 0xb6) {
3326                     size = p - pkt.data;
3327                     //                    av_hex_dump(pkt.data, size);
3328                     st->codec->extradata = av_malloc(size);
3329                     st->codec->extradata_size = size;
3330                     memcpy(st->codec->extradata, pkt.data, size);
3331                     break;
3332                 }
3333                 p++;
3334             }
3335             mpeg4_count--;
3336         }
3337         av_free_packet(&pkt);
3338     }
3339 }
3340
3341 /* compute the needed AVStream for each file */
3342 static void build_file_streams(void)
3343 {
3344     FFStream *stream, *stream_next;
3345     AVFormatContext *infile;
3346     int i;
3347
3348     /* gather all streams */
3349     for(stream = first_stream; stream != NULL; stream = stream_next) {
3350         stream_next = stream->next;
3351         if (stream->stream_type == STREAM_TYPE_LIVE &&
3352             !stream->feed) {
3353             /* the stream comes from a file */
3354             /* try to open the file */
3355             /* open stream */
3356             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3357             if (stream->fmt == &rtp_mux) {
3358                 /* specific case : if transport stream output to RTP,
3359                    we use a raw transport stream reader */
3360                 stream->ap_in->mpeg2ts_raw = 1;
3361                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3362             }
3363             
3364             if (av_open_input_file(&infile, stream->feed_filename, 
3365                                    stream->ifmt, 0, stream->ap_in) < 0) {
3366                 http_log("%s not found", stream->feed_filename);
3367                 /* remove stream (no need to spend more time on it) */
3368             fail:
3369                 remove_stream(stream);
3370             } else {
3371                 /* find all the AVStreams inside and reference them in
3372                    'stream' */
3373                 if (av_find_stream_info(infile) < 0) {
3374                     http_log("Could not find codec parameters from '%s'", 
3375                              stream->feed_filename);
3376                     av_close_input_file(infile);
3377                     goto fail;
3378                 }
3379                 extract_mpeg4_header(infile);
3380
3381                 for(i=0;i<infile->nb_streams;i++) {
3382                     add_av_stream1(stream, infile->streams[i]->codec);
3383                 }
3384                 av_close_input_file(infile);
3385             }
3386         }
3387     }
3388 }
3389
3390 /* compute the needed AVStream for each feed */
3391 static void build_feed_streams(void)
3392 {
3393     FFStream *stream, *feed;
3394     int i;
3395
3396     /* gather all streams */
3397     for(stream = first_stream; stream != NULL; stream = stream->next) {
3398         feed = stream->feed;
3399         if (feed) {
3400             if (!stream->is_feed) {
3401                 /* we handle a stream coming from a feed */
3402                 for(i=0;i<stream->nb_streams;i++) {
3403                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3404                 }
3405             }
3406         }
3407     }
3408
3409     /* gather all streams */
3410     for(stream = first_stream; stream != NULL; stream = stream->next) {
3411         feed = stream->feed;
3412         if (feed) {
3413             if (stream->is_feed) {
3414                 for(i=0;i<stream->nb_streams;i++) {
3415                     stream->feed_streams[i] = i;
3416                 }
3417             }
3418         }
3419     }
3420
3421     /* create feed files if needed */
3422     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3423         int fd;
3424
3425         if (url_exist(feed->feed_filename)) {
3426             /* See if it matches */
3427             AVFormatContext *s;
3428             int matches = 0;
3429
3430             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3431                 /* Now see if it matches */
3432                 if (s->nb_streams == feed->nb_streams) {
3433                     matches = 1;
3434                     for(i=0;i<s->nb_streams;i++) {
3435                         AVStream *sf, *ss;
3436                         sf = feed->streams[i];
3437                         ss = s->streams[i];
3438
3439                         if (sf->index != ss->index ||
3440                             sf->id != ss->id) {
3441                             printf("Index & Id do not match for stream %d (%s)\n", 
3442                                    i, feed->feed_filename);
3443                             matches = 0;
3444                         } else {
3445                             AVCodecContext *ccf, *ccs;
3446
3447                             ccf = sf->codec;
3448                             ccs = ss->codec;
3449 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3450
3451                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3452                                 printf("Codecs do not match for stream %d\n", i);
3453                                 matches = 0;
3454                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3455                                 printf("Codec bitrates do not match for stream %d\n", i);
3456                                 matches = 0;
3457                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3458                                 if (CHECK_CODEC(time_base.den) ||
3459                                     CHECK_CODEC(time_base.num) ||
3460                                     CHECK_CODEC(width) ||
3461                                     CHECK_CODEC(height)) {
3462                                     printf("Codec width, height and framerate do not match for stream %d\n", i);
3463                                     matches = 0;
3464                                 }
3465                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3466                                 if (CHECK_CODEC(sample_rate) ||
3467                                     CHECK_CODEC(channels) ||
3468                                     CHECK_CODEC(frame_size)) {
3469                                     printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3470                                     matches = 0;
3471                                 }
3472                             } else {
3473                                 printf("Unknown codec type\n");
3474                                 matches = 0;
3475                             }
3476                         }
3477                         if (!matches) {
3478                             break;
3479                         }
3480                     }
3481                 } else {
3482                     printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3483                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3484                 }
3485
3486                 av_close_input_file(s);
3487             } else {
3488                 printf("Deleting feed file '%s' as it appears to be corrupt\n",
3489                         feed->feed_filename);
3490             }
3491             if (!matches) {
3492                 if (feed->readonly) {
3493                     printf("Unable to delete feed file '%s' as it is marked readonly\n",
3494                         feed->feed_filename);
3495                     exit(1);
3496                 }
3497                 unlink(feed->feed_filename);
3498             }
3499         }
3500         if (!url_exist(feed->feed_filename)) {
3501             AVFormatContext s1, *s = &s1;
3502
3503             if (feed->readonly) {
3504                 printf("Unable to create feed file '%s' as it is marked readonly\n",
3505                     feed->feed_filename);
3506                 exit(1);
3507             }
3508
3509             /* only write the header of the ffm file */
3510             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3511                 fprintf(stderr, "Could not open output feed file '%s'\n",
3512                         feed->feed_filename);
3513                 exit(1);
3514             }
3515             s->oformat = feed->fmt;
3516             s->nb_streams = feed->nb_streams;
3517             for(i=0;i<s->nb_streams;i++) {
3518                 AVStream *st;
3519                 st = feed->streams[i];
3520                 s->streams[i] = st;
3521             }
3522             av_set_parameters(s, NULL);
3523             av_write_header(s);
3524             /* XXX: need better api */
3525             av_freep(&s->priv_data);
3526             url_fclose(&s->pb);
3527         }
3528         /* get feed size and write index */
3529         fd = open(feed->feed_filename, O_RDONLY);
3530         if (fd < 0) {
3531             fprintf(stderr, "Could not open output feed file '%s'\n",
3532                     feed->feed_filename);
3533             exit(1);
3534         }
3535
3536         feed->feed_write_index = ffm_read_write_index(fd);
3537         feed->feed_size = lseek(fd, 0, SEEK_END);
3538         /* ensure that we do not wrap before the end of file */
3539         if (feed->feed_max_size < feed->feed_size)
3540             feed->feed_max_size = feed->feed_size;
3541
3542         close(fd);
3543     }
3544 }
3545
3546 /* compute the bandwidth used by each stream */
3547 static void compute_bandwidth(void)
3548 {
3549     int bandwidth, i;
3550     FFStream *stream;
3551     
3552     for(stream = first_stream; stream != NULL; stream = stream->next) {
3553         bandwidth = 0;
3554         for(i=0;i<stream->nb_streams;i++) {
3555             AVStream *st = stream->streams[i];
3556             switch(st->codec->codec_type) {
3557             case CODEC_TYPE_AUDIO:
3558             case CODEC_TYPE_VIDEO:
3559                 bandwidth += st->codec->bit_rate;
3560                 break;
3561             default:
3562                 break;
3563             }
3564         }
3565         stream->bandwidth = (bandwidth + 999) / 1000;
3566     }
3567 }
3568
3569 static void get_arg(char *buf, int buf_size, const char **pp)
3570 {
3571     const char *p;
3572     char *q;
3573     int quote;
3574
3575     p = *pp;
3576     while (isspace(*p)) p++;
3577     q = buf;
3578     quote = 0;
3579     if (*p == '\"' || *p == '\'')
3580         quote = *p++;
3581     for(;;) {
3582         if (quote) {
3583             if (*p == quote)
3584                 break;
3585         } else {
3586             if (isspace(*p))
3587                 break;
3588         }
3589         if (*p == '\0')
3590             break;
3591         if ((q - buf) < buf_size - 1)
3592             *q++ = *p;
3593         p++;
3594     }
3595     *q = '\0';
3596     if (quote && *p == quote)
3597         p++;
3598     *pp = p;
3599 }
3600
3601 /* add a codec and set the default parameters */
3602 static void add_codec(FFStream *stream, AVCodecContext *av)
3603 {
3604     AVStream *st;
3605
3606     /* compute default parameters */
3607     switch(av->codec_type) {
3608     case CODEC_TYPE_AUDIO:
3609         if (av->bit_rate == 0)
3610             av->bit_rate = 64000;
3611         if (av->sample_rate == 0)
3612             av->sample_rate = 22050;
3