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