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