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