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