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