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