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