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