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