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