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