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