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