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