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