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