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