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