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