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