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