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