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