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