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