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