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