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