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