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