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