]> git.sesse.net Git - ffmpeg/blob - ffserver.c
cosmetics, encode_variance -> encode_fast
[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 "avformat.h"
29 #include "rtsp.h"
30 #include "rtp.h"
31 #include "os_support.h"
32
33 #include <stdarg.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/ioctl.h>
37 #ifdef HAVE_SYS_POLL_H
38 #include <sys/poll.h>
39 #endif
40 #include <errno.h>
41 #include <sys/time.h>
42 #undef time //needed because HAVE_AV_CONFIG_H is defined on top
43 #include <time.h>
44 #include <sys/wait.h>
45 #include <signal.h>
46 #ifdef HAVE_DLFCN_H
47 #include <dlfcn.h>
48 #endif
49
50 #include "network.h"
51 #include "version.h"
52 #include "ffserver.h"
53 #include "random.h"
54 #include "avstring.h"
55 #include "cmdutils.h"
56
57 #undef exit
58
59 static const char program_name[] = "FFserver";
60 static const int program_birth_year = 2000;
61
62 /* maximum number of simultaneous HTTP connections */
63 #define HTTP_MAX_CONNECTIONS 2000
64
65 enum HTTPState {
66     HTTPSTATE_WAIT_REQUEST,
67     HTTPSTATE_SEND_HEADER,
68     HTTPSTATE_SEND_DATA_HEADER,
69     HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
70     HTTPSTATE_SEND_DATA_TRAILER,
71     HTTPSTATE_RECEIVE_DATA,
72     HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
73     HTTPSTATE_READY,
74
75     RTSPSTATE_WAIT_REQUEST,
76     RTSPSTATE_SEND_REPLY,
77     RTSPSTATE_SEND_PACKET,
78 };
79
80 const char *http_state[] = {
81     "HTTP_WAIT_REQUEST",
82     "HTTP_SEND_HEADER",
83
84     "SEND_DATA_HEADER",
85     "SEND_DATA",
86     "SEND_DATA_TRAILER",
87     "RECEIVE_DATA",
88     "WAIT_FEED",
89     "READY",
90
91     "RTSP_WAIT_REQUEST",
92     "RTSP_SEND_REPLY",
93     "RTSP_SEND_PACKET",
94 };
95
96 #define IOBUFFER_INIT_SIZE 8192
97
98 /* timeouts are in ms */
99 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
100 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
101
102 #define SYNC_TIMEOUT (10 * 1000)
103
104 typedef struct {
105     int64_t count1, count2;
106     int64_t time1, time2;
107 } DataRateData;
108
109 /* context associated with one connection */
110 typedef struct HTTPContext {
111     enum HTTPState state;
112     int fd; /* socket file descriptor */
113     struct sockaddr_in from_addr; /* origin */
114     struct pollfd *poll_entry; /* used when polling */
115     int64_t timeout;
116     uint8_t *buffer_ptr, *buffer_end;
117     int http_error;
118     int post;
119     struct HTTPContext *next;
120     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
121     int64_t data_count;
122     /* feed input */
123     int feed_fd;
124     /* input format handling */
125     AVFormatContext *fmt_in;
126     int64_t start_time;            /* In milliseconds - this wraps fairly often */
127     int64_t first_pts;            /* initial pts value */
128     int64_t cur_pts;             /* current pts value from the stream in us */
129     int64_t cur_frame_duration;  /* duration of the current frame in us */
130     int cur_frame_bytes;       /* output frame size, needed to compute
131                                   the time at which we send each
132                                   packet */
133     int pts_stream_index;        /* stream we choose as clock reference */
134     int64_t cur_clock;           /* current clock reference value in us */
135     /* output format handling */
136     struct FFStream *stream;
137     /* -1 is invalid stream */
138     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
139     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
140     int switch_pending;
141     AVFormatContext fmt_ctx; /* instance of FFStream for one user */
142     int last_packet_sent; /* true if last data packet was sent */
143     int suppress_log;
144     DataRateData datarate;
145     int wmp_client_id;
146     char protocol[16];
147     char method[16];
148     char url[128];
149     int buffer_size;
150     uint8_t *buffer;
151     int is_packetized; /* if true, the stream is packetized */
152     int packet_stream_index; /* current stream for output in state machine */
153
154     /* RTSP state specific */
155     uint8_t *pb_buffer; /* XXX: use that in all the code */
156     ByteIOContext *pb;
157     int seq; /* RTSP sequence number */
158
159     /* RTP state specific */
160     enum RTSPProtocol rtp_protocol;
161     char session_id[32]; /* session id */
162     AVFormatContext *rtp_ctx[MAX_STREAMS];
163
164     /* RTP/UDP specific */
165     URLContext *rtp_handles[MAX_STREAMS];
166
167     /* RTP/TCP specific */
168     struct HTTPContext *rtsp_c;
169     uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
170 } HTTPContext;
171
172 static AVFrame dummy_frame;
173
174 /* each generated stream is described here */
175 enum StreamType {
176     STREAM_TYPE_LIVE,
177     STREAM_TYPE_STATUS,
178     STREAM_TYPE_REDIRECT,
179 };
180
181 enum IPAddressAction {
182     IP_ALLOW = 1,
183     IP_DENY,
184 };
185
186 typedef struct IPAddressACL {
187     struct IPAddressACL *next;
188     enum IPAddressAction action;
189     /* These are in host order */
190     struct in_addr first;
191     struct in_addr last;
192 } IPAddressACL;
193
194 /* description of each stream of the ffserver.conf file */
195 typedef struct FFStream {
196     enum StreamType stream_type;
197     char filename[1024];     /* stream filename */
198     struct FFStream *feed;   /* feed we are using (can be null if
199                                 coming from file) */
200     AVFormatParameters *ap_in; /* input parameters */
201     AVInputFormat *ifmt;       /* if non NULL, force input format */
202     AVOutputFormat *fmt;
203     IPAddressACL *acl;
204     int nb_streams;
205     int prebuffer;      /* Number of millseconds early to start */
206     int64_t max_time;      /* Number of milliseconds to run */
207     int send_on_key;
208     AVStream *streams[MAX_STREAMS];
209     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
210     char feed_filename[1024]; /* file name of the feed storage, or
211                                  input file name for a stream */
212     char author[512];
213     char title[512];
214     char copyright[512];
215     char comment[512];
216     pid_t pid;  /* Of ffmpeg process */
217     time_t pid_start;  /* Of ffmpeg process */
218     char **child_argv;
219     struct FFStream *next;
220     int bandwidth; /* bandwidth, in kbits/s */
221     /* RTSP options */
222     char *rtsp_option;
223     /* multicast specific */
224     int is_multicast;
225     struct in_addr multicast_ip;
226     int multicast_port; /* first port used for multicast */
227     int multicast_ttl;
228     int loop; /* if true, send the stream in loops (only meaningful if file) */
229
230     /* feed specific */
231     int feed_opened;     /* true if someone is writing to the feed */
232     int is_feed;         /* true if it is a feed */
233     int readonly;        /* True if writing is prohibited to the file */
234     int conns_served;
235     int64_t bytes_served;
236     int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
237     int64_t feed_write_index;   /* current write position in feed (it wraps round) */
238     int64_t feed_size;          /* current size of feed */
239     struct FFStream *next_feed;
240 } FFStream;
241
242 typedef struct FeedData {
243     long long data_count;
244     float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
245 } FeedData;
246
247 static struct sockaddr_in my_http_addr;
248 static struct sockaddr_in my_rtsp_addr;
249
250 static char logfilename[1024];
251 static HTTPContext *first_http_ctx;
252 static FFStream *first_feed;   /* contains only feeds */
253 static FFStream *first_stream; /* contains all streams, including feeds */
254
255 static void new_connection(int server_fd, int is_rtsp);
256 static void close_connection(HTTPContext *c);
257
258 /* HTTP handling */
259 static int handle_connection(HTTPContext *c);
260 static int http_parse_request(HTTPContext *c);
261 static int http_send_data(HTTPContext *c);
262 static void compute_stats(HTTPContext *c);
263 static int open_input_stream(HTTPContext *c, const char *info);
264 static int http_start_receive_data(HTTPContext *c);
265 static int http_receive_data(HTTPContext *c);
266
267 /* RTSP handling */
268 static int rtsp_parse_request(HTTPContext *c);
269 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
270 static void rtsp_cmd_options(HTTPContext *c, const char *url);
271 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
272 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
273 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
274 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
275
276 /* SDP handling */
277 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
278                                    struct in_addr my_ip);
279
280 /* RTP handling */
281 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
282                                        FFStream *stream, const char *session_id,
283                                        enum RTSPProtocol rtp_protocol);
284 static int rtp_new_av_stream(HTTPContext *c,
285                              int stream_index, struct sockaddr_in *dest_addr,
286                              HTTPContext *rtsp_c);
287
288 static const char *my_program_name;
289 static const char *my_program_dir;
290
291 static 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;
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 (av_open_input_file(&s, input_filename, c->stream->ifmt,
1930                            buf_size, c->stream->ap_in) < 0) {
1931         http_log("%s not found", input_filename);
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             /* I'm pretty sure that this is not correct...
2025              * However, without it, we crash
2026              */
2027             st->codec->coded_frame = &dummy_frame;
2028         }
2029         c->got_key_frame = 0;
2030
2031         /* prepare header and save header data in a stream */
2032         if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2033             /* XXX: potential leak */
2034             return -1;
2035         }
2036         c->fmt_ctx.pb->is_streamed = 1;
2037
2038         av_set_parameters(&c->fmt_ctx, NULL);
2039         if (av_write_header(&c->fmt_ctx) < 0)
2040             return -1;
2041
2042         len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2043         c->buffer_ptr = c->pb_buffer;
2044         c->buffer_end = c->pb_buffer + len;
2045
2046         c->state = HTTPSTATE_SEND_DATA;
2047         c->last_packet_sent = 0;
2048         break;
2049     case HTTPSTATE_SEND_DATA:
2050         /* find a new packet */
2051         {
2052             AVPacket pkt;
2053
2054             /* read a packet from the input stream */
2055             if (c->stream->feed)
2056                 ffm_set_write_index(c->fmt_in,
2057                                     c->stream->feed->feed_write_index,
2058                                     c->stream->feed->feed_size);
2059
2060             if (c->stream->max_time &&
2061                 c->stream->max_time + c->start_time - cur_time < 0)
2062                 /* We have timed out */
2063                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2064             else {
2065             redo:
2066                 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2067                     if (c->stream->feed && c->stream->feed->feed_opened) {
2068                         /* if coming from feed, it means we reached the end of the
2069                            ffm file, so must wait for more data */
2070                         c->state = HTTPSTATE_WAIT_FEED;
2071                         return 1; /* state changed */
2072                     } else {
2073                         if (c->stream->loop) {
2074                             av_close_input_file(c->fmt_in);
2075                             c->fmt_in = NULL;
2076                             if (open_input_stream(c, "") < 0)
2077                                 goto no_loop;
2078                             goto redo;
2079                         } else {
2080                         no_loop:
2081                             /* must send trailer now because eof or error */
2082                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2083                         }
2084                     }
2085                 } else {
2086                     /* update first pts if needed */
2087                     if (c->first_pts == AV_NOPTS_VALUE) {
2088                         c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2089                         c->start_time = cur_time;
2090                     }
2091                     /* send it to the appropriate stream */
2092                     if (c->stream->feed) {
2093                         /* if coming from a feed, select the right stream */
2094                         if (c->switch_pending) {
2095                             c->switch_pending = 0;
2096                             for(i=0;i<c->stream->nb_streams;i++) {
2097                                 if (c->switch_feed_streams[i] == pkt.stream_index)
2098                                     if (pkt.flags & PKT_FLAG_KEY)
2099                                         do_switch_stream(c, i);
2100                                 if (c->switch_feed_streams[i] >= 0)
2101                                     c->switch_pending = 1;
2102                             }
2103                         }
2104                         for(i=0;i<c->stream->nb_streams;i++) {
2105                             if (c->feed_streams[i] == pkt.stream_index) {
2106                                 pkt.stream_index = i;
2107                                 if (pkt.flags & PKT_FLAG_KEY)
2108                                     c->got_key_frame |= 1 << i;
2109                                 /* See if we have all the key frames, then
2110                                  * we start to send. This logic is not quite
2111                                  * right, but it works for the case of a
2112                                  * single video stream with one or more
2113                                  * audio streams (for which every frame is
2114                                  * typically a key frame).
2115                                  */
2116                                 if (!c->stream->send_on_key ||
2117                                     ((c->got_key_frame + 1) >> c->stream->nb_streams))
2118                                     goto send_it;
2119                             }
2120                         }
2121                     } else {
2122                         AVCodecContext *codec;
2123
2124                     send_it:
2125                         /* specific handling for RTP: we use several
2126                            output stream (one for each RTP
2127                            connection). XXX: need more abstract handling */
2128                         if (c->is_packetized) {
2129                             AVStream *st;
2130                             /* compute send time and duration */
2131                             st = c->fmt_in->streams[pkt.stream_index];
2132                             c->cur_pts = av_rescale_q(pkt.dts, st->time_base, AV_TIME_BASE_Q);
2133                             if (st->start_time != AV_NOPTS_VALUE)
2134                                 c->cur_pts -= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
2135                             c->cur_frame_duration = av_rescale_q(pkt.duration, st->time_base, AV_TIME_BASE_Q);
2136 #if 0
2137                             printf("index=%d pts=%0.3f duration=%0.6f\n",
2138                                    pkt.stream_index,
2139                                    (double)c->cur_pts /
2140                                    AV_TIME_BASE,
2141                                    (double)c->cur_frame_duration /
2142                                    AV_TIME_BASE);
2143 #endif
2144                             /* find RTP context */
2145                             c->packet_stream_index = pkt.stream_index;
2146                             ctx = c->rtp_ctx[c->packet_stream_index];
2147                             if(!ctx) {
2148                               av_free_packet(&pkt);
2149                               break;
2150                             }
2151                             codec = ctx->streams[0]->codec;
2152                             /* only one stream per RTP connection */
2153                             pkt.stream_index = 0;
2154                         } else {
2155                             ctx = &c->fmt_ctx;
2156                             /* Fudge here */
2157                             codec = ctx->streams[pkt.stream_index]->codec;
2158                         }
2159
2160                         codec->coded_frame->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
2161                         if (c->is_packetized) {
2162                             int max_packet_size;
2163                             if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2164                                 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2165                             else
2166                                 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2167                             ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2168                         } else {
2169                             ret = url_open_dyn_buf(&ctx->pb);
2170                         }
2171                         if (ret < 0) {
2172                             /* XXX: potential leak */
2173                             return -1;
2174                         }
2175                         if (pkt.dts != AV_NOPTS_VALUE)
2176                             pkt.dts = av_rescale_q(pkt.dts,
2177                                 c->fmt_in->streams[pkt.stream_index]->time_base,
2178                                 ctx->streams[pkt.stream_index]->time_base);
2179                         if (pkt.pts != AV_NOPTS_VALUE)
2180                             pkt.pts = av_rescale_q(pkt.pts,
2181                                 c->fmt_in->streams[pkt.stream_index]->time_base,
2182                                 ctx->streams[pkt.stream_index]->time_base);
2183                         if (av_write_frame(ctx, &pkt))
2184                             c->state = HTTPSTATE_SEND_DATA_TRAILER;
2185
2186                         len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2187                         c->cur_frame_bytes = len;
2188                         c->buffer_ptr = c->pb_buffer;
2189                         c->buffer_end = c->pb_buffer + len;
2190
2191                         codec->frame_number++;
2192                         if (len == 0)
2193                             goto redo;
2194                     }
2195                     av_free_packet(&pkt);
2196                 }
2197             }
2198         }
2199         break;
2200     default:
2201     case HTTPSTATE_SEND_DATA_TRAILER:
2202         /* last packet test ? */
2203         if (c->last_packet_sent || c->is_packetized)
2204             return -1;
2205         ctx = &c->fmt_ctx;
2206         /* prepare header */
2207         if (url_open_dyn_buf(&ctx->pb) < 0) {
2208             /* XXX: potential leak */
2209             return -1;
2210         }
2211         av_write_trailer(ctx);
2212         len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2213         c->buffer_ptr = c->pb_buffer;
2214         c->buffer_end = c->pb_buffer + len;
2215
2216         c->last_packet_sent = 1;
2217         break;
2218     }
2219     return 0;
2220 }
2221
2222 /* should convert the format at the same time */
2223 /* send data starting at c->buffer_ptr to the output connection
2224    (either UDP or TCP connection) */
2225 static int http_send_data(HTTPContext *c)
2226 {
2227     int len, ret;
2228
2229     for(;;) {
2230         if (c->buffer_ptr >= c->buffer_end) {
2231             ret = http_prepare_data(c);
2232             if (ret < 0)
2233                 return -1;
2234             else if (ret != 0)
2235                 /* state change requested */
2236                 break;
2237         } else {
2238             if (c->is_packetized) {
2239                 /* RTP data output */
2240                 len = c->buffer_end - c->buffer_ptr;
2241                 if (len < 4) {
2242                     /* fail safe - should never happen */
2243                 fail1:
2244                     c->buffer_ptr = c->buffer_end;
2245                     return 0;
2246                 }
2247                 len = (c->buffer_ptr[0] << 24) |
2248                     (c->buffer_ptr[1] << 16) |
2249                     (c->buffer_ptr[2] << 8) |
2250                     (c->buffer_ptr[3]);
2251                 if (len > (c->buffer_end - c->buffer_ptr))
2252                     goto fail1;
2253                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2254                     /* nothing to send yet: we can wait */
2255                     return 0;
2256                 }
2257
2258                 c->data_count += len;
2259                 update_datarate(&c->datarate, c->data_count);
2260                 if (c->stream)
2261                     c->stream->bytes_served += len;
2262
2263                 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2264                     /* RTP packets are sent inside the RTSP TCP connection */
2265                     ByteIOContext *pb;
2266                     int interleaved_index, size;
2267                     uint8_t header[4];
2268                     HTTPContext *rtsp_c;
2269
2270                     rtsp_c = c->rtsp_c;
2271                     /* if no RTSP connection left, error */
2272                     if (!rtsp_c)
2273                         return -1;
2274                     /* if already sending something, then wait. */
2275                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2276                         break;
2277                     if (url_open_dyn_buf(&pb) < 0)
2278                         goto fail1;
2279                     interleaved_index = c->packet_stream_index * 2;
2280                     /* RTCP packets are sent at odd indexes */
2281                     if (c->buffer_ptr[1] == 200)
2282                         interleaved_index++;
2283                     /* write RTSP TCP header */
2284                     header[0] = '$';
2285                     header[1] = interleaved_index;
2286                     header[2] = len >> 8;
2287                     header[3] = len;
2288                     put_buffer(pb, header, 4);
2289                     /* write RTP packet data */
2290                     c->buffer_ptr += 4;
2291                     put_buffer(pb, c->buffer_ptr, len);
2292                     size = url_close_dyn_buf(pb, &c->packet_buffer);
2293                     /* prepare asynchronous TCP sending */
2294                     rtsp_c->packet_buffer_ptr = c->packet_buffer;
2295                     rtsp_c->packet_buffer_end = c->packet_buffer + size;
2296                     c->buffer_ptr += len;
2297
2298                     /* send everything we can NOW */
2299                     len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2300                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2301                     if (len > 0)
2302                         rtsp_c->packet_buffer_ptr += len;
2303                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2304                         /* if we could not send all the data, we will
2305                            send it later, so a new state is needed to
2306                            "lock" the RTSP TCP connection */
2307                         rtsp_c->state = RTSPSTATE_SEND_PACKET;
2308                         break;
2309                     } else
2310                         /* all data has been sent */
2311                         av_freep(&c->packet_buffer);
2312                 } else {
2313                     /* send RTP packet directly in UDP */
2314                     c->buffer_ptr += 4;
2315                     url_write(c->rtp_handles[c->packet_stream_index],
2316                               c->buffer_ptr, len);
2317                     c->buffer_ptr += len;
2318                     /* here we continue as we can send several packets per 10 ms slot */
2319                 }
2320             } else {
2321                 /* TCP data output */
2322                 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2323                 if (len < 0) {
2324                     if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2325                         ff_neterrno() != FF_NETERROR(EINTR))
2326                         /* error : close connection */
2327                         return -1;
2328                     else
2329                         return 0;
2330                 } else
2331                     c->buffer_ptr += len;
2332
2333                 c->data_count += len;
2334                 update_datarate(&c->datarate, c->data_count);
2335                 if (c->stream)
2336                     c->stream->bytes_served += len;
2337                 break;
2338             }
2339         }
2340     } /* for(;;) */
2341     return 0;
2342 }
2343
2344 static int http_start_receive_data(HTTPContext *c)
2345 {
2346     int fd;
2347
2348     if (c->stream->feed_opened)
2349         return -1;
2350
2351     /* Don't permit writing to this one */
2352     if (c->stream->readonly)
2353         return -1;
2354
2355     /* open feed */
2356     fd = open(c->stream->feed_filename, O_RDWR);
2357     if (fd < 0)
2358         return -1;
2359     c->feed_fd = fd;
2360
2361     c->stream->feed_write_index = ffm_read_write_index(fd);
2362     c->stream->feed_size = lseek(fd, 0, SEEK_END);
2363     lseek(fd, 0, SEEK_SET);
2364
2365     /* init buffer input */
2366     c->buffer_ptr = c->buffer;
2367     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2368     c->stream->feed_opened = 1;
2369     return 0;
2370 }
2371
2372 static int http_receive_data(HTTPContext *c)
2373 {
2374     HTTPContext *c1;
2375
2376     if (c->buffer_end > c->buffer_ptr) {
2377         int len;
2378
2379         len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2380         if (len < 0) {
2381             if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2382                 ff_neterrno() != FF_NETERROR(EINTR))
2383                 /* error : close connection */
2384                 goto fail;
2385         } else if (len == 0)
2386             /* end of connection : close it */
2387             goto fail;
2388         else {
2389             c->buffer_ptr += len;
2390             c->data_count += len;
2391             update_datarate(&c->datarate, c->data_count);
2392         }
2393     }
2394
2395     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2396         if (c->buffer[0] != 'f' ||
2397             c->buffer[1] != 'm') {
2398             http_log("Feed stream has become desynchronized -- disconnecting\n");
2399             goto fail;
2400         }
2401     }
2402
2403     if (c->buffer_ptr >= c->buffer_end) {
2404         FFStream *feed = c->stream;
2405         /* a packet has been received : write it in the store, except
2406            if header */
2407         if (c->data_count > FFM_PACKET_SIZE) {
2408
2409             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2410             /* XXX: use llseek or url_seek */
2411             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2412             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
2413
2414             feed->feed_write_index += FFM_PACKET_SIZE;
2415             /* update file size */
2416             if (feed->feed_write_index > c->stream->feed_size)
2417                 feed->feed_size = feed->feed_write_index;
2418
2419             /* handle wrap around if max file size reached */
2420             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2421                 feed->feed_write_index = FFM_PACKET_SIZE;
2422
2423             /* write index */
2424             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2425
2426             /* wake up any waiting connections */
2427             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2428                 if (c1->state == HTTPSTATE_WAIT_FEED &&
2429                     c1->stream->feed == c->stream->feed)
2430                     c1->state = HTTPSTATE_SEND_DATA;
2431             }
2432         } else {
2433             /* We have a header in our hands that contains useful data */
2434             AVFormatContext s;
2435             AVInputFormat *fmt_in;
2436             int i;
2437
2438             memset(&s, 0, sizeof(s));
2439
2440             url_open_buf(&s.pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2441             s.pb->buf_end = c->buffer_end;        /* ?? */
2442             s.pb->is_streamed = 1;
2443
2444             /* use feed output format name to find corresponding input format */
2445             fmt_in = av_find_input_format(feed->fmt->name);
2446             if (!fmt_in)
2447                 goto fail;
2448
2449             if (fmt_in->priv_data_size > 0) {
2450                 s.priv_data = av_mallocz(fmt_in->priv_data_size);
2451                 if (!s.priv_data)
2452                     goto fail;
2453             } else
2454                 s.priv_data = NULL;
2455
2456             if (fmt_in->read_header(&s, 0) < 0) {
2457                 av_freep(&s.priv_data);
2458                 goto fail;
2459             }
2460
2461             /* Now we have the actual streams */
2462             if (s.nb_streams != feed->nb_streams) {
2463                 av_freep(&s.priv_data);
2464                 goto fail;
2465             }
2466             for (i = 0; i < s.nb_streams; i++)
2467                 memcpy(feed->streams[i]->codec,
2468                        s.streams[i]->codec, sizeof(AVCodecContext));
2469             av_freep(&s.priv_data);
2470         }
2471         c->buffer_ptr = c->buffer;
2472     }
2473
2474     return 0;
2475  fail:
2476     c->stream->feed_opened = 0;
2477     close(c->feed_fd);
2478     return -1;
2479 }
2480
2481 /********************************************************************/
2482 /* RTSP handling */
2483
2484 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2485 {
2486     const char *str;
2487     time_t ti;
2488     char *p;
2489     char buf2[32];
2490
2491     switch(error_number) {
2492     case RTSP_STATUS_OK:
2493         str = "OK";
2494         break;
2495     case RTSP_STATUS_METHOD:
2496         str = "Method Not Allowed";
2497         break;
2498     case RTSP_STATUS_BANDWIDTH:
2499         str = "Not Enough Bandwidth";
2500         break;
2501     case RTSP_STATUS_SESSION:
2502         str = "Session Not Found";
2503         break;
2504     case RTSP_STATUS_STATE:
2505         str = "Method Not Valid in This State";
2506         break;
2507     case RTSP_STATUS_AGGREGATE:
2508         str = "Aggregate operation not allowed";
2509         break;
2510     case RTSP_STATUS_ONLY_AGGREGATE:
2511         str = "Only aggregate operation allowed";
2512         break;
2513     case RTSP_STATUS_TRANSPORT:
2514         str = "Unsupported transport";
2515         break;
2516     case RTSP_STATUS_INTERNAL:
2517         str = "Internal Server Error";
2518         break;
2519     case RTSP_STATUS_SERVICE:
2520         str = "Service Unavailable";
2521         break;
2522     case RTSP_STATUS_VERSION:
2523         str = "RTSP Version not supported";
2524         break;
2525     default:
2526         str = "Unknown Error";
2527         break;
2528     }
2529
2530     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2531     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2532
2533     /* output GMT time */
2534     ti = time(NULL);
2535     p = ctime(&ti);
2536     strcpy(buf2, p);
2537     p = buf2 + strlen(p) - 1;
2538     if (*p == '\n')
2539         *p = '\0';
2540     url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2541 }
2542
2543 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2544 {
2545     rtsp_reply_header(c, error_number);
2546     url_fprintf(c->pb, "\r\n");
2547 }
2548
2549 static int rtsp_parse_request(HTTPContext *c)
2550 {
2551     const char *p, *p1, *p2;
2552     char cmd[32];
2553     char url[1024];
2554     char protocol[32];
2555     char line[1024];
2556     int len;
2557     RTSPHeader header1, *header = &header1;
2558
2559     c->buffer_ptr[0] = '\0';
2560     p = c->buffer;
2561
2562     get_word(cmd, sizeof(cmd), &p);
2563     get_word(url, sizeof(url), &p);
2564     get_word(protocol, sizeof(protocol), &p);
2565
2566     av_strlcpy(c->method, cmd, sizeof(c->method));
2567     av_strlcpy(c->url, url, sizeof(c->url));
2568     av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2569
2570     if (url_open_dyn_buf(&c->pb) < 0) {
2571         /* XXX: cannot do more */
2572         c->pb = NULL; /* safety */
2573         return -1;
2574     }
2575
2576     /* check version name */
2577     if (strcmp(protocol, "RTSP/1.0") != 0) {
2578         rtsp_reply_error(c, RTSP_STATUS_VERSION);
2579         goto the_end;
2580     }
2581
2582     /* parse each header line */
2583     memset(header, 0, sizeof(RTSPHeader));
2584     /* skip to next line */
2585     while (*p != '\n' && *p != '\0')
2586         p++;
2587     if (*p == '\n')
2588         p++;
2589     while (*p != '\0') {
2590         p1 = strchr(p, '\n');
2591         if (!p1)
2592             break;
2593         p2 = p1;
2594         if (p2 > p && p2[-1] == '\r')
2595             p2--;
2596         /* skip empty line */
2597         if (p2 == p)
2598             break;
2599         len = p2 - p;
2600         if (len > sizeof(line) - 1)
2601             len = sizeof(line) - 1;
2602         memcpy(line, p, len);
2603         line[len] = '\0';
2604         rtsp_parse_line(header, line);
2605         p = p1 + 1;
2606     }
2607
2608     /* handle sequence number */
2609     c->seq = header->seq;
2610
2611     if (!strcmp(cmd, "DESCRIBE"))
2612         rtsp_cmd_describe(c, url);
2613     else if (!strcmp(cmd, "OPTIONS"))
2614         rtsp_cmd_options(c, url);
2615     else if (!strcmp(cmd, "SETUP"))
2616         rtsp_cmd_setup(c, url, header);
2617     else if (!strcmp(cmd, "PLAY"))
2618         rtsp_cmd_play(c, url, header);
2619     else if (!strcmp(cmd, "PAUSE"))
2620         rtsp_cmd_pause(c, url, header);
2621     else if (!strcmp(cmd, "TEARDOWN"))
2622         rtsp_cmd_teardown(c, url, header);
2623     else
2624         rtsp_reply_error(c, RTSP_STATUS_METHOD);
2625
2626  the_end:
2627     len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2628     c->pb = NULL; /* safety */
2629     if (len < 0) {
2630         /* XXX: cannot do more */
2631         return -1;
2632     }
2633     c->buffer_ptr = c->pb_buffer;
2634     c->buffer_end = c->pb_buffer + len;
2635     c->state = RTSPSTATE_SEND_REPLY;
2636     return 0;
2637 }
2638
2639 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2640                                    struct in_addr my_ip)
2641 {
2642     AVFormatContext *avc;
2643     AVStream avs[MAX_STREAMS];
2644     int i;
2645
2646     avc =  av_alloc_format_context();
2647     if (avc == NULL) {
2648         return -1;
2649     }
2650     if (stream->title[0] != 0) {
2651         av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2652     } else {
2653         av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2654     }
2655     avc->nb_streams = stream->nb_streams;
2656     if (stream->is_multicast) {
2657         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2658                  inet_ntoa(stream->multicast_ip),
2659                  stream->multicast_port, stream->multicast_ttl);
2660     }
2661
2662     for(i = 0; i < stream->nb_streams; i++) {
2663         avc->streams[i] = &avs[i];
2664         avc->streams[i]->codec = stream->streams[i]->codec;
2665     }
2666     *pbuffer = av_mallocz(2048);
2667     avf_sdp_create(&avc, 1, *pbuffer, 2048);
2668     av_free(avc);
2669
2670     return strlen(*pbuffer);
2671 }
2672
2673 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2674 {
2675 //    rtsp_reply_header(c, RTSP_STATUS_OK);
2676     url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2677     url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2678     url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2679     url_fprintf(c->pb, "\r\n");
2680 }
2681
2682 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2683 {
2684     FFStream *stream;
2685     char path1[1024];
2686     const char *path;
2687     uint8_t *content;
2688     int content_length, len;
2689     struct sockaddr_in my_addr;
2690
2691     /* find which url is asked */
2692     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2693     path = path1;
2694     if (*path == '/')
2695         path++;
2696
2697     for(stream = first_stream; stream != NULL; stream = stream->next) {
2698         if (!stream->is_feed &&
2699             stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2700             !strcmp(path, stream->filename)) {
2701             goto found;
2702         }
2703     }
2704     /* no stream found */
2705     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2706     return;
2707
2708  found:
2709     /* prepare the media description in sdp format */
2710
2711     /* get the host IP */
2712     len = sizeof(my_addr);
2713     getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2714     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2715     if (content_length < 0) {
2716         rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2717         return;
2718     }
2719     rtsp_reply_header(c, RTSP_STATUS_OK);
2720     url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2721     url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2722     url_fprintf(c->pb, "\r\n");
2723     put_buffer(c->pb, content, content_length);
2724 }
2725
2726 static HTTPContext *find_rtp_session(const char *session_id)
2727 {
2728     HTTPContext *c;
2729
2730     if (session_id[0] == '\0')
2731         return NULL;
2732
2733     for(c = first_http_ctx; c != NULL; c = c->next) {
2734         if (!strcmp(c->session_id, session_id))
2735             return c;
2736     }
2737     return NULL;
2738 }
2739
2740 static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2741 {
2742     RTSPTransportField *th;
2743     int i;
2744
2745     for(i=0;i<h->nb_transports;i++) {
2746         th = &h->transports[i];
2747         if (th->protocol == protocol)
2748             return th;
2749     }
2750     return NULL;
2751 }
2752
2753 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2754                            RTSPHeader *h)
2755 {
2756     FFStream *stream;
2757     int stream_index, port;
2758     char buf[1024];
2759     char path1[1024];
2760     const char *path;
2761     HTTPContext *rtp_c;
2762     RTSPTransportField *th;
2763     struct sockaddr_in dest_addr;
2764     RTSPActionServerSetup setup;
2765
2766     /* find which url is asked */
2767     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2768     path = path1;
2769     if (*path == '/')
2770         path++;
2771
2772     /* now check each stream */
2773     for(stream = first_stream; stream != NULL; stream = stream->next) {
2774         if (!stream->is_feed &&
2775             stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2776             /* accept aggregate filenames only if single stream */
2777             if (!strcmp(path, stream->filename)) {
2778                 if (stream->nb_streams != 1) {
2779                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2780                     return;
2781                 }
2782                 stream_index = 0;
2783                 goto found;
2784             }
2785
2786             for(stream_index = 0; stream_index < stream->nb_streams;
2787                 stream_index++) {
2788                 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2789                          stream->filename, stream_index);
2790                 if (!strcmp(path, buf))
2791                     goto found;
2792             }
2793         }
2794     }
2795     /* no stream found */
2796     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2797     return;
2798  found:
2799
2800     /* generate session id if needed */
2801     if (h->session_id[0] == '\0')
2802         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2803                  av_random(&random_state), av_random(&random_state));
2804
2805     /* find rtp session, and create it if none found */
2806     rtp_c = find_rtp_session(h->session_id);
2807     if (!rtp_c) {
2808         /* always prefer UDP */
2809         th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2810         if (!th) {
2811             th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2812             if (!th) {
2813                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2814                 return;
2815             }
2816         }
2817
2818         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2819                                    th->protocol);
2820         if (!rtp_c) {
2821             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2822             return;
2823         }
2824
2825         /* open input stream */
2826         if (open_input_stream(rtp_c, "") < 0) {
2827             rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2828             return;
2829         }
2830     }
2831
2832     /* test if stream is OK (test needed because several SETUP needs
2833        to be done for a given file) */
2834     if (rtp_c->stream != stream) {
2835         rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2836         return;
2837     }
2838
2839     /* test if stream is already set up */
2840     if (rtp_c->rtp_ctx[stream_index]) {
2841         rtsp_reply_error(c, RTSP_STATUS_STATE);
2842         return;
2843     }
2844
2845     /* check transport */
2846     th = find_transport(h, rtp_c->rtp_protocol);
2847     if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2848                 th->client_port_min <= 0)) {
2849         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2850         return;
2851     }
2852
2853     /* setup default options */
2854     setup.transport_option[0] = '\0';
2855     dest_addr = rtp_c->from_addr;
2856     dest_addr.sin_port = htons(th->client_port_min);
2857
2858     /* setup stream */
2859     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2860         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2861         return;
2862     }
2863
2864     /* now everything is OK, so we can send the connection parameters */
2865     rtsp_reply_header(c, RTSP_STATUS_OK);
2866     /* session ID */
2867     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2868
2869     switch(rtp_c->rtp_protocol) {
2870     case RTSP_PROTOCOL_RTP_UDP:
2871         port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2872         url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2873                     "client_port=%d-%d;server_port=%d-%d",
2874                     th->client_port_min, th->client_port_min + 1,
2875                     port, port + 1);
2876         break;
2877     case RTSP_PROTOCOL_RTP_TCP:
2878         url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2879                     stream_index * 2, stream_index * 2 + 1);
2880         break;
2881     default:
2882         break;
2883     }
2884     if (setup.transport_option[0] != '\0')
2885         url_fprintf(c->pb, ";%s", setup.transport_option);
2886     url_fprintf(c->pb, "\r\n");
2887
2888
2889     url_fprintf(c->pb, "\r\n");
2890 }
2891
2892
2893 /* find an rtp connection by using the session ID. Check consistency
2894    with filename */
2895 static HTTPContext *find_rtp_session_with_url(const char *url,
2896                                               const char *session_id)
2897 {
2898     HTTPContext *rtp_c;
2899     char path1[1024];
2900     const char *path;
2901     char buf[1024];
2902     int s;
2903
2904     rtp_c = find_rtp_session(session_id);
2905     if (!rtp_c)
2906         return NULL;
2907
2908     /* find which url is asked */
2909     url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2910     path = path1;
2911     if (*path == '/')
2912         path++;
2913     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2914     for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2915       snprintf(buf, sizeof(buf), "%s/streamid=%d",
2916         rtp_c->stream->filename, s);
2917       if(!strncmp(path, buf, sizeof(buf))) {
2918     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2919         return rtp_c;
2920       }
2921     }
2922     return NULL;
2923 }
2924
2925 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2926 {
2927     HTTPContext *rtp_c;
2928
2929     rtp_c = find_rtp_session_with_url(url, h->session_id);
2930     if (!rtp_c) {
2931         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2932         return;
2933     }
2934
2935     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2936         rtp_c->state != HTTPSTATE_WAIT_FEED &&
2937         rtp_c->state != HTTPSTATE_READY) {
2938         rtsp_reply_error(c, RTSP_STATUS_STATE);
2939         return;
2940     }
2941
2942 #if 0
2943     /* XXX: seek in stream */
2944     if (h->range_start != AV_NOPTS_VALUE) {
2945         printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2946         av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2947     }
2948 #endif
2949
2950     rtp_c->state = HTTPSTATE_SEND_DATA;
2951
2952     /* now everything is OK, so we can send the connection parameters */
2953     rtsp_reply_header(c, RTSP_STATUS_OK);
2954     /* session ID */
2955     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2956     url_fprintf(c->pb, "\r\n");
2957 }
2958
2959 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
2960 {
2961     HTTPContext *rtp_c;
2962
2963     rtp_c = find_rtp_session_with_url(url, h->session_id);
2964     if (!rtp_c) {
2965         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2966         return;
2967     }
2968
2969     if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2970         rtp_c->state != HTTPSTATE_WAIT_FEED) {
2971         rtsp_reply_error(c, RTSP_STATUS_STATE);
2972         return;
2973     }
2974
2975     rtp_c->state = HTTPSTATE_READY;
2976     rtp_c->first_pts = AV_NOPTS_VALUE;
2977     /* now everything is OK, so we can send the connection parameters */
2978     rtsp_reply_header(c, RTSP_STATUS_OK);
2979     /* session ID */
2980     url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2981     url_fprintf(c->pb, "\r\n");
2982 }
2983
2984 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
2985 {
2986     HTTPContext *rtp_c;
2987     char session_id[32];
2988
2989     rtp_c = find_rtp_session_with_url(url, h->session_id);
2990     if (!rtp_c) {
2991         rtsp_reply_error(c, RTSP_STATUS_SESSION);
2992         return;
2993     }
2994
2995     av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
2996
2997     /* abort the session */
2998     close_connection(rtp_c);
2999
3000     /* now everything is OK, so we can send the connection parameters */
3001     rtsp_reply_header(c, RTSP_STATUS_OK);
3002     /* session ID */
3003     url_fprintf(c->pb, "Session: %s\r\n", session_id);
3004     url_fprintf(c->pb, "\r\n");
3005 }
3006
3007
3008 /********************************************************************/
3009 /* RTP handling */
3010
3011 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3012                                        FFStream *stream, const char *session_id,
3013                                        enum RTSPProtocol rtp_protocol)
3014 {
3015     HTTPContext *c = NULL;
3016     const char *proto_str;
3017
3018     /* XXX: should output a warning page when coming
3019        close to the connection limit */
3020     if (nb_connections >= nb_max_connections)
3021         goto fail;
3022
3023     /* add a new connection */
3024     c = av_mallocz(sizeof(HTTPContext));
3025     if (!c)
3026         goto fail;
3027
3028     c->fd = -1;
3029     c->poll_entry = NULL;
3030     c->from_addr = *from_addr;
3031     c->buffer_size = IOBUFFER_INIT_SIZE;
3032     c->buffer = av_malloc(c->buffer_size);
3033     if (!c->buffer)
3034         goto fail;
3035     nb_connections++;
3036     c->stream = stream;
3037     av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3038     c->state = HTTPSTATE_READY;
3039     c->is_packetized = 1;
3040     c->rtp_protocol = rtp_protocol;
3041
3042     /* protocol is shown in statistics */
3043     switch(c->rtp_protocol) {
3044     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3045         proto_str = "MCAST";
3046         break;
3047     case RTSP_PROTOCOL_RTP_UDP:
3048         proto_str = "UDP";
3049         break;
3050     case RTSP_PROTOCOL_RTP_TCP:
3051         proto_str = "TCP";
3052         break;
3053     default:
3054         proto_str = "???";
3055         break;
3056     }
3057     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3058     av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3059
3060     current_bandwidth += stream->bandwidth;
3061
3062     c->next = first_http_ctx;
3063     first_http_ctx = c;
3064     return c;
3065
3066  fail:
3067     if (c) {
3068         av_free(c->buffer);
3069         av_free(c);
3070     }
3071     return NULL;
3072 }
3073
3074 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3075    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3076    used. */
3077 static int rtp_new_av_stream(HTTPContext *c,
3078                              int stream_index, struct sockaddr_in *dest_addr,
3079                              HTTPContext *rtsp_c)
3080 {
3081     AVFormatContext *ctx;
3082     AVStream *st;
3083     char *ipaddr;
3084     URLContext *h;
3085     uint8_t *dummy_buf;
3086     char buf2[32];
3087     int max_packet_size;
3088
3089     /* now we can open the relevant output stream */
3090     ctx = av_alloc_format_context();
3091     if (!ctx)
3092         return -1;
3093     ctx->oformat = guess_format("rtp", NULL, NULL);
3094
3095     st = av_mallocz(sizeof(AVStream));
3096     if (!st)
3097         goto fail;
3098     st->codec= avcodec_alloc_context();
3099     ctx->nb_streams = 1;
3100     ctx->streams[0] = st;
3101
3102     if (!c->stream->feed ||
3103         c->stream->feed == c->stream)
3104         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3105     else
3106         memcpy(st,
3107                c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3108                sizeof(AVStream));
3109     st->priv_data = NULL;
3110
3111     /* build destination RTP address */
3112     ipaddr = inet_ntoa(dest_addr->sin_addr);
3113
3114     switch(c->rtp_protocol) {
3115     case RTSP_PROTOCOL_RTP_UDP:
3116     case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3117         /* RTP/UDP case */
3118
3119         /* XXX: also pass as parameter to function ? */
3120         if (c->stream->is_multicast) {
3121             int ttl;
3122             ttl = c->stream->multicast_ttl;
3123             if (!ttl)
3124                 ttl = 16;
3125             snprintf(ctx->filename, sizeof(ctx->filename),
3126                      "rtp://%s:%d?multicast=1&ttl=%d",
3127                      ipaddr, ntohs(dest_addr->sin_port), ttl);
3128         } else {
3129             snprintf(ctx->filename, sizeof(ctx->filename),
3130                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3131         }
3132
3133         if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3134             goto fail;
3135         c->rtp_handles[stream_index] = h;
3136         max_packet_size = url_get_max_packet_size(h);
3137         break;
3138     case RTSP_PROTOCOL_RTP_TCP:
3139         /* RTP/TCP case */
3140         c->rtsp_c = rtsp_c;
3141         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3142         break;
3143     default:
3144         goto fail;
3145     }
3146
3147     http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3148              ipaddr, ntohs(dest_addr->sin_port),
3149              ctime1(buf2),
3150              c->stream->filename, stream_index, c->protocol);
3151
3152     /* normally, no packets should be output here, but the packet size may be checked */
3153     if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3154         /* XXX: close stream */
3155         goto fail;
3156     }
3157     av_set_parameters(ctx, NULL);
3158     if (av_write_header(ctx) < 0) {
3159     fail:
3160         if (h)
3161             url_close(h);
3162         av_free(ctx);
3163         return -1;
3164     }
3165     url_close_dyn_buf(ctx->pb, &dummy_buf);
3166     av_free(dummy_buf);
3167
3168     c->rtp_ctx[stream_index] = ctx;
3169     return 0;
3170 }
3171
3172 /********************************************************************/
3173 /* ffserver initialization */
3174
3175 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3176 {
3177     AVStream *fst;
3178
3179     fst = av_mallocz(sizeof(AVStream));
3180     if (!fst)
3181         return NULL;
3182     fst->codec= avcodec_alloc_context();
3183     fst->priv_data = av_mallocz(sizeof(FeedData));
3184     memcpy(fst->codec, codec, sizeof(AVCodecContext));
3185     fst->codec->coded_frame = &dummy_frame;
3186     fst->index = stream->nb_streams;
3187     av_set_pts_info(fst, 33, 1, 90000);
3188     stream->streams[stream->nb_streams++] = fst;
3189     return fst;
3190 }
3191
3192 /* return the stream number in the feed */
3193 static int add_av_stream(FFStream *feed, AVStream *st)
3194 {
3195     AVStream *fst;
3196     AVCodecContext *av, *av1;
3197     int i;
3198
3199     av = st->codec;
3200     for(i=0;i<feed->nb_streams;i++) {
3201         st = feed->streams[i];
3202         av1 = st->codec;
3203         if (av1->codec_id == av->codec_id &&
3204             av1->codec_type == av->codec_type &&
3205             av1->bit_rate == av->bit_rate) {
3206
3207             switch(av->codec_type) {
3208             case CODEC_TYPE_AUDIO:
3209                 if (av1->channels == av->channels &&
3210                     av1->sample_rate == av->sample_rate)
3211                     goto found;
3212                 break;
3213             case CODEC_TYPE_VIDEO:
3214                 if (av1->width == av->width &&
3215                     av1->height == av->height &&
3216                     av1->time_base.den == av->time_base.den &&
3217                     av1->time_base.num == av->time_base.num &&
3218                     av1->gop_size == av->gop_size)
3219                     goto found;
3220                 break;
3221             default:
3222                 abort();
3223             }
3224         }
3225     }
3226
3227     fst = add_av_stream1(feed, av);
3228     if (!fst)
3229         return -1;
3230     return feed->nb_streams - 1;
3231  found:
3232     return i;
3233 }
3234
3235 static void remove_stream(FFStream *stream)
3236 {
3237     FFStream **ps;
3238     ps = &first_stream;
3239     while (*ps != NULL) {
3240         if (*ps == stream)
3241             *ps = (*ps)->next;
3242         else
3243             ps = &(*ps)->next;
3244     }
3245 }
3246
3247 /* specific mpeg4 handling : we extract the raw parameters */
3248 static void extract_mpeg4_header(AVFormatContext *infile)
3249 {
3250     int mpeg4_count, i, size;
3251     AVPacket pkt;
3252     AVStream *st;
3253     const uint8_t *p;
3254
3255     mpeg4_count = 0;
3256     for(i=0;i<infile->nb_streams;i++) {
3257         st = infile->streams[i];
3258         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3259             st->codec->extradata_size == 0) {
3260             mpeg4_count++;
3261         }
3262     }
3263     if (!mpeg4_count)
3264         return;
3265
3266     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3267     while (mpeg4_count > 0) {
3268         if (av_read_packet(infile, &pkt) < 0)
3269             break;
3270         st = infile->streams[pkt.stream_index];
3271         if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3272             st->codec->extradata_size == 0) {
3273             av_freep(&st->codec->extradata);
3274             /* fill extradata with the header */
3275             /* XXX: we make hard suppositions here ! */
3276             p = pkt.data;
3277             while (p < pkt.data + pkt.size - 4) {
3278                 /* stop when vop header is found */
3279                 if (p[0] == 0x00 && p[1] == 0x00 &&
3280                     p[2] == 0x01 && p[3] == 0xb6) {
3281                     size = p - pkt.data;
3282                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3283                     st->codec->extradata = av_malloc(size);
3284                     st->codec->extradata_size = size;
3285                     memcpy(st->codec->extradata, pkt.data, size);
3286                     break;
3287                 }
3288                 p++;
3289             }
3290             mpeg4_count--;
3291         }
3292         av_free_packet(&pkt);
3293     }
3294 }
3295
3296 /* compute the needed AVStream for each file */
3297 static void build_file_streams(void)
3298 {
3299     FFStream *stream, *stream_next;
3300     AVFormatContext *infile;
3301     int i;
3302
3303     /* gather all streams */
3304     for(stream = first_stream; stream != NULL; stream = stream_next) {
3305         stream_next = stream->next;
3306         if (stream->stream_type == STREAM_TYPE_LIVE &&
3307             !stream->feed) {
3308             /* the stream comes from a file */
3309             /* try to open the file */
3310             /* open stream */
3311             stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3312             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3313                 /* specific case : if transport stream output to RTP,
3314                    we use a raw transport stream reader */
3315                 stream->ap_in->mpeg2ts_raw = 1;
3316                 stream->ap_in->mpeg2ts_compute_pcr = 1;
3317             }
3318
3319             if (av_open_input_file(&infile, stream->feed_filename,
3320                                    stream->ifmt, 0, stream->ap_in) < 0) {
3321                 http_log("%s not found", stream->feed_filename);
3322                 /* remove stream (no need to spend more time on it) */
3323             fail:
3324                 remove_stream(stream);
3325             } else {
3326                 /* find all the AVStreams inside and reference them in
3327                    'stream' */
3328                 if (av_find_stream_info(infile) < 0) {
3329                     http_log("Could not find codec parameters from '%s'",
3330                              stream->feed_filename);
3331                     av_close_input_file(infile);
3332                     goto fail;
3333                 }
3334                 extract_mpeg4_header(infile);
3335
3336                 for(i=0;i<infile->nb_streams;i++)
3337                     add_av_stream1(stream, infile->streams[i]->codec);
3338
3339                 av_close_input_file(infile);
3340             }
3341         }
3342     }
3343 }
3344
3345 /* compute the needed AVStream for each feed */
3346 static void build_feed_streams(void)
3347 {
3348     FFStream *stream, *feed;
3349     int i;
3350
3351     /* gather all streams */
3352     for(stream = first_stream; stream != NULL; stream = stream->next) {
3353         feed = stream->feed;
3354         if (feed) {
3355             if (!stream->is_feed) {
3356                 /* we handle a stream coming from a feed */
3357                 for(i=0;i<stream->nb_streams;i++)
3358                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3359             }
3360         }
3361     }
3362
3363     /* gather all streams */
3364     for(stream = first_stream; stream != NULL; stream = stream->next) {
3365         feed = stream->feed;
3366         if (feed) {
3367             if (stream->is_feed) {
3368                 for(i=0;i<stream->nb_streams;i++)
3369                     stream->feed_streams[i] = i;
3370             }
3371         }
3372     }
3373
3374     /* create feed files if needed */
3375     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3376         int fd;
3377
3378         if (url_exist(feed->feed_filename)) {
3379             /* See if it matches */
3380             AVFormatContext *s;
3381             int matches = 0;
3382
3383             if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3384                 /* Now see if it matches */
3385                 if (s->nb_streams == feed->nb_streams) {
3386                     matches = 1;
3387                     for(i=0;i<s->nb_streams;i++) {
3388                         AVStream *sf, *ss;
3389                         sf = feed->streams[i];
3390                         ss = s->streams[i];
3391
3392                         if (sf->index != ss->index ||
3393                             sf->id != ss->id) {
3394                             printf("Index & Id do not match for stream %d (%s)\n",
3395                                    i, feed->feed_filename);
3396                             matches = 0;
3397                         } else {
3398                             AVCodecContext *ccf, *ccs;
3399
3400                             ccf = sf->codec;
3401                             ccs = ss->codec;
3402 #define CHECK_CODEC(x)  (ccf->x != ccs->x)
3403
3404                             if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3405                                 printf("Codecs do not match for stream %d\n", i);
3406                                 matches = 0;
3407                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3408                                 printf("Codec bitrates do not match for stream %d\n", i);
3409                                 matches = 0;
3410                             } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3411                                 if (CHECK_CODEC(time_base.den) ||
3412                                     CHECK_CODEC(time_base.num) ||
3413                                     CHECK_CODEC(width) ||
3414                                     CHECK_CODEC(height)) {
3415                                     printf("Codec width, height and framerate do not match for stream %d\n", i);
3416                                     matches = 0;
3417                                 }
3418                             } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3419                                 if (CHECK_CODEC(sample_rate) ||
3420                                     CHECK_CODEC(channels) ||
3421                                     CHECK_CODEC(frame_size)) {
3422                                     printf("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3423                                     matches = 0;
3424                                 }
3425                             } else {
3426                                 printf("Unknown codec type\n");
3427                                 matches = 0;
3428                             }
3429                         }
3430                         if (!matches)
3431                             break;
3432                     }
3433                 } else
3434                     printf("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3435                         feed->feed_filename, s->nb_streams, feed->nb_streams);
3436
3437                 av_close_input_file(s);
3438             } else
3439                 printf("Deleting feed file '%s' as it appears to be corrupt\n",
3440                         feed->feed_filename);
3441
3442             if (!matches) {
3443                 if (feed->readonly) {
3444                     printf("Unable to delete feed file '%s' as it is marked readonly\n",
3445                         feed->feed_filename);
3446                     exit(1);
3447                 }
3448                 unlink(feed->feed_filename);
3449             }
3450         }
3451         if (!url_exist(feed->feed_filename)) {
3452             AVFormatContext s1, *s = &s1;
3453
3454             if (feed->readonly) {
3455                 printf("Unable to create feed file '%s' as it is marked readonly\n",
3456                     feed->feed_filename);
3457                 exit(1);
3458             }
3459
3460             /* only write the header of the ffm file */
3461             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3462                 fprintf(stderr, "Could not open output feed file '%s'\n",
3463                         feed->feed_filename);
3464                 exit(1);
3465             }
3466             s->oformat = feed->fmt;
3467             s->nb_streams = feed->nb_streams;
3468             for(i=0;i<s->nb_streams;i++) {
3469                 AVStream *st;
3470                 st = feed->streams[i];
3471                 s->streams[i] = st;
3472             }
3473             av_set_parameters(s, NULL);
3474             if (av_write_header(s) < 0) {
3475                 fprintf(stderr, "Container doesn't supports the required parameters\n");
3476                 exit(1);
3477             }
3478             /* XXX: need better api */
3479             av_freep(&s->priv_data);
3480             url_fclose(s->pb);
3481         }
3482         /* get feed size and write index */
3483         fd = open(feed->feed_filename, O_RDONLY);
3484         if (fd < 0) {
3485             fprintf(stderr, "Could not open output feed file '%s'\n",
3486                     feed->feed_filename);
3487             exit(1);
3488         }
3489
3490         feed->feed_write_index = ffm_read_write_index(fd);
3491         feed->feed_size = lseek(fd, 0, SEEK_END);
3492         /* ensure that we do not wrap before the end of file */
3493         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3494             feed->feed_max_size = feed->feed_size;
3495
3496         close(fd);
3497     }
3498 }
3499
3500 /* compute the bandwidth used by each stream */
3501 static void compute_bandwidth(void)
3502 {
3503     int bandwidth, i;
3504     FFStream *stream;
3505
3506     for(stream = first_stream; stream != NULL; stream = stream->next) {
3507         bandwidth = 0;
3508         for(i=0;i<stream->nb_streams;i++) {
3509             AVStream *st = stream->streams[i];
3510             switch(st->codec->codec_type) {
3511             case CODEC_TYPE_AUDIO:
3512             case CODEC_TYPE_VIDEO:
3513                 bandwidth += st->codec->bit_rate;
3514                 break;
3515             default:
3516                 break;
3517             }
3518         }
3519         stream->bandwidth = (bandwidth + 999) / 1000;
3520     }
3521 }
3522
3523 static void get_arg(char *buf, int buf_size, const char **pp)
3524 {
3525     const char *p;
3526     char *q;
3527     int quote;
3528
3529     p = *pp;
3530     while (isspace(*p)) p++;
3531     q = buf;
3532     quote = 0;
3533     if (*p == '\"' || *p == '\'')
3534         quote = *p++;
3535     for(;;) {
3536         if (quote) {
3537             if (*p == quote)
3538                 break;
3539         } else {
3540             if (isspace(*p))
3541                 break;
3542         }
3543         if (*p == '\0')
3544             break;
3545         if ((q - buf) < buf_size - 1)
3546             *q++ = *p;
3547         p++;
3548     }
3549     *q = '\0';
3550     if (quote && *p == quote)
3551         p++;
3552     *pp = p;
3553 }
3554
3555 /* add a codec and set the default parameters */
3556 static void add_codec(FFStream *stream, AVCodecContext *av)
3557 {
3558     AVStream *st;
3559
3560     /* compute default parameters */
3561     switch(av->codec_type) {
3562     case CODEC_TYPE_AUDIO:
3563         if (av->bit_rate == 0)
3564             av->bit_rate = 64000;
3565         if (av->sample_rate == 0)
3566             av->sample_rate = 22050;
3567         if (av->channels == 0)
3568             av->channels = 1;
3569         break;
3570     case CODEC_TYPE_VIDEO:
3571         if (av->bit_rate == 0)
3572             av->bit_rate = 64000;
3573         if (av->time_base.num == 0){
3574             av->time_base.den = 5;
3575             av->time_base.num = 1;
3576         }
3577         if (av->width == 0 || av->height == 0) {
3578             av->width = 160;
3579             av->height = 128;
3580         }
3581         /* Bitrate tolerance is less for streaming */
3582         if (av->bit_rate_tolerance == 0)
3583             av->bit_rate_tolerance = av->bit_rate / 4;
3584         if (av->qmin == 0)
3585             av->qmin = 3;
3586         if (av->qmax == 0)
3587             av->qmax = 31;
3588         if (av->max_qdiff == 0)
3589             av->max_qdiff = 3;
3590         av->qcompress = 0.5;
3591         av->qblur = 0.5;
3592
3593         if (!av->nsse_weight)
3594             av->nsse_weight = 8;
3595
3596         av->frame_skip_cmp = FF_CMP_DCTMAX;
3597         av->me_method = ME_EPZS;
3598         av->rc_buffer_aggressivity = 1.0;
3599
3600         if (!av->rc_eq)
3601             av->rc_eq = "tex^qComp";
3602         if (!av->i_quant_factor)
3603             av->i_quant_factor = -0.8;
3604         if (!av->b_quant_factor)
3605             av->b_quant_factor = 1.25;
3606         if (!av->b_quant_offset)
3607             av->b_quant_offset = 1.25;
3608         if (!av->rc_max_rate)
3609             av->rc_max_rate = av->bit_rate * 2;
3610
3611         if (av->rc_max_rate && !av->rc_buffer_size) {
3612             av->rc_buffer_size = av->rc_max_rate;
3613         }
3614
3615
3616         break;
3617     default:
3618         abort();
3619     }
3620
3621     st = av_mallocz(sizeof(AVStream));
3622     if (!st)
3623         return;
3624     st->codec = avcodec_alloc_context();
3625     stream->streams[stream->nb_streams++] = st;
3626     memcpy(st->codec, av, sizeof(AVCodecContext));
3627 }
3628
3629 static int opt_audio_codec(const char *arg)
3630 {
3631     AVCodec *p;
3632
3633     p = first_avcodec;
3634     while (p) {
3635         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
3636             break;
3637         p = p->next;
3638     }
3639     if (p == NULL)
3640         return CODEC_ID_NONE;
3641
3642     return p->id;
3643 }
3644
3645 static int opt_video_codec(const char *arg)
3646 {
3647     AVCodec *p;
3648
3649     p = first_avcodec;
3650     while (p) {
3651         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
3652             break;
3653         p = p->next;
3654     }
3655     if (p == NULL)
3656         return CODEC_ID_NONE;
3657
3658     return p->id;
3659 }
3660
3661 /* simplistic plugin support */
3662
3663 #ifdef HAVE_DLOPEN
3664 static void load_module(const char *filename)
3665 {
3666     void *dll;
3667     void (*init_func)(void);
3668     dll = dlopen(filename, RTLD_NOW);
3669     if (!dll) {
3670         fprintf(stderr, "Could not load module '%s' - %s\n",
3671                 filename, dlerror());
3672         return;
3673     }
3674
3675     init_func = dlsym(dll, "ffserver_module_init");
3676     if (!init_func) {
3677         fprintf(stderr,
3678                 "%s: init function 'ffserver_module_init()' not found\n",
3679                 filename);
3680         dlclose(dll);
3681     }
3682
3683     init_func();
3684 }
3685 #endif
3686
3687 static int parse_ffconfig(const char *filename)
3688 {
3689     FILE *f;
3690     char line[1024];
3691     char cmd[64];
3692     char arg[1024];
3693     const char *p;
3694     int val, errors, line_num;
3695     FFStream **last_stream, *stream, *redirect;
3696     FFStream **last_feed, *feed;
3697     AVCodecContext audio_enc, video_enc;
3698     int audio_id, video_id;
3699
3700     f = fopen(filename, "r");
3701     if (!f) {
3702         perror(filename);
3703         return -1;
3704     }
3705
3706     errors = 0;
3707     line_num = 0;
3708     first_stream = NULL;
3709     last_stream = &first_stream;
3710     first_feed = NULL;
3711     last_feed = &first_feed;
3712     stream = NULL;
3713     feed = NULL;
3714     redirect = NULL;
3715     audio_id = CODEC_ID_NONE;
3716     video_id = CODEC_ID_NONE;
3717     for(;;) {
3718         if (fgets(line, sizeof(line), f) == NULL)
3719             break;
3720         line_num++;
3721         p = line;
3722         while (isspace(*p))
3723             p++;
3724         if (*p == '\0' || *p == '#')
3725             continue;
3726
3727         get_arg(cmd, sizeof(cmd), &p);
3728
3729         if (!strcasecmp(cmd, "Port")) {
3730             get_arg(arg, sizeof(arg), &p);
3731             val = atoi(arg);
3732             if (val < 1 || val > 65536) {
3733                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3734                         filename, line_num, arg);
3735                 errors++;
3736             }
3737             my_http_addr.sin_port = htons(val);
3738         } else if (!strcasecmp(cmd, "BindAddress")) {
3739             get_arg(arg, sizeof(arg), &p);
3740             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3741                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3742                         filename, line_num, arg);
3743                 errors++;
3744             }
3745         } else if (!strcasecmp(cmd, "NoDaemon")) {
3746             ffserver_daemon = 0;
3747         } else if (!strcasecmp(cmd, "RTSPPort")) {
3748             get_arg(arg, sizeof(arg), &p);
3749             val = atoi(arg);
3750             if (val < 1 || val > 65536) {
3751                 fprintf(stderr, "%s:%d: Invalid port: %s\n",
3752                         filename, line_num, arg);
3753                 errors++;
3754             }
3755             my_rtsp_addr.sin_port = htons(atoi(arg));
3756         } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3757             get_arg(arg, sizeof(arg), &p);
3758             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3759                 fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3760                         filename, line_num, arg);
3761                 errors++;
3762             }
3763         } else if (!strcasecmp(cmd, "MaxClients")) {
3764             get_arg(arg, sizeof(arg), &p);
3765             val = atoi(arg);
3766             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
3767                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3768                         filename, line_num, arg);
3769                 errors++;
3770             } else {
3771                 nb_max_connections = val;
3772             }
3773         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3774             get_arg(arg, sizeof(arg), &p);
3775             val = atoi(arg);
3776             if (val < 10 || val > 100000) {
3777                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3778                         filename, line_num, arg);
3779                 errors++;
3780             } else
3781                 max_bandwidth = val;
3782         } else if (!strcasecmp(cmd, "CustomLog")) {
3783             get_arg(logfilename, sizeof(logfilename), &p);
3784         } else if (!strcasecmp(cmd, "<Feed")) {
3785             /*********************************************/
3786             /* Feed related options */
3787             char *q;
3788             if (stream || feed) {
3789                 fprintf(stderr, "%s:%d: Already in a tag\n",
3790                         filename, line_num);
3791             } else {
3792                 feed = av_mallocz(sizeof(FFStream));
3793                 /* add in stream list */
3794                 *last_stream = feed;
3795                 last_stream = &feed->next;
3796                 /* add in feed list */
3797                 *last_feed = feed;
3798                 last_feed = &feed->next_feed;
3799
3800                 get_arg(feed->filename, sizeof(feed->filename), &p);
3801                 q = strrchr(feed->filename, '>');
3802                 if (*q)
3803                     *q = '\0';
3804                 feed->fmt = guess_format("ffm", NULL, NULL);
3805                 /* defaut feed file */
3806                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3807                          "/tmp/%s.ffm", feed->filename);
3808                 feed->feed_max_size = 5 * 1024 * 1024;
3809                 feed->is_feed = 1;
3810                 feed->feed = feed; /* self feeding :-) */
3811             }
3812         } else if (!strcasecmp(cmd, "Launch")) {
3813             if (feed) {
3814                 int i;
3815
3816                 feed->child_argv = av_mallocz(64 * sizeof(char *));
3817
3818                 for (i = 0; i < 62; i++) {
3819                     get_arg(arg, sizeof(arg), &p);
3820                     if (!arg[0])
3821                         break;
3822
3823                     feed->child_argv[i] = av_strdup(arg);
3824                 }
3825
3826                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
3827
3828                 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3829                     "http://%s:%d/%s",
3830                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3831                     inet_ntoa(my_http_addr.sin_addr),
3832                     ntohs(my_http_addr.sin_port), feed->filename);
3833
3834                 if (ffserver_debug)
3835                 {
3836                     int j;
3837                     fprintf(stdout, "Launch commandline: ");
3838                     for (j = 0; j <= i; j++)
3839                         fprintf(stdout, "%s ", feed->child_argv[j]);
3840                     fprintf(stdout, "\n");
3841                 }
3842             }
3843         } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3844             if (feed) {
3845                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3846                 feed->readonly = 1;
3847             } else if (stream) {
3848                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3849             }
3850         } else if (!strcasecmp(cmd, "File")) {
3851             if (feed) {
3852                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3853             } else if (stream)
3854                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3855         } else if (!strcasecmp(cmd, "FileMaxSize")) {
3856             if (feed) {
3857                 const char *p1;
3858                 double fsize;
3859
3860                 get_arg(arg, sizeof(arg), &p);
3861                 p1 = arg;
3862                 fsize = strtod(p1, (char **)&p1);
3863                 switch(toupper(*p1)) {
3864                 case 'K':
3865                     fsize *= 1024;
3866                     break;
3867                 case 'M':
3868                     fsize *= 1024 * 1024;
3869                     break;
3870                 case 'G':
3871                     fsize *= 1024 * 1024 * 1024;
3872                     break;
3873                 }
3874                 feed->feed_max_size = (int64_t)fsize;
3875             }
3876         } else if (!strcasecmp(cmd, "</Feed>")) {
3877             if (!feed) {
3878                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3879                         filename, line_num);
3880                 errors++;
3881             }
3882             feed = NULL;
3883         } else if (!strcasecmp(cmd, "<Stream")) {
3884             /*********************************************/
3885             /* Stream related options */
3886             char *q;
3887             if (stream || feed) {
3888                 fprintf(stderr, "%s:%d: Already in a tag\n",
3889                         filename, line_num);
3890             } else {
3891                 stream = av_mallocz(sizeof(FFStream));
3892                 *last_stream = stream;
3893                 last_stream = &stream->next;
3894
3895                 get_arg(stream->filename, sizeof(stream->filename), &p);
3896                 q = strrchr(stream->filename, '>');
3897                 if (*q)
3898                     *q = '\0';
3899                 stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3900                 memset(&audio_enc, 0, sizeof(AVCodecContext));
3901                 memset(&video_enc, 0, sizeof(AVCodecContext));
3902                 audio_id = CODEC_ID_NONE;
3903                 video_id = CODEC_ID_NONE;
3904                 if (stream->fmt) {
3905                     audio_id = stream->fmt->audio_codec;
3906                     video_id = stream->fmt->video_codec;
3907                 }
3908             }
3909         } else if (!strcasecmp(cmd, "Feed")) {
3910             get_arg(arg, sizeof(arg), &p);
3911             if (stream) {
3912                 FFStream *sfeed;
3913
3914                 sfeed = first_feed;
3915                 while (sfeed != NULL) {
3916                     if (!strcmp(sfeed->filename, arg))
3917                         break;
3918                     sfeed = sfeed->next_feed;
3919                 }
3920                 if (!sfeed)
3921                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
3922                             filename, line_num, arg);
3923                 else
3924                     stream->feed = sfeed;
3925             }
3926         } else if (!strcasecmp(cmd, "Format")) {
3927             get_arg(arg, sizeof(arg), &p);
3928             if (!strcmp(arg, "status")) {
3929                 stream->stream_type = STREAM_TYPE_STATUS;
3930                 stream->fmt = NULL;
3931             } else {
3932                 stream->stream_type = STREAM_TYPE_LIVE;
3933                 /* jpeg cannot be used here, so use single frame jpeg */
3934                 if (!strcmp(arg, "jpeg"))
3935                     strcpy(arg, "mjpeg");
3936                 stream->fmt = guess_stream_format(arg, NULL, NULL);
3937                 if (!stream->fmt) {
3938                     fprintf(stderr, "%s:%d: Unknown Format: %s\n",
3939                             filename, line_num, arg);
3940                     errors++;
3941                 }
3942             }
3943             if (stream->fmt) {
3944                 audio_id = stream->fmt->audio_codec;
3945                 video_id = stream->fmt->video_codec;
3946             }
3947         } else if (!strcasecmp(cmd, "InputFormat")) {
3948             get_arg(arg, sizeof(arg), &p);
3949             stream->ifmt = av_find_input_format(arg);
3950             if (!stream->ifmt) {
3951                 fprintf(stderr, "%s:%d: Unknown input format: %s\n",
3952                         filename, line_num, arg);
3953             }
3954         } else if (!strcasecmp(cmd, "FaviconURL")) {
3955             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
3956                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3957             } else {
3958                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
3959                             filename, line_num);
3960                 errors++;
3961             }
3962         } else if (!strcasecmp(cmd, "Author")) {
3963             if (stream)
3964                 get_arg(stream->author, sizeof(stream->author), &p);
3965         } else if (!strcasecmp(cmd, "Comment")) {
3966             if (stream)
3967                 get_arg(stream->comment, sizeof(stream->comment), &p);
3968         } else if (!strcasecmp(cmd, "Copyright")) {
3969             if (stream)
3970                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
3971         } else if (!strcasecmp(cmd, "Title")) {
3972             if (stream)
3973                 get_arg(stream->title, sizeof(stream->title), &p);
3974         } else if (!strcasecmp(cmd, "Preroll")) {
3975             get_arg(arg, sizeof(arg), &p);
3976             if (stream)
3977                 stream->prebuffer = atof(arg) * 1000;
3978         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
3979             if (stream)
3980                 stream->send_on_key = 1;
3981         } else if (!strcasecmp(cmd, "AudioCodec")) {
3982             get_arg(arg, sizeof(arg), &p);
3983             audio_id = opt_audio_codec(arg);
3984             if (audio_id == CODEC_ID_NONE) {
3985                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
3986                         filename, line_num, arg);
3987                 errors++;
3988             }
3989         } else if (!strcasecmp(cmd, "VideoCodec")) {
3990             get_arg(arg, sizeof(arg), &p);
3991             video_id = opt_video_codec(arg);
3992             if (video_id == CODEC_ID_NONE) {
3993                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
3994                         filename, line_num, arg);
3995                 errors++;
3996             }
3997         } else if (!strcasecmp(cmd, "MaxTime")) {
3998             get_arg(arg, sizeof(arg), &p);
3999             if (stream)
4000                 stream->max_time = atof(arg) * 1000;
4001         } else if (!strcasecmp(cmd, "AudioBitRate")) {
4002             get_arg(arg, sizeof(arg), &p);
4003             if (stream)
4004                 audio_enc.bit_rate = atoi(arg) * 1000;
4005         } else if (!strcasecmp(cmd, "AudioChannels")) {
4006             get_arg(arg, sizeof(arg), &p);
4007             if (stream)
4008                 audio_enc.channels = atoi(arg);
4009         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4010             get_arg(arg, sizeof(arg), &p);
4011             if (stream)
4012                 audio_enc.sample_rate = atoi(arg);
4013         } else if (!strcasecmp(cmd, "AudioQuality")) {
4014             get_arg(arg, sizeof(arg), &p);
4015             if (stream) {
4016 //                audio_enc.quality = atof(arg) * 1000;
4017             }
4018         } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4019             if (stream) {
4020                 int minrate, maxrate;
4021
4022                 get_arg(arg, sizeof(arg), &p);
4023
4024                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4025                     video_enc.rc_min_rate = minrate * 1000;
4026                     video_enc.rc_max_rate = maxrate * 1000;
4027                 } else {
4028                     fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4029                             filename, line_num, arg);
4030                     errors++;
4031                 }
4032             }
4033         } else if (!strcasecmp(cmd, "Debug")) {
4034             if (stream) {
4035                 get_arg(arg, sizeof(arg), &p);
4036                 video_enc.debug = strtol(arg,0,0);
4037             }
4038         } else if (!strcasecmp(cmd, "Strict")) {
4039             if (stream) {
4040                 get_arg(arg, sizeof(arg), &p);
4041                 video_enc.strict_std_compliance = atoi(arg);
4042             }
4043         } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4044             if (stream) {
4045                 get_arg(arg, sizeof(arg), &p);
4046                 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4047             }
4048         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4049             if (stream) {
4050                 get_arg(arg, sizeof(arg), &p);
4051                 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4052             }
4053         } else if (!strcasecmp(cmd, "VideoBitRate")) {
4054             get_arg(arg, sizeof(arg), &p);
4055             if (stream) {
4056                 video_enc.bit_rate = atoi(arg) * 1000;
4057             }
4058         } else if (!strcasecmp(cmd, "VideoSize")) {
4059             get_arg(arg, sizeof(arg), &p);
4060             if (stream) {
4061                 av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4062                 if ((video_enc.width % 16) != 0 ||
4063                     (video_enc.height % 16) != 0) {
4064                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4065                             filename, line_num);
4066                     errors++;
4067                 }
4068             }
4069         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4070             get_arg(arg, sizeof(arg), &p);
4071             if (stream) {
4072                 video_enc.time_base.num= DEFAULT_FRAME_RATE_BASE;
4073                 video_enc.time_base.den = (int)(strtod(arg, NULL) * video_enc.time_base.num);
4074             }
4075         } else if (!strcasecmp(cmd, "VideoGopSize")) {
4076             get_arg(arg, sizeof(arg), &p);
4077             if (stream)
4078                 video_enc.gop_size = atoi(arg);
4079         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4080             if (stream)
4081                 video_enc.gop_size = 1;
4082         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4083             if (stream)
4084                 video_enc.mb_decision = FF_MB_DECISION_BITS;
4085         } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4086             if (stream) {
4087                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4088                 video_enc.flags |= CODEC_FLAG_4MV;
4089             }
4090         } else if (!strcasecmp(cmd, "VideoTag")) {
4091             get_arg(arg, sizeof(arg), &p);
4092             if ((strlen(arg) == 4) && stream)
4093                 video_enc.codec_tag = ff_get_fourcc(arg);
4094         } else if (!strcasecmp(cmd, "BitExact")) {
4095             if (stream)
4096                 video_enc.flags |= CODEC_FLAG_BITEXACT;
4097         } else if (!strcasecmp(cmd, "DctFastint")) {
4098             if (stream)
4099                 video_enc.dct_algo  = FF_DCT_FASTINT;
4100         } else if (!strcasecmp(cmd, "IdctSimple")) {
4101             if (stream)
4102                 video_enc.idct_algo = FF_IDCT_SIMPLE;
4103         } else if (!strcasecmp(cmd, "Qscale")) {
4104             get_arg(arg, sizeof(arg), &p);
4105             if (stream) {
4106                 video_enc.flags |= CODEC_FLAG_QSCALE;
4107                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4108             }
4109         } else if (!strcasecmp(cmd, "VideoQDiff")) {
4110             get_arg(arg, sizeof(arg), &p);
4111             if (stream) {
4112                 video_enc.max_qdiff = atoi(arg);
4113                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4114                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4115                             filename, line_num);
4116                     errors++;
4117                 }
4118             }
4119         } else if (!strcasecmp(cmd, "VideoQMax")) {
4120             get_arg(arg, sizeof(arg), &p);
4121             if (stream) {
4122                 video_enc.qmax = atoi(arg);
4123                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4124                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4125                             filename, line_num);
4126                     errors++;
4127                 }
4128             }
4129         } else if (!strcasecmp(cmd, "VideoQMin")) {
4130             get_arg(arg, sizeof(arg), &p);
4131             if (stream) {
4132                 video_enc.qmin = atoi(arg);
4133                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4134                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4135                             filename, line_num);
4136                     errors++;
4137                 }
4138             }
4139         } else if (!strcasecmp(cmd, "LumaElim")) {
4140             get_arg(arg, sizeof(arg), &p);
4141             if (stream)
4142                 video_enc.luma_elim_threshold = atoi(arg);
4143         } else if (!strcasecmp(cmd, "ChromaElim")) {
4144             get_arg(arg, sizeof(arg), &p);
4145             if (stream)
4146                 video_enc.chroma_elim_threshold = atoi(arg);
4147         } else if (!strcasecmp(cmd, "LumiMask")) {
4148             get_arg(arg, sizeof(arg), &p);
4149             if (stream)
4150                 video_enc.lumi_masking = atof(arg);
4151         } else if (!strcasecmp(cmd, "DarkMask")) {
4152             get_arg(arg, sizeof(arg), &p);
4153             if (stream)
4154                 video_enc.dark_masking = atof(arg);
4155         } else if (!strcasecmp(cmd, "NoVideo")) {
4156             video_id = CODEC_ID_NONE;
4157         } else if (!strcasecmp(cmd, "NoAudio")) {
4158             audio_id = CODEC_ID_NONE;
4159         } else if (!strcasecmp(cmd, "ACL")) {
4160             IPAddressACL acl;
4161
4162             get_arg(arg, sizeof(arg), &p);
4163             if (strcasecmp(arg, "allow") == 0)
4164                 acl.action = IP_ALLOW;
4165             else if (strcasecmp(arg, "deny") == 0)
4166                 acl.action = IP_DENY;
4167             else {
4168                 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4169                         filename, line_num, arg);
4170                 errors++;
4171             }
4172
4173             get_arg(arg, sizeof(arg), &p);
4174
4175             if (resolve_host(&acl.first, arg) != 0) {
4176                 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4177                         filename, line_num, arg);
4178                 errors++;
4179             } else
4180                 acl.last = acl.first;
4181
4182             get_arg(arg, sizeof(arg), &p);
4183
4184             if (arg[0]) {
4185                 if (resolve_host(&acl.last, arg) != 0) {
4186                     fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4187                             filename, line_num, arg);
4188                     errors++;
4189                 }
4190             }
4191
4192             if (!errors) {
4193                 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4194                 IPAddressACL **naclp = 0;
4195
4196                 acl.next = 0;
4197                 *nacl = acl;
4198
4199                 if (stream)
4200                     naclp = &stream->acl;
4201                 else if (feed)
4202                     naclp = &feed->acl;
4203                 else {
4204                     fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4205                             filename, line_num);
4206                     errors++;
4207                 }
4208
4209                 if (naclp) {
4210                     while (*naclp)
4211                         naclp = &(*naclp)->next;
4212
4213                     *naclp = nacl;
4214                 }
4215             }
4216         } else if (!strcasecmp(cmd, "RTSPOption")) {
4217             get_arg(arg, sizeof(arg), &p);
4218             if (stream) {
4219                 av_freep(&stream->rtsp_option);
4220                 stream->rtsp_option = av_strdup(arg);
4221             }
4222         } else if (!strcasecmp(cmd, "MulticastAddress")) {
4223             get_arg(arg, sizeof(arg), &p);
4224             if (stream) {
4225                 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4226                     fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4227                             filename, line_num, arg);
4228                     errors++;
4229                 }
4230                 stream->is_multicast = 1;
4231                 stream->loop = 1; /* default is looping */
4232             }
4233         } else if (!strcasecmp(cmd, "MulticastPort")) {
4234             get_arg(arg, sizeof(arg), &p);
4235             if (stream)
4236                 stream->multicast_port = atoi(arg);
4237         } else if (!strcasecmp(cmd, "MulticastTTL")) {
4238             get_arg(arg, sizeof(arg), &p);
4239             if (stream)
4240                 stream->multicast_ttl = atoi(arg);
4241         } else if (!strcasecmp(cmd, "NoLoop")) {
4242             if (stream)
4243                 stream->loop = 0;
4244         } else if (!strcasecmp(cmd, "</Stream>")) {
4245             if (!stream) {
4246                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4247                         filename, line_num);
4248                 errors++;
4249             }
4250             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4251                 if (audio_id != CODEC_ID_NONE) {
4252                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
4253                     audio_enc.codec_id = audio_id;
4254                     add_codec(stream, &audio_enc);
4255                 }
4256                 if (video_id != CODEC_ID_NONE) {
4257                     video_enc.codec_type = CODEC_TYPE_VIDEO;
4258                     video_enc.codec_id = video_id;
4259                     add_codec(stream, &video_enc);
4260                 }
4261             }
4262             stream = NULL;
4263         } else if (!strcasecmp(cmd, "<Redirect")) {
4264             /*********************************************/
4265             char *q;
4266             if (stream || feed || redirect) {
4267                 fprintf(stderr, "%s:%d: Already in a tag\n",
4268                         filename, line_num);
4269                 errors++;
4270             } else {
4271                 redirect = av_mallocz(sizeof(FFStream));
4272                 *last_stream = redirect;
4273                 last_stream = &redirect->next;
4274
4275                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4276                 q = strrchr(redirect->filename, '>');
4277                 if (*q)
4278                     *q = '\0';
4279                 redirect->stream_type = STREAM_TYPE_REDIRECT;
4280             }
4281         } else if (!strcasecmp(cmd, "URL")) {
4282             if (redirect)
4283                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4284         } else if (!strcasecmp(cmd, "</Redirect>")) {
4285             if (!redirect) {
4286                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4287                         filename, line_num);
4288                 errors++;
4289             }
4290             if (!redirect->feed_filename[0]) {
4291                 fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4292                         filename, line_num);
4293                 errors++;
4294             }
4295             redirect = NULL;
4296         } else if (!strcasecmp(cmd, "LoadModule")) {
4297             get_arg(arg, sizeof(arg), &p);
4298 #ifdef HAVE_DLOPEN
4299             load_module(arg);
4300 #else
4301             fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4302                     filename, line_num, arg);
4303             errors++;
4304 #endif
4305         } else {
4306             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4307                     filename, line_num, cmd);
4308             errors++;
4309         }
4310     }
4311
4312     fclose(f);
4313     if (errors)
4314         return -1;
4315     else
4316         return 0;
4317 }
4318
4319 static void show_help(void)
4320 {
4321     printf("usage: ffserver [-L] [-h] [-f configfile]\n"
4322            "Hyper fast multi format Audio/Video streaming server\n"
4323            "\n"
4324            "-L            : print the LICENSE\n"
4325            "-h            : this help\n"
4326            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
4327            );
4328 }
4329
4330 static void handle_child_exit(int sig)
4331 {
4332     pid_t pid;
4333     int status;
4334
4335     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4336         FFStream *feed;
4337
4338         for (feed = first_feed; feed; feed = feed->next) {
4339             if (feed->pid == pid) {
4340                 int uptime = time(0) - feed->pid_start;
4341
4342                 feed->pid = 0;
4343                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4344
4345                 if (uptime < 30)
4346                     /* Turn off any more restarts */
4347                     feed->child_argv = 0;
4348             }
4349         }
4350     }
4351
4352     need_to_start_children = 1;
4353 }
4354
4355 int main(int argc, char **argv)
4356 {
4357     const char *config_filename;
4358     int c;
4359     struct sigaction sigact;
4360
4361     av_register_all();
4362
4363     show_banner(program_name, program_birth_year);
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     for(;;) {
4372         c = getopt(argc, argv, "ndLh?f:");
4373         if (c == -1)
4374             break;
4375         switch(c) {
4376         case 'L':
4377             show_license();
4378             exit(0);
4379         case '?':
4380         case 'h':
4381             show_help();
4382             exit(0);
4383         case 'n':
4384             no_launch = 1;
4385             break;
4386         case 'd':
4387             ffserver_debug = 1;
4388             ffserver_daemon = 0;
4389             break;
4390         case 'f':
4391             config_filename = optarg;
4392             break;
4393         default:
4394             exit(2);
4395         }
4396     }
4397
4398     putenv("http_proxy");               /* Kill the http_proxy */
4399
4400     av_init_random(av_gettime() + (getpid() << 16), &random_state);
4401
4402     /* address on which the server will handle HTTP connections */
4403     my_http_addr.sin_family = AF_INET;
4404     my_http_addr.sin_port = htons (8080);
4405     my_http_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4406
4407     /* address on which the server will handle RTSP connections */
4408     my_rtsp_addr.sin_family = AF_INET;
4409     my_rtsp_addr.sin_port = htons (5454);
4410     my_rtsp_addr.sin_addr.s_addr = htonl (INADDR_ANY);
4411
4412     nb_max_connections = 5;
4413     max_bandwidth = 1000;
4414     first_stream = NULL;
4415     logfilename[0] = '\0';
4416
4417     memset(&sigact, 0, sizeof(sigact));
4418     sigact.sa_handler = handle_child_exit;
4419     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4420     sigaction(SIGCHLD, &sigact, 0);
4421
4422     if (parse_ffconfig(config_filename) < 0) {
4423         fprintf(stderr, "Incorrect config file - exiting.\n");
4424         exit(1);
4425     }
4426
4427     build_file_streams();
4428
4429     build_feed_streams();
4430
4431     compute_bandwidth();
4432
4433     /* put the process in background and detach it from its TTY */
4434     if (ffserver_daemon) {
4435         int pid;
4436
4437         pid = fork();
4438         if (pid < 0) {
4439             perror("fork");
4440             exit(1);
4441         } else if (pid > 0) {
4442             /* parent : exit */
4443             exit(0);
4444         } else {
4445             /* child */
4446             setsid();
4447             chdir("/");
4448             close(0);
4449             open("/dev/null", O_RDWR);
4450             if (strcmp(logfilename, "-") != 0) {
4451                 close(1);
4452                 dup(0);
4453             }
4454             close(2);
4455             dup(0);
4456         }
4457     }
4458
4459     /* signal init */
4460     signal(SIGPIPE, SIG_IGN);
4461
4462     /* open log file if needed */
4463     if (logfilename[0] != '\0') {
4464         if (!strcmp(logfilename, "-"))
4465             logfile = stdout;
4466         else
4467             logfile = fopen(logfilename, "w");
4468     }
4469
4470     if (http_server() < 0) {
4471         fprintf(stderr, "Could not start server\n");
4472         exit(1);
4473     }
4474
4475     return 0;
4476 }