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