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