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