ffserver.c 157 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
Fabrice Bellard's avatar
Fabrice Bellard committed
3
 *
4 5 6
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
19
 */
20

21 22 23 24 25
/**
 * @file
 * multiple format streaming server based on the FFmpeg libraries
 */

26
#include "config.h"
27
#if !HAVE_CLOSESOCKET
28 29 30 31
#define closesocket close
#endif
#include <string.h>
#include <stdlib.h>
32
#include <stdio.h>
33
#include "libavformat/avformat.h"
34
// FIXME those are internal headers, ffserver _really_ shouldn't use them
35
#include "libavformat/ffm.h"
36 37
#include "libavformat/network.h"
#include "libavformat/os_support.h"
38
#include "libavformat/rtpdec.h"
39
#include "libavformat/rtpproto.h"
40
#include "libavformat/rtsp.h"
41
#include "libavformat/rtspcodes.h"
42
#include "libavformat/avio_internal.h"
43 44 45
#include "libavformat/internal.h"
#include "libavformat/url.h"

46
#include "libavutil/avassert.h"
47
#include "libavutil/avstring.h"
48
#include "libavutil/lfg.h"
49
#include "libavutil/dict.h"
50
#include "libavutil/intreadwrite.h"
51
#include "libavutil/mathematics.h"
52
#include "libavutil/pixdesc.h"
53
#include "libavutil/random_seed.h"
54
#include "libavutil/parseutils.h"
55
#include "libavutil/opt.h"
56 57
#include "libavutil/time.h"

Fabrice Bellard's avatar
Fabrice Bellard committed
58 59 60 61
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
62
#if HAVE_POLL_H
63
#include <poll.h>
64
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
65 66
#include <errno.h>
#include <time.h>
67
#include <sys/wait.h>
Fabrice Bellard's avatar
Fabrice Bellard committed
68
#include <signal.h>
69

70
#include "cmdutils.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
71

72
const char program_name[] = "ffserver";
73
const int program_birth_year = 2000;
74

75 76
static const OptionDef options[];

Fabrice Bellard's avatar
Fabrice Bellard committed
77 78 79 80
enum HTTPState {
    HTTPSTATE_WAIT_REQUEST,
    HTTPSTATE_SEND_HEADER,
    HTTPSTATE_SEND_DATA_HEADER,
81
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
Fabrice Bellard's avatar
Fabrice Bellard committed
82
    HTTPSTATE_SEND_DATA_TRAILER,
83
    HTTPSTATE_RECEIVE_DATA,
84 85 86 87 88
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
    HTTPSTATE_READY,

    RTSPSTATE_WAIT_REQUEST,
    RTSPSTATE_SEND_REPLY,
89
    RTSPSTATE_SEND_PACKET,
Fabrice Bellard's avatar
Fabrice Bellard committed
90 91
};

Baptiste Coudurier's avatar
Baptiste Coudurier committed
92
static const char *http_state[] = {
93 94 95
    "HTTP_WAIT_REQUEST",
    "HTTP_SEND_HEADER",

Fabrice Bellard's avatar
Fabrice Bellard committed
96 97 98 99 100
    "SEND_DATA_HEADER",
    "SEND_DATA",
    "SEND_DATA_TRAILER",
    "RECEIVE_DATA",
    "WAIT_FEED",
101 102 103 104
    "READY",

    "RTSP_WAIT_REQUEST",
    "RTSP_SEND_REPLY",
105
    "RTSP_SEND_PACKET",
Fabrice Bellard's avatar
Fabrice Bellard committed
106 107
};

108 109
#define MAX_STREAMS 20

110
#define IOBUFFER_INIT_SIZE 8192
Fabrice Bellard's avatar
Fabrice Bellard committed
111 112

/* timeouts are in ms */
113 114 115
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)

Fabrice Bellard's avatar
Fabrice Bellard committed
116 117
#define SYNC_TIMEOUT (10 * 1000)

118 119 120 121 122
typedef struct RTSPActionServerSetup {
    uint32_t ipaddr;
    char transport_option[512];
} RTSPActionServerSetup;

123
typedef struct {
124
    int64_t count1, count2;
125
    int64_t time1, time2;
126 127
} DataRateData;

Fabrice Bellard's avatar
Fabrice Bellard committed
128 129 130 131 132 133
/* context associated with one connection */
typedef struct HTTPContext {
    enum HTTPState state;
    int fd; /* socket file descriptor */
    struct sockaddr_in from_addr; /* origin */
    struct pollfd *poll_entry; /* used when polling */
134
    int64_t timeout;
135
    uint8_t *buffer_ptr, *buffer_end;
Fabrice Bellard's avatar
Fabrice Bellard committed
136
    int http_error;
137
    int post;
138 139
    int chunked_encoding;
    int chunk_size;               /* 0 if it needs to be read */
Fabrice Bellard's avatar
Fabrice Bellard committed
140
    struct HTTPContext *next;
141
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
142
    int64_t data_count;
Fabrice Bellard's avatar
Fabrice Bellard committed
143 144 145 146
    /* feed input */
    int feed_fd;
    /* input format handling */
    AVFormatContext *fmt_in;
147
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
148
    int64_t first_pts;            /* initial pts value */
149 150 151 152 153 154 155
    int64_t cur_pts;             /* current pts value from the stream in us */
    int64_t cur_frame_duration;  /* duration of the current frame in us */
    int cur_frame_bytes;       /* output frame size, needed to compute
                                  the time at which we send each
                                  packet */
    int pts_stream_index;        /* stream we choose as clock reference */
    int64_t cur_clock;           /* current clock reference value in us */
Fabrice Bellard's avatar
Fabrice Bellard committed
156 157
    /* output format handling */
    struct FFStream *stream;
158 159 160 161
    /* -1 is invalid stream */
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
    int switch_pending;
162
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
Fabrice Bellard's avatar
Fabrice Bellard committed
163
    int last_packet_sent; /* true if last data packet was sent */
164
    int suppress_log;
165
    DataRateData datarate;
166
    int wmp_client_id;
167 168 169
    char protocol[16];
    char method[16];
    char url[128];
170
    int buffer_size;
171
    uint8_t *buffer;
172 173
    int is_packetized; /* if true, the stream is packetized */
    int packet_stream_index; /* current stream for output in state machine */
174

175
    /* RTSP state specific */
176
    uint8_t *pb_buffer; /* XXX: use that in all the code */
177
    AVIOContext *pb;
178
    int seq; /* RTSP sequence number */
179

180
    /* RTP state specific */
181
    enum RTSPLowerTransport rtp_protocol;
182 183
    char session_id[32]; /* session id */
    AVFormatContext *rtp_ctx[MAX_STREAMS];
184

185 186 187 188 189 190
    /* RTP/UDP specific */
    URLContext *rtp_handles[MAX_STREAMS];

    /* RTP/TCP specific */
    struct HTTPContext *rtsp_c;
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
Fabrice Bellard's avatar
Fabrice Bellard committed
191 192 193 194 195 196
} HTTPContext;

/* each generated stream is described here */
enum StreamType {
    STREAM_TYPE_LIVE,
    STREAM_TYPE_STATUS,
197
    STREAM_TYPE_REDIRECT,
Fabrice Bellard's avatar
Fabrice Bellard committed
198 199
};

200 201 202 203 204 205 206 207
enum IPAddressAction {
    IP_ALLOW = 1,
    IP_DENY,
};

typedef struct IPAddressACL {
    struct IPAddressACL *next;
    enum IPAddressAction action;
208
    /* These are in host order */
209 210 211 212
    struct in_addr first;
    struct in_addr last;
} IPAddressACL;

Fabrice Bellard's avatar
Fabrice Bellard committed
213 214 215 216
/* description of each stream of the ffserver.conf file */
typedef struct FFStream {
    enum StreamType stream_type;
    char filename[1024];     /* stream filename */
217 218
    struct FFStream *feed;   /* feed we are using (can be null if
                                coming from file) */
219
    AVDictionary *in_opts;   /* input parameters */
220
    AVDictionary *metadata;  /* metadata to set on the stream */
221
    AVInputFormat *ifmt;       /* if non NULL, force input format */
222
    AVOutputFormat *fmt;
223
    IPAddressACL *acl;
224
    char dynamic_acl[1024];
Fabrice Bellard's avatar
Fabrice Bellard committed
225
    int nb_streams;
226
    int prebuffer;      /* Number of milliseconds early to start */
227
    int64_t max_time;      /* Number of milliseconds to run */
228
    int send_on_key;
Fabrice Bellard's avatar
Fabrice Bellard committed
229 230 231 232
    AVStream *streams[MAX_STREAMS];
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
    char feed_filename[1024]; /* file name of the feed storage, or
                                 input file name for a stream */
233
    pid_t pid;  /* Of ffmpeg process */
234
    time_t pid_start;  /* Of ffmpeg process */
235
    char **child_argv;
Fabrice Bellard's avatar
Fabrice Bellard committed
236
    struct FFStream *next;
237
    unsigned bandwidth; /* bandwidth, in kbits/s */
238 239
    /* RTSP options */
    char *rtsp_option;
240 241 242 243
    /* multicast specific */
    int is_multicast;
    struct in_addr multicast_ip;
    int multicast_port; /* first port used for multicast */
244 245
    int multicast_ttl;
    int loop; /* if true, send the stream in loops (only meaningful if file) */
246

Fabrice Bellard's avatar
Fabrice Bellard committed
247
    /* feed specific */
248
    int feed_opened;     /* true if someone is writing to the feed */
Fabrice Bellard's avatar
Fabrice Bellard committed
249
    int is_feed;         /* true if it is a feed */
250
    int readonly;        /* True if writing is prohibited to the file */
251
    int truncate;        /* True if feeder connection truncate the feed file */
252
    int conns_served;
253
    int64_t bytes_served;
254
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
Diego Biurrun's avatar
Diego Biurrun committed
255
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
256
    int64_t feed_size;          /* current size of feed */
Fabrice Bellard's avatar
Fabrice Bellard committed
257 258 259 260 261
    struct FFStream *next_feed;
} FFStream;

typedef struct FeedData {
    long long data_count;
Diego Biurrun's avatar
Diego Biurrun committed
262
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
Fabrice Bellard's avatar
Fabrice Bellard committed
263 264
} FeedData;

265 266
static struct sockaddr_in my_http_addr;
static struct sockaddr_in my_rtsp_addr;
267

268 269 270 271
static char logfilename[1024];
static HTTPContext *first_http_ctx;
static FFStream *first_feed;   /* contains only feeds */
static FFStream *first_stream; /* contains all streams, including feeds */
Fabrice Bellard's avatar
Fabrice Bellard committed
272

273 274 275 276 277
static void new_connection(int server_fd, int is_rtsp);
static void close_connection(HTTPContext *c);

/* HTTP handling */
static int handle_connection(HTTPContext *c);
Fabrice Bellard's avatar
Fabrice Bellard committed
278
static int http_parse_request(HTTPContext *c);
279
static int http_send_data(HTTPContext *c);
280
static void compute_status(HTTPContext *c);
Fabrice Bellard's avatar
Fabrice Bellard committed
281 282 283
static int open_input_stream(HTTPContext *c, const char *info);
static int http_start_receive_data(HTTPContext *c);
static int http_receive_data(HTTPContext *c);
284 285 286 287

/* RTSP handling */
static int rtsp_parse_request(HTTPContext *c);
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
288
static void rtsp_cmd_options(HTTPContext *c, const char *url);
289 290
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291
static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
292

293
/* SDP handling */
294
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
295 296
                                   struct in_addr my_ip);

297
/* RTP handling */
298
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
299
                                       FFStream *stream, const char *session_id,
300
                                       enum RTSPLowerTransport rtp_protocol);
301
static int rtp_new_av_stream(HTTPContext *c,
302 303
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c);
Fabrice Bellard's avatar
Fabrice Bellard committed
304

305 306
static const char *my_program_name;

307
static const char *config_filename;
308

309 310
static int ffserver_debug;
static int no_launch;
311
static int need_to_start_children;
312

313 314
/* maximum number of simultaneous HTTP connections */
static unsigned int nb_max_http_connections = 2000;
315 316
static unsigned int nb_max_connections = 5;
static unsigned int nb_connections;
Fabrice Bellard's avatar
Fabrice Bellard committed
317

318
static uint64_t max_bandwidth = 1000;
319
static uint64_t current_bandwidth;
320

321
static int64_t cur_time;           // Making this global saves on passing it around everywhere
322

323
static AVLFG random_state;
324

Fabrice Bellard's avatar
Fabrice Bellard committed
325 326
static FILE *logfile = NULL;

327 328 329 330 331 332 333 334
static void htmlstrip(char *s) {
    while (s && *s) {
        s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
        if (*s)
            *s++ = '?';
    }
}

335 336 337 338
static int64_t ffm_read_write_index(int fd)
{
    uint8_t buf[8];

339 340
    if (lseek(fd, 8, SEEK_SET) < 0)
        return AVERROR(EIO);
341 342 343 344 345 346 347 348 349 350 351 352
    if (read(fd, buf, 8) != 8)
        return AVERROR(EIO);
    return AV_RB64(buf);
}

static int ffm_write_write_index(int fd, int64_t pos)
{
    uint8_t buf[8];
    int i;

    for(i=0;i<8;i++)
        buf[i] = (pos >> (56 - i * 8)) & 0xff;
353 354
    if (lseek(fd, 8, SEEK_SET) < 0)
        return AVERROR(EIO);
355 356 357 358 359 360 361 362 363 364 365 366 367
    if (write(fd, buf, 8) != 8)
        return AVERROR(EIO);
    return 8;
}

static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
                                int64_t file_size)
{
    FFMContext *ffm = s->priv_data;
    ffm->write_index = pos;
    ffm->file_size = file_size;
}

368 369 370 371 372 373 374 375
/* FIXME: make ffserver work with IPv6 */
/* resolve host with also IP address parsing */
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
{

    if (!ff_inet_aton(hostname, sin_addr)) {
#if HAVE_GETADDRINFO
        struct addrinfo *ai, *cur;
376
        struct addrinfo hints = { 0 };
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
        hints.ai_family = AF_INET;
        if (getaddrinfo(hostname, NULL, &hints, &ai))
            return -1;
        /* getaddrinfo returns a linked list of addrinfo structs.
         * Even if we set ai_family = AF_INET above, make sure
         * that the returned one actually is of the correct type. */
        for (cur = ai; cur; cur = cur->ai_next) {
            if (cur->ai_family == AF_INET) {
                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
                freeaddrinfo(ai);
                return 0;
            }
        }
        freeaddrinfo(ai);
        return -1;
#else
        struct hostent *hp;
        hp = gethostbyname(hostname);
        if (!hp)
            return -1;
        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
#endif
    }
    return 0;
}

403
static char *ctime1(char *buf2, int buf_size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
404 405 406 407 408 409
{
    time_t ti;
    char *p;

    ti = time(NULL);
    p = ctime(&ti);
410
    av_strlcpy(buf2, p, buf_size);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
411 412 413 414 415 416
    p = buf2 + strlen(p) - 1;
    if (*p == '\n')
        *p = '\0';
    return buf2;
}

417
static void http_vlog(const char *fmt, va_list vargs)
Fabrice Bellard's avatar
Fabrice Bellard committed
418
{
419
    static int print_prefix = 1;
420
    if (logfile) {
421
        if (print_prefix) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
422
            char buf[32];
423
            ctime1(buf, sizeof(buf));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
424
            fprintf(logfile, "%s ", buf);
425 426
        }
        print_prefix = strstr(fmt, "\n") != NULL;
427
        vfprintf(logfile, fmt, vargs);
428 429
        fflush(logfile);
    }
430 431
}

432 433 434 435
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
static void http_log(const char *fmt, ...)
436 437 438 439 440 441 442 443 444 445 446
{
    va_list vargs;
    va_start(vargs, fmt);
    http_vlog(fmt, vargs);
    va_end(vargs);
}

static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
{
    static int print_prefix = 1;
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
447
    if (level > av_log_get_level())
448 449
        return;
    if (print_prefix && avc)
450
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
451 452
    print_prefix = strstr(fmt, "\n") != NULL;
    http_vlog(fmt, vargs);
Fabrice Bellard's avatar
Fabrice Bellard committed
453 454
}

455 456
static void log_connection(HTTPContext *c)
{
457
    if (c->suppress_log)
458 459
        return;

460 461
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
462
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
463 464
}

465
static void update_datarate(DataRateData *drd, int64_t count)
466 467 468 469
{
    if (!drd->time1 && !drd->count1) {
        drd->time1 = drd->time2 = cur_time;
        drd->count1 = drd->count2 = count;
470
    } else if (cur_time - drd->time2 > 5000) {
Alex Beregszaszi's avatar
Alex Beregszaszi committed
471 472 473 474
        drd->time1 = drd->time2;
        drd->count1 = drd->count2;
        drd->time2 = cur_time;
        drd->count2 = count;
475 476 477 478
    }
}

/* In bytes per second */
479
static int compute_datarate(DataRateData *drd, int64_t count)
480 481 482
{
    if (cur_time == drd->time1)
        return 0;
483

484 485 486
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
}

487

488 489
static void start_children(FFStream *feed)
{
490 491 492
    if (no_launch)
        return;

493
    for (; feed; feed = feed->next) {
494 495 496
        if (feed->child_argv && !feed->pid) {
            feed->pid_start = time(0);

497 498 499
            feed->pid = fork();

            if (feed->pid < 0) {
500
                http_log("Unable to create children\n");
501 502 503 504 505 506 507 508
                exit(1);
            }
            if (!feed->pid) {
                /* In child */
                char pathname[1024];
                char *slash;
                int i;

509 510
                /* replace "ffserver" with "ffmpeg" in the path of current
                 * program. Ignore user provided path */
511 512 513 514 515 516 517 518
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
                slash = strrchr(pathname, '/');
                if (!slash)
                    slash = pathname;
                else
                    slash++;
                strcpy(slash, "ffmpeg");

519
                http_log("Launch command line: ");
Stefano Sabatini's avatar
Stefano Sabatini committed
520 521 522 523
                http_log("%s ", pathname);
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
                    http_log("%s ", feed->child_argv[i]);
                http_log("\n");
524

525
                for (i = 3; i < 256; i++)
526
                    close(i);
527

528
                if (!ffserver_debug) {
529 530 531 532 533 534
                    if (!freopen("/dev/null", "r", stdin))
                        http_log("failed to redirect STDIN to /dev/null\n;");
                    if (!freopen("/dev/null", "w", stdout))
                        http_log("failed to redirect STDOUT to /dev/null\n;");
                    if (!freopen("/dev/null", "w", stderr))
                        http_log("failed to redirect STDERR to /dev/null\n;");
535
                }
536

537 538
                signal(SIGPIPE, SIG_DFL);

539 540 541 542 543 544
                execvp(pathname, feed->child_argv);

                _exit(1);
            }
        }
    }
545 546
}

547 548
/* open a listening socket */
static int socket_open_listen(struct sockaddr_in *my_addr)
Fabrice Bellard's avatar
Fabrice Bellard committed
549
{
550
    int server_fd, tmp;
Fabrice Bellard's avatar
Fabrice Bellard committed
551 552 553 554 555 556

    server_fd = socket(AF_INET,SOCK_STREAM,0);
    if (server_fd < 0) {
        perror ("socket");
        return -1;
    }
557

Fabrice Bellard's avatar
Fabrice Bellard committed
558 559 560
    tmp = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));

561
    my_addr->sin_family = AF_INET;
562
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
563 564 565
        char bindmsg[32];
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
        perror (bindmsg);
566
        closesocket(server_fd);
Fabrice Bellard's avatar
Fabrice Bellard committed
567 568
        return -1;
    }
569

Fabrice Bellard's avatar
Fabrice Bellard committed
570 571
    if (listen (server_fd, 5) < 0) {
        perror ("listen");
572
        closesocket(server_fd);
Fabrice Bellard's avatar
Fabrice Bellard committed
573 574
        return -1;
    }
575
    ff_socket_nonblock(server_fd, 1);
576 577 578 579

    return server_fd;
}

580 581 582 583 584 585
/* start all multicast streams */
static void start_multicast(void)
{
    FFStream *stream;
    char session_id[32];
    HTTPContext *rtp_c;
586
    struct sockaddr_in dest_addr = {0};
587 588 589 590 591
    int default_port, stream_index;

    default_port = 6000;
    for(stream = first_stream; stream != NULL; stream = stream->next) {
        if (stream->is_multicast) {
592 593
            unsigned random0 = av_lfg_get(&random_state);
            unsigned random1 = av_lfg_get(&random_state);
594
            /* open the RTP connection */
595
            snprintf(session_id, sizeof(session_id), "%08x%08x",
596
                     random0, random1);
597 598 599 600 601 602 603 604 605 606 607

            /* choose a port if none given */
            if (stream->multicast_port == 0) {
                stream->multicast_port = default_port;
                default_port += 100;
            }

            dest_addr.sin_family = AF_INET;
            dest_addr.sin_addr = stream->multicast_ip;
            dest_addr.sin_port = htons(stream->multicast_port);

608
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
609
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
610
            if (!rtp_c)
611
                continue;
612

613
            if (open_input_stream(rtp_c, "") < 0) {
614 615
                http_log("Could not open input stream for stream '%s'\n",
                         stream->filename);
616 617 618 619
                continue;
            }

            /* open each RTP stream */
620
            for(stream_index = 0; stream_index < stream->nb_streams;
621
                stream_index++) {
622
                dest_addr.sin_port = htons(stream->multicast_port +
623
                                           2 * stream_index);
624
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
625 626
                    http_log("Could not open output stream '%s/streamid=%d'\n",
                             stream->filename, stream_index);
627
                    exit(1);
628 629 630 631 632 633 634
                }
            }

            rtp_c->state = HTTPSTATE_SEND_DATA;
        }
    }
}
635

636
/* main loop of the HTTP server */
637 638
static int http_server(void)
{
639
    int server_fd = 0, rtsp_server_fd = 0;
640
    int ret, delay;
641
    struct pollfd *poll_table, *poll_entry;
642 643
    HTTPContext *c, *c_next;

644
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
645 646 647 648
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
        return -1;
    }

649
    if (my_http_addr.sin_port) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
650 651 652
        server_fd = socket_open_listen(&my_http_addr);
        if (server_fd < 0)
            return -1;
653
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
654

655
    if (my_rtsp_addr.sin_port) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
656 657 658
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
        if (rtsp_server_fd < 0)
            return -1;
659 660 661 662 663 664
    }

    if (!rtsp_server_fd && !server_fd) {
        http_log("HTTP and RTSP disabled.\n");
        return -1;
    }
665

666
    http_log("FFserver started.\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
667

668 669
    start_children(first_feed);

670 671
    start_multicast();

Fabrice Bellard's avatar
Fabrice Bellard committed
672 673
    for(;;) {
        poll_entry = poll_table;
674
        if (server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
675 676 677
            poll_entry->fd = server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
678 679
        }
        if (rtsp_server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
680 681 682
            poll_entry->fd = rtsp_server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
683
        }
684

Fabrice Bellard's avatar
Fabrice Bellard committed
685 686
        /* wait for events on each HTTP handle */
        c = first_http_ctx;
687
        delay = 1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
688 689 690 691
        while (c != NULL) {
            int fd;
            fd = c->fd;
            switch(c->state) {
692 693
            case HTTPSTATE_SEND_HEADER:
            case RTSPSTATE_SEND_REPLY:
694
            case RTSPSTATE_SEND_PACKET:
Fabrice Bellard's avatar
Fabrice Bellard committed
695 696
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
697
                poll_entry->events = POLLOUT;
Fabrice Bellard's avatar
Fabrice Bellard committed
698 699 700 701 702
                poll_entry++;
                break;
            case HTTPSTATE_SEND_DATA_HEADER:
            case HTTPSTATE_SEND_DATA:
            case HTTPSTATE_SEND_DATA_TRAILER:
703
                if (!c->is_packetized) {
704 705
                    /* for TCP, we output as much as we can
                     * (may need to put a limit) */
706 707 708 709 710
                    c->poll_entry = poll_entry;
                    poll_entry->fd = fd;
                    poll_entry->events = POLLOUT;
                    poll_entry++;
                } else {
711
                    /* when ffserver is doing the timing, we work by
712
                       looking at which packet needs to be sent every
713
                       10 ms */
714 715 716
                    /* one tick wait XXX: 10 ms assumed */
                    if (delay > 10)
                        delay = 10;
717
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
718
                break;
719
            case HTTPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
720 721
            case HTTPSTATE_RECEIVE_DATA:
            case HTTPSTATE_WAIT_FEED:
722
            case RTSPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
723 724 725
                /* need to catch errors */
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
726
                poll_entry->events = POLLIN;/* Maybe this will work */
Fabrice Bellard's avatar
Fabrice Bellard committed
727 728 729 730 731 732 733 734 735 736 737 738
                poll_entry++;
                break;
            default:
                c->poll_entry = NULL;
                break;
            }
            c = c->next;
        }

        /* wait for an event on one connection. We poll at least every
           second to handle timeouts */
        do {
739
            ret = poll(poll_table, poll_entry - poll_table, delay);
740 741
            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
742
                return -1;
743
        } while (ret < 0);
744

745
        cur_time = av_gettime() / 1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
746

747 748 749 750 751
        if (need_to_start_children) {
            need_to_start_children = 0;
            start_children(first_feed);
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
752
        /* now handle the events */
753 754 755
        for(c = first_http_ctx; c != NULL; c = c_next) {
            c_next = c->next;
            if (handle_connection(c) < 0) {
756
                log_connection(c);
757
                /* close and free the connection */
758
                close_connection(c);
Fabrice Bellard's avatar
Fabrice Bellard committed
759 760 761 762
            }
        }

        poll_entry = poll_table;
763
        if (server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
764 765 766 767
            /* new HTTP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(server_fd, 0);
            poll_entry++;
768 769
        }
        if (rtsp_server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
770 771 772
            /* new RTSP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(rtsp_server_fd, 1);
773
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
774 775 776
    }
}

777 778
/* start waiting for a new HTTP/RTSP request */
static void start_wait_request(HTTPContext *c, int is_rtsp)
Fabrice Bellard's avatar
Fabrice Bellard committed
779
{
780 781 782 783 784 785 786 787 788 789 790 791
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */

    if (is_rtsp) {
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
        c->state = RTSPSTATE_WAIT_REQUEST;
    } else {
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
        c->state = HTTPSTATE_WAIT_REQUEST;
    }
}

792 793
static void http_send_too_busy_reply(int fd)
{
794
    char buffer[400];
795
    int len = snprintf(buffer, sizeof(buffer),
796
                       "HTTP/1.0 503 Server too busy\r\n"
797 798 799 800
                       "Content-type: text/html\r\n"
                       "\r\n"
                       "<html><head><title>Too busy</title></head><body>\r\n"
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
801
                       "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
802 803
                       "</body></html>\r\n",
                       nb_connections, nb_max_connections);
804
    av_assert0(len < sizeof(buffer));
805 806 807 808
    send(fd, buffer, len, 0);
}


809 810 811
static void new_connection(int server_fd, int is_rtsp)
{
    struct sockaddr_in from_addr;
812 813
    socklen_t len;
    int fd;
814 815 816
    HTTPContext *c = NULL;

    len = sizeof(from_addr);
817
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
818
                &len);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
819 820
    if (fd < 0) {
        http_log("error during accept %s\n", strerror(errno));
821
        return;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
822
    }
823
    ff_socket_nonblock(fd, 1);
824

825 826
    if (nb_connections >= nb_max_connections) {
        http_send_too_busy_reply(fd);
827
        goto fail;
828
    }
829

830 831 832 833
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
834

835 836 837 838 839 840 841
    c->fd = fd;
    c->poll_entry = NULL;
    c->from_addr = from_addr;
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;
842 843 844

    c->next = first_http_ctx;
    first_http_ctx = c;
845
    nb_connections++;
846

847 848 849 850 851 852 853 854 855
    start_wait_request(c, is_rtsp);

    return;

 fail:
    if (c) {
        av_free(c->buffer);
        av_free(c);
    }
856
    closesocket(fd);
857 858 859 860 861 862 863 864 865 866 867 868 869 870
}

static void close_connection(HTTPContext *c)
{
    HTTPContext **cp, *c1;
    int i, nb_streams;
    AVFormatContext *ctx;
    URLContext *h;
    AVStream *st;

    /* remove connection from list */
    cp = &first_http_ctx;
    while ((*cp) != NULL) {
        c1 = *cp;
871
        if (c1 == c)
872
            *cp = c->next;
873
        else
874 875 876
            cp = &c1->next;
    }

877 878 879 880 881 882
    /* remove references, if any (XXX: do it faster) */
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
        if (c1->rtsp_c == c)
            c1->rtsp_c = NULL;
    }

883 884
    /* remove connection associated resources */
    if (c->fd >= 0)
885
        closesocket(c->fd);
886 887 888 889
    if (c->fmt_in) {
        /* close each frame parser */
        for(i=0;i<c->fmt_in->nb_streams;i++) {
            st = c->fmt_in->streams[i];
890
            if (st->codec->codec)
891
                avcodec_close(st->codec);
892
        }
893
        avformat_close_input(&c->fmt_in);
894 895 896 897
    }

    /* free RTP output streams if any */
    nb_streams = 0;
898
    if (c->stream)
899
        nb_streams = c->stream->nb_streams;
900

901 902 903 904
    for(i=0;i<nb_streams;i++) {
        ctx = c->rtp_ctx[i];
        if (ctx) {
            av_write_trailer(ctx);
905
            av_dict_free(&ctx->metadata);
906
            av_free(ctx->streams[0]);
907 908 909
            av_free(ctx);
        }
        h = c->rtp_handles[i];
910
        if (h)
911
            ffurl_close(h);
912
    }
913

914 915
    ctx = &c->fmt_ctx;

916
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
917 918
        if (ctx->oformat) {
            /* prepare header */
919
            if (avio_open_dyn_buf(&ctx->pb) >= 0) {
920
                av_write_trailer(ctx);
921
                av_freep(&c->pb_buffer);
922
                avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
923 924 925 926
            }
        }
    }

927
    for(i=0; i<ctx->nb_streams; i++)
Alex Beregszaszi's avatar
Alex Beregszaszi committed
928
        av_free(ctx->streams[i]);
929 930
    av_freep(&ctx->streams);
    av_freep(&ctx->priv_data);
931

932
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
933
        current_bandwidth -= c->stream->bandwidth;
934 935 936 937 938 939 940

    /* signal that there is no feed if we are the feeder socket */
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
        c->stream->feed_opened = 0;
        close(c->feed_fd);
    }

941
    av_freep(&c->pb_buffer);
942
    av_freep(&c->packet_buffer);
943 944 945 946 947 948 949 950
    av_free(c->buffer);
    av_free(c);
    nb_connections--;
}

static int handle_connection(HTTPContext *c)
{
    int len, ret;
951

Fabrice Bellard's avatar
Fabrice Bellard committed
952 953
    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
954
    case RTSPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
955 956 957 958 959 960 961 962 963 964
        /* timeout ? */
        if ((c->timeout - cur_time) < 0)
            return -1;
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        /* read the data */
965
    read_loop:
966
        len = recv(c->fd, c->buffer_ptr, 1, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
967
        if (len < 0) {
968 969
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
Fabrice Bellard's avatar
Fabrice Bellard committed
970 971 972 973
                return -1;
        } else if (len == 0) {
            return -1;
        } else {
974
            /* search for end of request. */
975
            uint8_t *ptr;
Fabrice Bellard's avatar
Fabrice Bellard committed
976 977 978 979 980
            c->buffer_ptr += len;
            ptr = c->buffer_ptr;
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
                /* request found : parse it and reply */
981 982 983 984 985 986
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
                    ret = http_parse_request(c);
                } else {
                    ret = rtsp_parse_request(c);
                }
                if (ret < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
987 988 989 990
                    return -1;
            } else if (ptr >= c->buffer_end) {
                /* request too long: cannot do anything */
                return -1;
991
            } else goto read_loop;
Fabrice Bellard's avatar
Fabrice Bellard committed
992 993 994 995 996 997 998
        }
        break;

    case HTTPSTATE_SEND_HEADER:
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

999
        /* no need to write if no events */
Fabrice Bellard's avatar
Fabrice Bellard committed
1000 1001
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1002
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
1003
        if (len < 0) {
1004 1005
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1006
                goto close_connection;
Fabrice Bellard's avatar
Fabrice Bellard committed
1007 1008 1009
            }
        } else {
            c->buffer_ptr += len;
1010 1011
            if (c->stream)
                c->stream->bytes_served += len;
1012
            c->data_count += len;
Fabrice Bellard's avatar
Fabrice Bellard committed
1013
            if (c->buffer_ptr >= c->buffer_end) {
1014
                av_freep(&c->pb_buffer);
Fabrice Bellard's avatar
Fabrice Bellard committed
1015
                /* if error, exit */
1016
                if (c->http_error)
Fabrice Bellard's avatar
Fabrice Bellard committed
1017
                    return -1;
1018 1019
                /* all the buffer was sent : synchronize to the incoming
                 * stream */
Fabrice Bellard's avatar
Fabrice Bellard committed
1020 1021 1022 1023 1024 1025 1026 1027 1028
                c->state = HTTPSTATE_SEND_DATA_HEADER;
                c->buffer_ptr = c->buffer_end = c->buffer;
            }
        }
        break;

    case HTTPSTATE_SEND_DATA:
    case HTTPSTATE_SEND_DATA_HEADER:
    case HTTPSTATE_SEND_DATA_TRAILER:
1029
        /* for packetized output, we consider we can always write (the
1030
           input streams set the speed). It may be better to verify
1031 1032 1033 1034
           that we do not rely too much on the kernel queues */
        if (!c->is_packetized) {
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
                return -1;
1035

1036 1037 1038 1039
            /* no need to read if no events */
            if (!(c->poll_entry->revents & POLLOUT))
                return 0;
        }
1040
        if (http_send_data(c) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
1041
            return -1;
1042 1043 1044
        /* close connection if trailer sent */
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
        break;
    case HTTPSTATE_RECEIVE_DATA:
        /* no need to read if no events */
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        if (http_receive_data(c) < 0)
            return -1;
        break;
    case HTTPSTATE_WAIT_FEED:
        /* no need to read if no events */
1057
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
Fabrice Bellard's avatar
Fabrice Bellard committed
1058 1059 1060 1061
            return -1;

        /* nothing to do, we'll be waken up by incoming feed packets */
        break;
1062 1063

    case RTSPSTATE_SEND_REPLY:
1064 1065
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            goto close_connection;
1066 1067 1068
        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1069
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1070
        if (len < 0) {
1071 1072
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1073
                goto close_connection;
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
            }
        } else {
            c->buffer_ptr += len;
            c->data_count += len;
            if (c->buffer_ptr >= c->buffer_end) {
                /* all the buffer was sent : wait for a new request */
                av_freep(&c->pb_buffer);
                start_wait_request(c, 1);
            }
        }
        break;
1085 1086 1087 1088 1089 1090 1091 1092
    case RTSPSTATE_SEND_PACKET:
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
            av_freep(&c->packet_buffer);
            return -1;
        }
        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1093 1094
        len = send(c->fd, c->packet_buffer_ptr,
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1095
        if (len < 0) {
1096 1097
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
                /* error : close connection */
                av_freep(&c->packet_buffer);
                return -1;
            }
        } else {
            c->packet_buffer_ptr += len;
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
                /* all the buffer was sent : wait for a new request */
                av_freep(&c->packet_buffer);
                c->state = RTSPSTATE_WAIT_REQUEST;
            }
        }
        break;
1111 1112 1113
    case HTTPSTATE_READY:
        /* nothing to do */
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
1114 1115 1116 1117
    default:
        return -1;
    }
    return 0;
1118 1119 1120 1121

close_connection:
    av_freep(&c->pb_buffer);
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1122 1123
}

1124 1125 1126 1127 1128
static int extract_rates(char *rates, int ratelen, const char *request)
{
    const char *p;

    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1129
        if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1130 1131
            const char *q = p + 7;

1132
            while (*q && *q != '\n' && av_isspace(*q))
1133 1134
                q++;

1135
            if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1136 1137 1138 1139 1140
                int stream_no;
                int rate_no;

                q += 20;

1141
                memset(rates, 0xff, ratelen);
1142 1143 1144 1145 1146

                while (1) {
                    while (*q && *q != '\n' && *q != ':')
                        q++;

1147
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1148
                        break;
1149

1150
                    stream_no--;
1151
                    if (stream_no < ratelen && stream_no >= 0)
1152 1153
                        rates[stream_no] = rate_no;

1154
                    while (*q && *q != '\n' && !av_isspace(*q))
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
                        q++;
                }

                return 1;
            }
        }
        p = strchr(p, '\n');
        if (!p)
            break;

        p++;
    }

    return 0;
}

1171
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1172 1173
{
    int i;
1174 1175 1176 1177
    int best_bitrate = 100000000;
    int best = -1;

    for (i = 0; i < feed->nb_streams; i++) {
1178
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1179 1180 1181 1182

        if (feed_codec->codec_id != codec->codec_id ||
            feed_codec->sample_rate != codec->sample_rate ||
            feed_codec->width != codec->width ||
1183
            feed_codec->height != codec->height)
1184 1185 1186 1187
            continue;

        /* Potential stream */

1188
        /* We want the fastest stream less than bit_rate, or the slowest
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
         * faster than bit_rate
         */

        if (feed_codec->bit_rate <= bit_rate) {
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
                best_bitrate = feed_codec->bit_rate;
                best = i;
            }
        } else {
            if (feed_codec->bit_rate < best_bitrate) {
                best_bitrate = feed_codec->bit_rate;
                best = i;
            }
        }
    }

    return best;
}

static int modify_current_stream(HTTPContext *c, char *rates)
{
    int i;
    FFStream *req = c->stream;
    int action_required = 0;
1213

1214 1215 1216 1217
    /* Not much we can do for a feed */
    if (!req->feed)
        return 0;

1218
    for (i = 0; i < req->nb_streams; i++) {
1219
        AVCodecContext *codec = req->streams[i]->codec;
1220 1221 1222

        switch(rates[i]) {
            case 0:
1223
                c->switch_feed_streams[i] = req->feed_streams[i];
1224 1225
                break;
            case 1:
1226
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1227 1228
                break;
            case 2:
1229 1230 1231 1232 1233 1234 1235
                /* Wants off or slow */
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
#ifdef WANTS_OFF
                /* This doesn't work well when it turns off the only stream! */
                c->switch_feed_streams[i] = -2;
                c->feed_streams[i] = -2;
#endif
1236 1237 1238
                break;
        }

1239 1240 1241
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
            action_required = 1;
    }
1242

1243 1244
    return action_required;
}
1245

1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
/* XXX: factorize in utils.c ? */
/* XXX: take care with different space meaning */
static void skip_spaces(const char **pp)
{
    const char *p;
    p = *pp;
    while (*p == ' ' || *p == '\t')
        p++;
    *pp = p;
}

static void get_word(char *buf, int buf_size, const char **pp)
{
    const char *p;
    char *q;

    p = *pp;
    skip_spaces(&p);
    q = buf;
1265
    while (!av_isspace(*p) && *p != '\0') {
1266 1267 1268 1269 1270 1271 1272 1273 1274
        if ((q - buf) < buf_size - 1)
            *q++ = *p;
        p++;
    }
    if (buf_size > 0)
        *q = '\0';
    *pp = p;
}

1275 1276 1277 1278 1279 1280 1281
static void get_arg(char *buf, int buf_size, const char **pp)
{
    const char *p;
    char *q;
    int quote;

    p = *pp;
1282
    while (av_isspace(*p)) p++;
1283 1284 1285 1286 1287 1288 1289 1290 1291
    q = buf;
    quote = 0;
    if (*p == '\"' || *p == '\'')
        quote = *p++;
    for(;;) {
        if (quote) {
            if (*p == quote)
                break;
        } else {
1292
            if (av_isspace(*p))
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
                break;
        }
        if (*p == '\0')
            break;
        if ((q - buf) < buf_size - 1)
            *q++ = *p;
        p++;
    }
    *q = '\0';
    if (quote && *p == quote)
        p++;
    *pp = p;
}

1307 1308 1309 1310 1311 1312 1313 1314
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
                         const char *p, const char *filename, int line_num)
{
    char arg[1024];
    IPAddressACL acl;
    int errors = 0;

    get_arg(arg, sizeof(arg), &p);
1315
    if (av_strcasecmp(arg, "allow") == 0)
1316
        acl.action = IP_ALLOW;
1317
    else if (av_strcasecmp(arg, "deny") == 0)
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
        acl.action = IP_DENY;
    else {
        fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
                filename, line_num, arg);
        errors++;
    }

    get_arg(arg, sizeof(arg), &p);

    if (resolve_host(&acl.first, arg) != 0) {
1328
        fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1329 1330 1331 1332 1333 1334 1335 1336 1337
                filename, line_num, arg);
        errors++;
    } else
        acl.last = acl.first;

    get_arg(arg, sizeof(arg), &p);

    if (arg[0]) {
        if (resolve_host(&acl.last, arg) != 0) {
1338
            fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
                    filename, line_num, arg);
            errors++;
        }
    }

    if (!errors) {
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
        IPAddressACL **naclp = 0;

        acl.next = 0;
        *nacl = acl;

        if (stream)
            naclp = &stream->acl;
        else if (feed)
            naclp = &feed->acl;
        else if (ext_acl)
            naclp = &ext_acl;
        else {
            fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
                    filename, line_num);
            errors++;
        }

        if (naclp) {
            while (*naclp)
                naclp = &(*naclp)->next;

            *naclp = nacl;
        }
    }
}


static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
{
    FILE* f;
    char line[1024];
    char  cmd[1024];
    IPAddressACL *acl = NULL;
    int line_num = 0;
    const char *p;

    f = fopen(stream->dynamic_acl, "r");
    if (!f) {
        perror(stream->dynamic_acl);
        return NULL;
    }

    acl = av_mallocz(sizeof(IPAddressACL));

    /* Build ACL */
    for(;;) {
        if (fgets(line, sizeof(line), f) == NULL)
            break;
        line_num++;
        p = line;
1396
        while (av_isspace(*p))
1397 1398 1399 1400 1401
            p++;
        if (*p == '\0' || *p == '#')
            continue;
        get_arg(cmd, sizeof(cmd), &p);

1402
        if (!av_strcasecmp(cmd, "ACL"))
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
    }
    fclose(f);
    return acl;
}


static void free_acl_list(IPAddressACL *in_acl)
{
    IPAddressACL *pacl,*pacl2;

    pacl = in_acl;
    while(pacl) {
        pacl2 = pacl;
        pacl = pacl->next;
        av_freep(pacl2);
    }
}

static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1423 1424 1425 1426
{
    enum IPAddressAction last_action = IP_DENY;
    IPAddressACL *acl;
    struct in_addr *src = &c->from_addr.sin_addr;
1427
    unsigned long src_addr = src->s_addr;
1428

1429
    for (acl = in_acl; acl; acl = acl->next) {
1430
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1431 1432 1433 1434 1435 1436 1437 1438
            return (acl->action == IP_ALLOW) ? 1 : 0;
        last_action = acl->action;
    }

    /* Nothing matched, so return not the last action */
    return (last_action == IP_DENY) ? 1 : 0;
}

1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
static int validate_acl(FFStream *stream, HTTPContext *c)
{
    int ret = 0;
    IPAddressACL *acl;


    /* if stream->acl is null validate_acl_list will return 1 */
    ret = validate_acl_list(stream->acl, c);

    if (stream->dynamic_acl[0]) {
        acl = parse_dynamic_acl(stream, c);

        ret = validate_acl_list(acl, c);

        free_acl_list(acl);
    }

    return ret;
}

1459
/* compute the real filename of a file by matching it without its
1460
   extensions to all the stream's filenames */
1461 1462 1463 1464 1465 1466 1467 1468
static void compute_real_filename(char *filename, int max_size)
{
    char file1[1024];
    char file2[1024];
    char *p;
    FFStream *stream;

    /* compute filename by matching without the file extensions */
1469
    av_strlcpy(file1, filename, sizeof(file1));
1470 1471 1472 1473
    p = strrchr(file1, '.');
    if (p)
        *p = '\0';
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1474
        av_strlcpy(file2, stream->filename, sizeof(file2));
1475 1476 1477 1478
        p = strrchr(file2, '.');
        if (p)
            *p = '\0';
        if (!strcmp(file1, file2)) {
1479
            av_strlcpy(filename, stream->filename, max_size);
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
            break;
        }
    }
}

enum RedirType {
    REDIR_NONE,
    REDIR_ASX,
    REDIR_RAM,
    REDIR_ASF,
    REDIR_RTSP,
    REDIR_SDP,
};

1494
/* parse HTTP request and prepare header */
Fabrice Bellard's avatar
Fabrice Bellard committed
1495 1496
static int http_parse_request(HTTPContext *c)
{
1497 1498
    const char *p;
    char *p1;
1499
    enum RedirType redir_type;
Fabrice Bellard's avatar
Fabrice Bellard committed
1500
    char cmd[32];
1501
    char info[1024], filename[1024];
Fabrice Bellard's avatar
Fabrice Bellard committed
1502 1503 1504 1505 1506
    char url[1024], *q;
    char protocol[32];
    char msg[1024];
    const char *mime_type;
    FFStream *stream;
1507
    int i;
1508
    char ratebuf[32];
1509
    const char *useragent = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1510 1511

    p = c->buffer;
1512
    get_word(cmd, sizeof(cmd), &p);
1513
    av_strlcpy(c->method, cmd, sizeof(c->method));
1514

Fabrice Bellard's avatar
Fabrice Bellard committed
1515
    if (!strcmp(cmd, "GET"))
1516
        c->post = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1517
    else if (!strcmp(cmd, "POST"))
1518
        c->post = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1519 1520 1521
    else
        return -1;

1522
    get_word(url, sizeof(url), &p);
1523
    av_strlcpy(c->url, url, sizeof(c->url));
1524

1525
    get_word(protocol, sizeof(protocol), (const char **)&p);
Fabrice Bellard's avatar
Fabrice Bellard committed
1526 1527
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
        return -1;
1528

1529
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1530 1531

    if (ffserver_debug)
1532
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1533

Fabrice Bellard's avatar
Fabrice Bellard committed
1534
    /* find the filename and the optional info string in the request */
1535 1536 1537 1538
    p1 = strchr(url, '?');
    if (p1) {
        av_strlcpy(info, p1, sizeof(info));
        *p1 = '\0';
1539
    } else
Fabrice Bellard's avatar
Fabrice Bellard committed
1540 1541
        info[0] = '\0';

1542
    av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1543

1544
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1545
        if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1546
            useragent = p + 11;
1547
            if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
                useragent++;
            break;
        }
        p = strchr(p, '\n');
        if (!p)
            break;

        p++;
    }

1558
    redir_type = REDIR_NONE;
1559
    if (av_match_ext(filename, "asx")) {
1560
        redir_type = REDIR_ASX;
1561
        filename[strlen(filename)-1] = 'f';
1562
    } else if (av_match_ext(filename, "asf") &&
1563
        (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1564
        /* if this isn't WMP or lookalike, return the redirector file */
1565
        redir_type = REDIR_ASF;
1566
    } else if (av_match_ext(filename, "rpm,ram")) {
1567
        redir_type = REDIR_RAM;
1568
        strcpy(filename + strlen(filename)-2, "m");
1569
    } else if (av_match_ext(filename, "rtsp")) {
1570
        redir_type = REDIR_RTSP;
1571
        compute_real_filename(filename, sizeof(filename) - 1);
1572
    } else if (av_match_ext(filename, "sdp")) {
1573
        redir_type = REDIR_SDP;
1574
        compute_real_filename(filename, sizeof(filename) - 1);
1575
    }
1576

1577 1578
    // "redirect" / request to index.html
    if (!strlen(filename))
1579
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1580

Fabrice Bellard's avatar
Fabrice Bellard committed
1581 1582
    stream = first_stream;
    while (stream != NULL) {
1583
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
Fabrice Bellard's avatar
Fabrice Bellard committed
1584 1585 1586 1587
            break;
        stream = stream->next;
    }
    if (stream == NULL) {
1588
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1589
        http_log("File '%s' not found\n", url);
Fabrice Bellard's avatar
Fabrice Bellard committed
1590 1591
        goto send_error;
    }
1592

1593 1594 1595 1596 1597 1598 1599
    c->stream = stream;
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));

    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
        c->http_error = 301;
        q = c->buffer;
1600
        snprintf(q, c->buffer_size,
1601 1602 1603 1604 1605 1606 1607
                      "HTTP/1.0 301 Moved\r\n"
                      "Location: %s\r\n"
                      "Content-type: text/html\r\n"
                      "\r\n"
                      "<html><head><title>Moved</title></head><body>\r\n"
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1608
        q += strlen(q);
1609 1610 1611 1612 1613 1614 1615
        /* prepare output buffer */
        c->buffer_ptr = c->buffer;
        c->buffer_end = q;
        c->state = HTTPSTATE_SEND_HEADER;
        return 0;
    }

1616 1617
    /* If this is WMP, get the rate information */
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1618
        if (modify_current_stream(c, ratebuf)) {
1619
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1620
                if (c->switch_feed_streams[i] >= 0)
Reinhard Tartler's avatar
Reinhard Tartler committed
1621
                    c->switch_feed_streams[i] = -1;
1622 1623
            }
        }
1624 1625
    }

1626 1627 1628
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
        current_bandwidth += stream->bandwidth;

Diego Biurrun's avatar
Diego Biurrun committed
1629
    /* If already streaming this feed, do not let start another feeder. */
1630 1631
    if (stream->feed_opened) {
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1632
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1633 1634 1635
        goto send_error;
    }

1636
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1637
        c->http_error = 503;
1638
        q = c->buffer;
1639
        snprintf(q, c->buffer_size,
1640
                      "HTTP/1.0 503 Server too busy\r\n"
1641 1642 1643 1644
                      "Content-type: text/html\r\n"
                      "\r\n"
                      "<html><head><title>Too busy</title></head><body>\r\n"
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1645 1646
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1647
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1648
        q += strlen(q);
1649 1650 1651 1652 1653 1654
        /* prepare output buffer */
        c->buffer_ptr = c->buffer;
        c->buffer_end = q;
        c->state = HTTPSTATE_SEND_HEADER;
        return 0;
    }
1655

1656
    if (redir_type != REDIR_NONE) {
1657
        const char *hostinfo = 0;
1658

1659
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1660
            if (av_strncasecmp(p, "Host:", 5) == 0) {
1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
                hostinfo = p + 5;
                break;
            }
            p = strchr(p, '\n');
            if (!p)
                break;

            p++;
        }

        if (hostinfo) {
            char *eoh;
            char hostbuf[260];

1675
            while (av_isspace(*hostinfo))
1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
                hostinfo++;

            eoh = strchr(hostinfo, '\n');
            if (eoh) {
                if (eoh[-1] == '\r')
                    eoh--;

                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
                    hostbuf[eoh - hostinfo] = 0;

                    c->http_error = 200;
                    q = c->buffer;
1689 1690
                    switch(redir_type) {
                    case REDIR_ASX:
1691
                        snprintf(q, c->buffer_size,
1692 1693 1694 1695 1696 1697 1698
                                      "HTTP/1.0 200 ASX Follows\r\n"
                                      "Content-type: video/x-ms-asf\r\n"
                                      "\r\n"
                                      "<ASX Version=\"3\">\r\n"
                                      //"<!-- Autogenerated by ffserver -->\r\n"
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
                                      "</ASX>\r\n", hostbuf, filename, info);
1699
                        q += strlen(q);
1700 1701
                        break;
                    case REDIR_RAM:
1702
                        snprintf(q, c->buffer_size,
1703 1704 1705 1706 1707
                                      "HTTP/1.0 200 RAM Follows\r\n"
                                      "Content-type: audio/x-pn-realaudio\r\n"
                                      "\r\n"
                                      "# Autogenerated by ffserver\r\n"
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1708
                        q += strlen(q);
1709 1710
                        break;
                    case REDIR_ASF:
1711
                        snprintf(q, c->buffer_size,
1712 1713 1714 1715 1716
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
                                      "Content-type: video/x-ms-asf\r\n"
                                      "\r\n"
                                      "[Reference]\r\n"
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1717
                        q += strlen(q);
1718 1719 1720 1721 1722
                        break;
                    case REDIR_RTSP:
                        {
                            char hostname[256], *p;
                            /* extract only hostname */
1723
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1724 1725 1726
                            p = strrchr(hostname, ':');
                            if (p)
                                *p = '\0';
1727
                            snprintf(q, c->buffer_size,
1728
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1729
                                          /* XXX: incorrect MIME type ? */
1730 1731 1732
                                          "Content-type: application/x-rtsp\r\n"
                                          "\r\n"
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1733
                            q += strlen(q);
1734 1735 1736 1737
                        }
                        break;
                    case REDIR_SDP:
                        {
1738
                            uint8_t *sdp_data;
1739 1740
                            int sdp_data_size;
                            socklen_t len;
1741 1742
                            struct sockaddr_in my_addr;

1743
                            snprintf(q, c->buffer_size,
1744 1745 1746
                                          "HTTP/1.0 200 OK\r\n"
                                          "Content-type: application/sdp\r\n"
                                          "\r\n");
1747
                            q += strlen(q);
1748 1749 1750

                            len = sizeof(my_addr);
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1751

1752
                            /* XXX: should use a dynamic buffer */
1753 1754
                            sdp_data_size = prepare_sdp_description(stream,
                                                                    &sdp_data,
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
                                                                    my_addr.sin_addr);
                            if (sdp_data_size > 0) {
                                memcpy(q, sdp_data, sdp_data_size);
                                q += sdp_data_size;
                                *q = '\0';
                                av_free(sdp_data);
                            }
                        }
                        break;
                    default:
1765
                        abort();
1766
                        break;
1767
                    }
1768 1769 1770 1771 1772 1773 1774 1775 1776 1777

                    /* prepare output buffer */
                    c->buffer_ptr = c->buffer;
                    c->buffer_end = q;
                    c->state = HTTPSTATE_SEND_HEADER;
                    return 0;
                }
            }
        }

1778
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1779
        goto send_error;
Fabrice Bellard's avatar
Fabrice Bellard committed
1780 1781
    }

1782
    stream->conns_served++;
1783

Fabrice Bellard's avatar
Fabrice Bellard committed
1784 1785
    /* XXX: add there authenticate and IP match */

1786
    if (c->post) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1787 1788
        /* if post, it means a feed is being sent */
        if (!stream->is_feed) {
Diego Biurrun's avatar
Diego Biurrun committed
1789
            /* However it might be a status report from WMP! Let us log the
1790
             * data as it might come handy one day. */
1791
            const char *logline = 0;
1792
            int client_id = 0;
1793

1794
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1795
                if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1796 1797 1798
                    logline = p;
                    break;
                }
1799
                if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1800
                    client_id = strtol(p + 18, 0, 10);
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
                p = strchr(p, '\n');
                if (!p)
                    break;

                p++;
            }

            if (logline) {
                char *eol = strchr(logline, '\n');

                logline += 17;

                if (eol) {
                    if (eol[-1] == '\r')
                        eol--;
Falk Hüffner's avatar
Falk Hüffner committed
1816
                    http_log("%.*s\n", (int) (eol - logline), logline);
1817 1818 1819
                    c->suppress_log = 1;
                }
            }
1820

1821
#ifdef DEBUG
1822
            http_log("\nGot request:\n%s\n", c->buffer);
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
#endif

            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
                HTTPContext *wmpc;

                /* Now we have to find the client_id */
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
                    if (wmpc->wmp_client_id == client_id)
                        break;
                }

1834 1835
                if (wmpc && modify_current_stream(wmpc, ratebuf))
                    wmpc->switch_pending = 1;
1836
            }
1837

1838
            snprintf(msg, sizeof(msg), "POST command not handled");
1839
            c->stream = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1840 1841 1842
            goto send_error;
        }
        if (http_start_receive_data(c) < 0) {
1843
            snprintf(msg, sizeof(msg), "could not open feed");
Fabrice Bellard's avatar
Fabrice Bellard committed
1844 1845 1846 1847 1848 1849 1850
            goto send_error;
        }
        c->http_error = 0;
        c->state = HTTPSTATE_RECEIVE_DATA;
        return 0;
    }

1851
#ifdef DEBUG
1852
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1853
        http_log("\nGot request:\n%s\n", c->buffer);
1854 1855
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
1856
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1857
        goto send_status;
Fabrice Bellard's avatar
Fabrice Bellard committed
1858 1859 1860

    /* open input stream */
    if (open_input_stream(c, info) < 0) {
1861
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
Fabrice Bellard's avatar
Fabrice Bellard committed
1862 1863 1864
        goto send_error;
    }

1865
    /* prepare HTTP header */
1866 1867
    c->buffer[0] = 0;
    av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
1868 1869
    mime_type = c->stream->fmt->mime_type;
    if (!mime_type)
1870
        mime_type = "application/x-octet-stream";
1871
    av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
1872 1873

    /* for asf, we need extra headers */
1874
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1875 1876
        /* Need to allocate a client id */

1877
        c->wmp_client_id = av_lfg_get(&random_state);
1878

1879
        av_strlcatf(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);
Fabrice Bellard's avatar
Fabrice Bellard committed
1880
    }
1881 1882 1883
    av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
    av_strlcatf(c->buffer, c->buffer_size, "\r\n");
    q = c->buffer + strlen(c->buffer);
1884

Fabrice Bellard's avatar
Fabrice Bellard committed
1885 1886 1887 1888 1889 1890 1891 1892 1893
    /* prepare output buffer */
    c->http_error = 0;
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
 send_error:
    c->http_error = 404;
    q = c->buffer;
1894
    htmlstrip(msg);
1895
    snprintf(q, c->buffer_size,
1896 1897 1898
                  "HTTP/1.0 404 Not Found\r\n"
                  "Content-type: text/html\r\n"
                  "\r\n"
1899 1900 1901 1902
                  "<html>\n"
                  "<head><title>404 Not Found</title></head>\n"
                  "<body>%s</body>\n"
                  "</html>\n", msg);
1903
    q += strlen(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
1904 1905 1906 1907 1908
    /* prepare output buffer */
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
1909 1910
 send_status:
    compute_status(c);
Fabrice Bellard's avatar
Fabrice Bellard committed
1911 1912 1913 1914 1915 1916
    c->http_error = 200; /* horrible : we use this value to avoid
                            going to the send data state */
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
}

1917
static void fmt_bytecount(AVIOContext *pb, int64_t count)
1918
{
1919
    static const char suffix[] = " kMGTP";
1920 1921
    const char *s;

1922
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1923

1924
    avio_printf(pb, "%"PRId64"%c", count, *s);
1925 1926
}

1927
static void compute_status(HTTPContext *c)
Fabrice Bellard's avatar
Fabrice Bellard committed
1928 1929 1930
{
    HTTPContext *c1;
    FFStream *stream;
1931
    char *p;
Fabrice Bellard's avatar
Fabrice Bellard committed
1932
    time_t ti;
1933
    int i, len;
1934
    AVIOContext *pb;
1935

1936
    if (avio_open_dyn_buf(&pb) < 0) {
1937
        /* XXX: return an error ? */
1938
        c->buffer_ptr = c->buffer;
1939 1940
        c->buffer_end = c->buffer;
        return;
1941
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1942

1943
    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1944
    avio_printf(pb, "Content-type: text/html\r\n");
1945 1946
    avio_printf(pb, "Pragma: no-cache\r\n");
    avio_printf(pb, "\r\n");
1947

1948
    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1949
    if (c->stream->feed_filename[0])
1950 1951 1952
        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
    avio_printf(pb, "</head>\n<body>");
    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
Fabrice Bellard's avatar
Fabrice Bellard committed
1953
    /* format status */
1954 1955 1956
    avio_printf(pb, "<h2>Available Streams</h2>\n");
    avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
    avio_printf(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");
Fabrice Bellard's avatar
Fabrice Bellard committed
1957 1958
    stream = first_stream;
    while (stream != NULL) {
1959 1960 1961
        char sfilename[1024];
        char *eosf;

1962
        if (stream->feed != stream) {
1963
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1964 1965
            eosf = sfilename + strlen(sfilename);
            if (eosf - sfilename >= 4) {
1966
                if (strcmp(eosf - 4, ".asf") == 0)
1967
                    strcpy(eosf - 4, ".asx");
1968
                else if (strcmp(eosf - 3, ".rm") == 0)
1969
                    strcpy(eosf - 3, ".ram");
1970
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1971 1972 1973
                    /* generate a sample RTSP director if
                       unicast. Generate an SDP redirector if
                       multicast */
1974 1975 1976
                    eosf = strrchr(sfilename, '.');
                    if (!eosf)
                        eosf = sfilename + strlen(sfilename);
1977 1978 1979 1980
                    if (stream->is_multicast)
                        strcpy(eosf, ".sdp");
                    else
                        strcpy(eosf, ".rtsp");
1981
                }
1982
            }
1983

1984
            avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1985
                         sfilename, stream->filename);
1986
            avio_printf(pb, "<td align=right> %d <td align=right> ",
1987
                        stream->conns_served);
1988
            fmt_bytecount(pb, stream->bytes_served);
1989
            switch(stream->stream_type) {
1990
            case STREAM_TYPE_LIVE: {
1991 1992
                    int audio_bit_rate = 0;
                    int video_bit_rate = 0;
Zdenek Kabelac's avatar
Zdenek Kabelac committed
1993 1994 1995 1996
                    const char *audio_codec_name = "";
                    const char *video_codec_name = "";
                    const char *audio_codec_name_extra = "";
                    const char *video_codec_name_extra = "";
1997 1998 1999

                    for(i=0;i<stream->nb_streams;i++) {
                        AVStream *st = stream->streams[i];
2000 2001
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
                        switch(st->codec->codec_type) {
2002
                        case AVMEDIA_TYPE_AUDIO:
2003
                            audio_bit_rate += st->codec->bit_rate;
2004 2005 2006 2007 2008 2009
                            if (codec) {
                                if (*audio_codec_name)
                                    audio_codec_name_extra = "...";
                                audio_codec_name = codec->name;
                            }
                            break;
2010
                        case AVMEDIA_TYPE_VIDEO:
2011
                            video_bit_rate += st->codec->bit_rate;
2012 2013 2014 2015 2016 2017
                            if (codec) {
                                if (*video_codec_name)
                                    video_codec_name_extra = "...";
                                video_codec_name = codec->name;
                            }
                            break;
2018
                        case AVMEDIA_TYPE_DATA:
2019
                            video_bit_rate += st->codec->bit_rate;
2020
                            break;
2021
                        default:
2022
                            abort();
2023
                        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2024
                    }
2025
                    avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
2026
                                 stream->fmt->name,
2027
                                 stream->bandwidth,
2028 2029
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2030
                    if (stream->feed)
2031
                        avio_printf(pb, "<td>%s", stream->feed->filename);
2032
                    else
2033 2034
                        avio_printf(pb, "<td>%s", stream->feed_filename);
                    avio_printf(pb, "\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2035
                }
2036 2037
                break;
            default:
2038
                avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2039
                break;
Fabrice Bellard's avatar
Fabrice Bellard committed
2040 2041 2042 2043
            }
        }
        stream = stream->next;
    }
2044
    avio_printf(pb, "</table>\n");
2045 2046 2047 2048

    stream = first_stream;
    while (stream != NULL) {
        if (stream->feed == stream) {
2049
            avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2050
            if (stream->pid) {
2051
                avio_printf(pb, "Running as pid %d.\n", stream->pid);
2052

2053
#if defined(linux)
2054 2055 2056 2057 2058
                {
                    FILE *pid_stat;
                    char ps_cmd[64];

                    /* This is somewhat linux specific I guess */
2059 2060
                    snprintf(ps_cmd, sizeof(ps_cmd),
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2061
                             stream->pid);
2062

2063 2064 2065 2066
                    pid_stat = popen(ps_cmd, "r");
                    if (pid_stat) {
                        char cpuperc[10];
                        char cpuused[64];
2067

2068
                        if (fscanf(pid_stat, "%9s %63s", cpuperc,
2069
                                   cpuused) == 2) {
2070
                            avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2071 2072 2073
                                         cpuperc, cpuused);
                        }
                        fclose(pid_stat);
2074 2075 2076 2077
                    }
                }
#endif

2078
                avio_printf(pb, "<p>");
2079
            }
2080
            avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
2081 2082 2083

            for (i = 0; i < stream->nb_streams; i++) {
                AVStream *st = stream->streams[i];
2084
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2085
                const char *type = "unknown";
2086 2087 2088
                char parameters[64];

                parameters[0] = 0;
2089

2090
                switch(st->codec->codec_type) {
2091
                case AVMEDIA_TYPE_AUDIO:
2092
                    type = "audio";
2093
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2094
                    break;
2095
                case AVMEDIA_TYPE_VIDEO:
2096
                    type = "video";
2097 2098
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2099 2100
                    break;
                default:
2101
                    abort();
2102
                }
2103
                avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2104
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2105
            }
2106
            avio_printf(pb, "</table>\n");
2107

2108
        }
2109 2110
        stream = stream->next;
    }
2111

Fabrice Bellard's avatar
Fabrice Bellard committed
2112
    /* connection status */
2113
    avio_printf(pb, "<h2>Connection Status</h2>\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2114

2115
    avio_printf(pb, "Number of connections: %d / %d<br>\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
2116 2117
                 nb_connections, nb_max_connections);

2118
    avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2119
                 current_bandwidth, max_bandwidth);
2120

2121 2122
    avio_printf(pb, "<table>\n");
    avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2123 2124
    c1 = first_http_ctx;
    i = 0;
2125
    while (c1 != NULL) {
2126 2127 2128 2129
        int bitrate;
        int j;

        bitrate = 0;
2130 2131
        if (c1->stream) {
            for (j = 0; j < c1->stream->nb_streams; j++) {
2132
                if (!c1->stream->feed)
2133
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2134 2135
                else if (c1->feed_streams[j] >= 0)
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2136 2137 2138
            }
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2139 2140
        i++;
        p = inet_ntoa(c1->from_addr.sin_addr);
2141
        avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2142 2143
                    i,
                    c1->stream ? c1->stream->filename : "",
2144
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2145
                    p,
2146 2147 2148
                    c1->protocol,
                    http_state[c1->state]);
        fmt_bytecount(pb, bitrate);
2149
        avio_printf(pb, "<td align=right>");
2150
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2151
        avio_printf(pb, "<td align=right>");
2152
        fmt_bytecount(pb, c1->data_count);
2153
        avio_printf(pb, "\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2154 2155
        c1 = c1->next;
    }
2156
    avio_printf(pb, "</table>\n");
2157

Fabrice Bellard's avatar
Fabrice Bellard committed
2158 2159 2160
    /* date */
    ti = time(NULL);
    p = ctime(&ti);
2161 2162
    avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
    avio_printf(pb, "</body>\n</html>\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2163

2164
    len = avio_close_dyn_buf(pb, &c->pb_buffer);
2165 2166
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
Fabrice Bellard's avatar
Fabrice Bellard committed
2167 2168 2169 2170 2171 2172
}

static int open_input_stream(HTTPContext *c, const char *info)
{
    char buf[128];
    char input_filename[1024];
2173
    AVFormatContext *s = NULL;
2174
    int buf_size, i, ret;
2175
    int64_t stream_pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
2176 2177 2178 2179

    /* find file name */
    if (c->stream->feed) {
        strcpy(input_filename, c->stream->feed->feed_filename);
2180
        buf_size = FFM_PACKET_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
2181
        /* compute position (absolute time) */
2182
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2183 2184
            if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
                http_log("Invalid date specification '%s' for stream\n", buf);
2185
                return ret;
2186
            }
2187
        } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2188
            int prebuffer = strtol(buf, 0, 10);
2189
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2190
        } else
2191
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
2192 2193
    } else {
        strcpy(input_filename, c->stream->feed_filename);
2194
        buf_size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2195
        /* compute position (relative time) */
2196
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2197 2198
            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
                http_log("Invalid date specification '%s' for stream\n", buf);
2199
                return ret;
2200
            }
2201
        } else
Fabrice Bellard's avatar
Fabrice Bellard committed
2202 2203
            stream_pos = 0;
    }
2204 2205 2206 2207
    if (!input_filename[0]) {
        http_log("No filename was specified for stream\n");
        return AVERROR(EINVAL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2208 2209

    /* open stream */
2210
    if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2211 2212
        http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
        return ret;
2213
    }
2214 2215 2216 2217

    /* set buffer size */
    if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);

2218
    s->flags |= AVFMT_FLAG_GENPTS;
Fabrice Bellard's avatar
Fabrice Bellard committed
2219
    c->fmt_in = s;
2220 2221 2222
    if (strcmp(s->iformat->name, "ffm") &&
        (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
        http_log("Could not find stream info for input '%s'\n", input_filename);
2223
        avformat_close_input(&s);
2224
        return ret;
2225
    }
2226

2227 2228
    /* choose stream as clock source (we favor the video stream if
     * present) for packet sending */
2229 2230
    c->pts_stream_index = 0;
    for(i=0;i<c->stream->nb_streams;i++) {
2231
        if (c->pts_stream_index == 0 &&
2232
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2233 2234 2235
            c->pts_stream_index = i;
        }
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2236

2237
    if (c->fmt_in->iformat->read_seek)
2238
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2239 2240 2241
    /* set the start time (needed for maxtime and RTP packet timing) */
    c->start_time = cur_time;
    c->first_pts = AV_NOPTS_VALUE;
Fabrice Bellard's avatar
Fabrice Bellard committed
2242 2243 2244
    return 0;
}

2245 2246
/* return the server clock (in us) */
static int64_t get_server_clock(HTTPContext *c)
2247
{
2248
    /* compute current pts value from system time */
2249
    return (cur_time - c->start_time) * 1000;
2250 2251
}

2252 2253 2254
/* return the estimated time at which the current packet must be sent
   (in us) */
static int64_t get_packet_send_clock(HTTPContext *c)
2255
{
2256
    int bytes_left, bytes_sent, frame_bytes;
2257

2258
    frame_bytes = c->cur_frame_bytes;
2259
    if (frame_bytes <= 0)
2260
        return c->cur_pts;
2261
    else {
2262 2263 2264
        bytes_left = c->buffer_end - c->buffer_ptr;
        bytes_sent = frame_bytes - bytes_left;
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2265 2266 2267 2268 2269 2270 2271 2272 2273
    }
}


static int http_prepare_data(HTTPContext *c)
{
    int i, len, ret;
    AVFormatContext *ctx;

2274
    av_freep(&c->pb_buffer);
2275 2276
    switch(c->state) {
    case HTTPSTATE_SEND_DATA_HEADER:
2277 2278 2279
        ctx = avformat_alloc_context();
        c->fmt_ctx = *ctx;
        av_freep(&ctx);
2280
        av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2281 2282
        c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);

2283
        for(i=0;i<c->stream->nb_streams;i++) {
2284
            AVStream *src;
2285
            c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2286
            /* if file or feed, then just take streams from FFStream struct */
2287
            if (!c->stream->feed ||
2288
                c->stream->feed == c->stream)
2289
                src = c->stream->streams[i];
2290
            else
2291 2292
                src = c->stream->feed->streams[c->stream->feed_streams[i]];

2293 2294
            *(c->fmt_ctx.streams[i]) = *src;
            c->fmt_ctx.streams[i]->priv_data = 0;
2295 2296
            /* XXX: should be done in AVStream, not in codec */
            c->fmt_ctx.streams[i]->codec->frame_number = 0;
2297
        }
2298 2299 2300 2301
        /* set output format parameters */
        c->fmt_ctx.oformat = c->stream->fmt;
        c->fmt_ctx.nb_streams = c->stream->nb_streams;

2302 2303 2304
        c->got_key_frame = 0;

        /* prepare header and save header data in a stream */
2305
        if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2306 2307 2308
            /* XXX: potential leak */
            return -1;
        }
2309
        c->fmt_ctx.pb->seekable = 0;
2310

2311
        /*
2312
         * HACK to avoid MPEG-PS muxer to spit many underflow errors
2313
         * Default value from FFmpeg
2314
         * Try to set it using configuration option
2315 2316 2317
         */
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);

2318 2319 2320 2321
        if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
            http_log("Error writing output header for stream '%s': %s\n",
                     c->stream->filename, av_err2str(ret));
            return ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2322
        }
2323
        av_dict_free(&c->fmt_ctx.metadata);
2324

2325
        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2326 2327 2328 2329
        c->buffer_ptr = c->pb_buffer;
        c->buffer_end = c->pb_buffer + len;

        c->state = HTTPSTATE_SEND_DATA;
Fabrice Bellard's avatar
Fabrice Bellard committed
2330 2331 2332 2333
        c->last_packet_sent = 0;
        break;
    case HTTPSTATE_SEND_DATA:
        /* find a new packet */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346
        /* read a packet from the input stream */
        if (c->stream->feed)
            ffm_set_write_index(c->fmt_in,
                                c->stream->feed->feed_write_index,
                                c->stream->feed->feed_size);

        if (c->stream->max_time &&
            c->stream->max_time + c->start_time - cur_time < 0)
            /* We have timed out */
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
        else {
            AVPacket pkt;
        redo:
2347 2348 2349
            ret = av_read_frame(c->fmt_in, &pkt);
            if (ret < 0) {
                if (c->stream->feed) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2350 2351 2352 2353
                    /* if coming from feed, it means we reached the end of the
                       ffm file, so must wait for more data */
                    c->state = HTTPSTATE_WAIT_FEED;
                    return 1; /* state changed */
2354 2355 2356
                } else if (ret == AVERROR(EAGAIN)) {
                    /* input not ready, come back later */
                    return 0;
2357
                } else {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2358
                    if (c->stream->loop) {
2359
                        avformat_close_input(&c->fmt_in);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2360 2361 2362 2363 2364
                        if (open_input_stream(c, "") < 0)
                            goto no_loop;
                        goto redo;
                    } else {
                    no_loop:
2365
                        /* must send trailer now because EOF or error */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2366
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2367
                    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2368 2369
                }
            } else {
2370
                int source_index = pkt.stream_index;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
                /* update first pts if needed */
                if (c->first_pts == AV_NOPTS_VALUE) {
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
                    c->start_time = cur_time;
                }
                /* send it to the appropriate stream */
                if (c->stream->feed) {
                    /* if coming from a feed, select the right stream */
                    if (c->switch_pending) {
                        c->switch_pending = 0;
2381
                        for(i=0;i<c->stream->nb_streams;i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2382
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2383
                                if (pkt.flags & AV_PKT_FLAG_KEY)
Reinhard Tartler's avatar
Reinhard Tartler committed
2384
                                    c->switch_feed_streams[i] = -1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2385 2386
                            if (c->switch_feed_streams[i] >= 0)
                                c->switch_pending = 1;
2387
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2388 2389
                    }
                    for(i=0;i<c->stream->nb_streams;i++) {
2390
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2391
                            AVStream *st = c->fmt_in->streams[source_index];
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2392
                            pkt.stream_index = i;
2393
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2394
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2395
                                 c->stream->nb_streams == 1))
2396 2397
                                c->got_key_frame = 1;
                            if (!c->stream->send_on_key || c->got_key_frame)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2398 2399 2400 2401 2402
                                goto send_it;
                        }
                    }
                } else {
                    AVCodecContext *codec;
2403 2404 2405
                    AVStream *ist, *ost;
                send_it:
                    ist = c->fmt_in->streams[source_index];
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2406
                    /* specific handling for RTP: we use several
2407 2408
                     * output streams (one for each RTP connection).
                     * XXX: need more abstract handling */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2409 2410
                    if (c->is_packetized) {
                        /* compute send time and duration */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2411
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2412
                        c->cur_pts -= c->first_pts;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2413
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2414 2415 2416 2417
                        /* find RTP context */
                        c->packet_stream_index = pkt.stream_index;
                        ctx = c->rtp_ctx[c->packet_stream_index];
                        if(!ctx) {
2418
                            av_free_packet(&pkt);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2419
                            break;
2420
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2421 2422 2423 2424 2425 2426
                        codec = ctx->streams[0]->codec;
                        /* only one stream per RTP connection */
                        pkt.stream_index = 0;
                    } else {
                        ctx = &c->fmt_ctx;
                        /* Fudge here */
2427
                        codec = ctx->streams[pkt.stream_index]->codec;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2428 2429 2430 2431
                    }

                    if (c->is_packetized) {
                        int max_packet_size;
2432
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2433 2434
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
                        else
2435
                            max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2436
                        ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2437
                    } else {
2438
                        ret = avio_open_dyn_buf(&ctx->pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2439 2440 2441 2442 2443
                    }
                    if (ret < 0) {
                        /* XXX: potential leak */
                        return -1;
                    }
2444 2445
                    ost = ctx->streams[pkt.stream_index];

2446
                    ctx->pb->seekable = 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2447
                    if (pkt.dts != AV_NOPTS_VALUE)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2448
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2449
                    if (pkt.pts != AV_NOPTS_VALUE)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2450 2451
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2452 2453 2454
                    if ((ret = av_write_frame(ctx, &pkt)) < 0) {
                        http_log("Error writing frame to output for stream '%s': %s\n",
                                 c->stream->filename, av_err2str(ret));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2455
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2456
                    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2457

2458
                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2459 2460 2461 2462 2463 2464 2465 2466
                    c->cur_frame_bytes = len;
                    c->buffer_ptr = c->pb_buffer;
                    c->buffer_end = c->pb_buffer + len;

                    codec->frame_number++;
                    if (len == 0) {
                        av_free_packet(&pkt);
                        goto redo;
2467
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2468
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2469
                av_free_packet(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2470
            }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2471
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2472 2473 2474 2475
        break;
    default:
    case HTTPSTATE_SEND_DATA_TRAILER:
        /* last packet test ? */
2476
        if (c->last_packet_sent || c->is_packetized)
Fabrice Bellard's avatar
Fabrice Bellard committed
2477
            return -1;
2478
        ctx = &c->fmt_ctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2479
        /* prepare header */
2480
        if (avio_open_dyn_buf(&ctx->pb) < 0) {
2481 2482 2483
            /* XXX: potential leak */
            return -1;
        }
2484
        c->fmt_ctx.pb->seekable = 0;
2485
        av_write_trailer(ctx);
2486
        len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2487 2488 2489
        c->buffer_ptr = c->pb_buffer;
        c->buffer_end = c->pb_buffer + len;

Fabrice Bellard's avatar
Fabrice Bellard committed
2490 2491 2492 2493 2494 2495 2496
        c->last_packet_sent = 1;
        break;
    }
    return 0;
}

/* should convert the format at the same time */
2497
/* send data starting at c->buffer_ptr to the output connection
2498
 * (either UDP or TCP) */
2499
static int http_send_data(HTTPContext *c)
Fabrice Bellard's avatar
Fabrice Bellard committed
2500
{
2501
    int len, ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2502

2503 2504 2505 2506 2507
    for(;;) {
        if (c->buffer_ptr >= c->buffer_end) {
            ret = http_prepare_data(c);
            if (ret < 0)
                return -1;
2508
            else if (ret != 0)
2509 2510
                /* state change requested */
                break;
2511
        } else {
2512 2513 2514 2515 2516 2517 2518
            if (c->is_packetized) {
                /* RTP data output */
                len = c->buffer_end - c->buffer_ptr;
                if (len < 4) {
                    /* fail safe - should never happen */
                fail1:
                    c->buffer_ptr = c->buffer_end;
2519 2520
                    return 0;
                }
2521 2522 2523 2524 2525 2526
                len = (c->buffer_ptr[0] << 24) |
                    (c->buffer_ptr[1] << 16) |
                    (c->buffer_ptr[2] << 8) |
                    (c->buffer_ptr[3]);
                if (len > (c->buffer_end - c->buffer_ptr))
                    goto fail1;
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
                    /* nothing to send yet: we can wait */
                    return 0;
                }

                c->data_count += len;
                update_datarate(&c->datarate, c->data_count);
                if (c->stream)
                    c->stream->bytes_served += len;

2537
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2538
                    /* RTP packets are sent inside the RTSP TCP connection */
2539
                    AVIOContext *pb;
2540 2541 2542
                    int interleaved_index, size;
                    uint8_t header[4];
                    HTTPContext *rtsp_c;
2543

2544 2545 2546 2547 2548
                    rtsp_c = c->rtsp_c;
                    /* if no RTSP connection left, error */
                    if (!rtsp_c)
                        return -1;
                    /* if already sending something, then wait. */
2549
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2550
                        break;
2551
                    if (avio_open_dyn_buf(&pb) < 0)
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
                        goto fail1;
                    interleaved_index = c->packet_stream_index * 2;
                    /* RTCP packets are sent at odd indexes */
                    if (c->buffer_ptr[1] == 200)
                        interleaved_index++;
                    /* write RTSP TCP header */
                    header[0] = '$';
                    header[1] = interleaved_index;
                    header[2] = len >> 8;
                    header[3] = len;
2562
                    avio_write(pb, header, 4);
2563 2564
                    /* write RTP packet data */
                    c->buffer_ptr += 4;
2565
                    avio_write(pb, c->buffer_ptr, len);
2566
                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
2567 2568 2569
                    /* prepare asynchronous TCP sending */
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2570
                    c->buffer_ptr += len;
2571

2572
                    /* send everything we can NOW */
2573 2574
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2575
                    if (len > 0)
2576 2577 2578 2579 2580 2581 2582
                        rtsp_c->packet_buffer_ptr += len;
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
                        /* if we could not send all the data, we will
                           send it later, so a new state is needed to
                           "lock" the RTSP TCP connection */
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
                        break;
2583
                    } else
2584 2585 2586 2587
                        /* all data has been sent */
                        av_freep(&c->packet_buffer);
                } else {
                    /* send RTP packet directly in UDP */
2588
                    c->buffer_ptr += 4;
2589 2590
                    ffurl_write(c->rtp_handles[c->packet_stream_index],
                                c->buffer_ptr, len);
2591 2592
                    c->buffer_ptr += len;
                    /* here we continue as we can send several packets per 10 ms slot */
2593 2594 2595
                }
            } else {
                /* TCP data output */
2596
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2597
                if (len < 0) {
2598 2599
                    if (ff_neterrno() != AVERROR(EAGAIN) &&
                        ff_neterrno() != AVERROR(EINTR))
2600 2601
                        /* error : close connection */
                        return -1;
2602
                    else
2603
                        return 0;
2604
                } else
2605
                    c->buffer_ptr += len;
2606

2607 2608 2609 2610 2611
                c->data_count += len;
                update_datarate(&c->datarate, c->data_count);
                if (c->stream)
                    c->stream->bytes_served += len;
                break;
2612
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2613
        }
2614
    } /* for(;;) */
Fabrice Bellard's avatar
Fabrice Bellard committed
2615 2616 2617 2618 2619 2620
    return 0;
}

static int http_start_receive_data(HTTPContext *c)
{
    int fd;
2621
    int ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2622

2623 2624 2625 2626
    if (c->stream->feed_opened) {
        http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
        return AVERROR(EINVAL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2627

2628
    /* Don't permit writing to this one */
2629 2630 2631 2632
    if (c->stream->readonly) {
        http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
        return AVERROR(EINVAL);
    }
2633

Fabrice Bellard's avatar
Fabrice Bellard committed
2634 2635
    /* open feed */
    fd = open(c->stream->feed_filename, O_RDWR);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2636
    if (fd < 0) {
2637
        ret = AVERROR(errno);
2638
        http_log("Could not open feed file '%s': %s\n",
2639 2640
                 c->stream->feed_filename, strerror(errno));
        return ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2641
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2642
    c->feed_fd = fd;
2643

2644 2645 2646 2647
    if (c->stream->truncate) {
        /* truncate feed file */
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2648
        if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2649 2650 2651 2652
            ret = AVERROR(errno);
            http_log("Error truncating feed file '%s': %s\n",
                     c->stream->feed_filename, strerror(errno));
            return ret;
2653
        }
2654
    } else {
2655 2656 2657 2658 2659 2660 2661
        ret = ffm_read_write_index(fd);
        if (ret < 0) {
            http_log("Error reading write index from feed file '%s': %s\n",
                     c->stream->feed_filename, strerror(errno));
            return ret;
        } else {
            c->stream->feed_write_index = ret;
2662
        }
2663 2664
    }

2665
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
2666 2667 2668 2669 2670 2671 2672
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    /* init buffer input */
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
    c->stream->feed_opened = 1;
2673
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
Fabrice Bellard's avatar
Fabrice Bellard committed
2674 2675
    return 0;
}
2676

Fabrice Bellard's avatar
Fabrice Bellard committed
2677 2678 2679
static int http_receive_data(HTTPContext *c)
{
    HTTPContext *c1;
2680
    int len, loop_run = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2681

2682 2683 2684 2685 2686 2687
    while (c->chunked_encoding && !c->chunk_size &&
           c->buffer_end > c->buffer_ptr) {
        /* read chunk header, if present */
        len = recv(c->fd, c->buffer_ptr, 1, 0);

        if (len < 0) {
2688 2689
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
2690 2691
                /* error : close connection */
                goto fail;
2692
            return 0;
2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709
        } else if (len == 0) {
            /* end of connection : close it */
            goto fail;
        } else if (c->buffer_ptr - c->buffer >= 2 &&
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
            c->chunk_size = strtol(c->buffer, 0, 16);
            if (c->chunk_size == 0) // end of stream
                goto fail;
            c->buffer_ptr = c->buffer;
            break;
        } else if (++loop_run > 10) {
            /* no chunk header, abort */
            goto fail;
        } else {
            c->buffer_ptr++;
        }
    }
2710

2711 2712 2713
    if (c->buffer_end > c->buffer_ptr) {
        len = recv(c->fd, c->buffer_ptr,
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2714
        if (len < 0) {
2715 2716
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
2717 2718
                /* error : close connection */
                goto fail;
2719
        } else if (len == 0)
2720 2721
            /* end of connection : close it */
            goto fail;
2722
        else {
2723
            c->chunk_size -= len;
2724 2725
            c->buffer_ptr += len;
            c->data_count += len;
2726
            update_datarate(&c->datarate, c->data_count);
2727 2728 2729
        }
    }

2730 2731 2732 2733 2734 2735 2736 2737
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
        if (c->buffer[0] != 'f' ||
            c->buffer[1] != 'm') {
            http_log("Feed stream has become desynchronized -- disconnecting\n");
            goto fail;
        }
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
2738
    if (c->buffer_ptr >= c->buffer_end) {
2739
        FFStream *feed = c->stream;
Fabrice Bellard's avatar
Fabrice Bellard committed
2740 2741 2742 2743 2744
        /* a packet has been received : write it in the store, except
           if header */
        if (c->data_count > FFM_PACKET_SIZE) {
            /* XXX: use llseek or url_seek */
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2745 2746 2747 2748
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
                http_log("Error writing to feed file: %s\n", strerror(errno));
                goto fail;
            }
2749

Fabrice Bellard's avatar
Fabrice Bellard committed
2750 2751 2752 2753 2754 2755
            feed->feed_write_index += FFM_PACKET_SIZE;
            /* update file size */
            if (feed->feed_write_index > c->stream->feed_size)
                feed->feed_size = feed->feed_write_index;

            /* handle wrap around if max file size reached */
2756
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
2757 2758 2759
                feed->feed_write_index = FFM_PACKET_SIZE;

            /* write index */
2760 2761 2762 2763
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
                http_log("Error writing index to feed file: %s\n", strerror(errno));
                goto fail;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2764 2765 2766

            /* wake up any waiting connections */
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2767
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2768
                    c1->stream->feed == c->stream->feed)
Fabrice Bellard's avatar
Fabrice Bellard committed
2769 2770
                    c1->state = HTTPSTATE_SEND_DATA;
            }
2771 2772
        } else {
            /* We have a header in our hands that contains useful data */
2773
            AVFormatContext *s = avformat_alloc_context();
2774
            AVIOContext *pb;
2775
            AVInputFormat *fmt_in;
2776 2777
            int i;

2778 2779 2780
            if (!s)
                goto fail;

2781 2782 2783 2784 2785
            /* use feed output format name to find corresponding input format */
            fmt_in = av_find_input_format(feed->fmt->name);
            if (!fmt_in)
                goto fail;

2786 2787
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
                                    0, NULL, NULL, NULL, NULL);
2788
            pb->seekable = 0;
2789

2790 2791
            s->pb = pb;
            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2792 2793 2794
                av_free(pb);
                goto fail;
            }
2795 2796

            /* Now we have the actual streams */
2797
            if (s->nb_streams != feed->nb_streams) {
2798
                avformat_close_input(&s);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2799
                av_free(pb);
2800 2801
                http_log("Feed '%s' stream number does not match registered feed\n",
                         c->stream->feed_filename);
2802 2803
                goto fail;
            }
2804

2805 2806 2807
            for (i = 0; i < s->nb_streams; i++) {
                AVStream *fst = feed->streams[i];
                AVStream *st = s->streams[i];
2808
                avcodec_copy_context(fst->codec, st->codec);
2809
            }
2810

2811
            avformat_close_input(&s);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2812
            av_free(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
2813 2814 2815 2816 2817 2818 2819 2820
        }
        c->buffer_ptr = c->buffer;
    }

    return 0;
 fail:
    c->stream->feed_opened = 0;
    close(c->feed_fd);
2821 2822 2823 2824 2825 2826
    /* wake up any waiting connections to stop waiting for feed */
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
        if (c1->state == HTTPSTATE_WAIT_FEED &&
            c1->stream->feed == c->stream->feed)
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2827 2828 2829
    return -1;
}

2830 2831 2832 2833 2834 2835 2836
/********************************************************************/
/* RTSP handling */

static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
{
    const char *str;
    time_t ti;
2837
    struct tm *tm;
2838 2839
    char buf2[32];

2840 2841
    str = RTSP_STATUS_CODE2STRING(error_number);
    if (!str)
2842
        str = "Unknown Error";
2843

2844 2845
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2846 2847 2848

    /* output GMT time */
    ti = time(NULL);
2849 2850
    tm = gmtime(&ti);
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2851
    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2852 2853 2854 2855 2856
}

static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
{
    rtsp_reply_header(c, error_number);
2857
    avio_printf(c->pb, "\r\n");
2858 2859 2860 2861 2862 2863 2864 2865 2866 2867
}

static int rtsp_parse_request(HTTPContext *c)
{
    const char *p, *p1, *p2;
    char cmd[32];
    char url[1024];
    char protocol[32];
    char line[1024];
    int len;
2868
    RTSPMessageHeader header1 = { 0 }, *header = &header1;
2869

2870 2871
    c->buffer_ptr[0] = '\0';
    p = c->buffer;
2872

2873 2874 2875 2876
    get_word(cmd, sizeof(cmd), &p);
    get_word(url, sizeof(url), &p);
    get_word(protocol, sizeof(protocol), &p);

2877 2878 2879
    av_strlcpy(c->method, cmd, sizeof(c->method));
    av_strlcpy(c->url, url, sizeof(c->url));
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2880

2881
    if (avio_open_dyn_buf(&c->pb) < 0) {
2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899
        /* XXX: cannot do more */
        c->pb = NULL; /* safety */
        return -1;
    }

    /* check version name */
    if (strcmp(protocol, "RTSP/1.0") != 0) {
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
        goto the_end;
    }

    /* parse each header line */
    /* skip to next line */
    while (*p != '\n' && *p != '\0')
        p++;
    if (*p == '\n')
        p++;
    while (*p != '\0') {
2900
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913
        if (!p1)
            break;
        p2 = p1;
        if (p2 > p && p2[-1] == '\r')
            p2--;
        /* skip empty line */
        if (p2 == p)
            break;
        len = p2 - p;
        if (len > sizeof(line) - 1)
            len = sizeof(line) - 1;
        memcpy(line, p, len);
        line[len] = '\0';
2914
        ff_rtsp_parse_line(header, line, NULL, NULL);
2915 2916 2917 2918 2919 2920
        p = p1 + 1;
    }

    /* handle sequence number */
    c->seq = header->seq;

2921
    if (!strcmp(cmd, "DESCRIBE"))
2922
        rtsp_cmd_describe(c, url);
2923
    else if (!strcmp(cmd, "OPTIONS"))
2924
        rtsp_cmd_options(c, url);
2925
    else if (!strcmp(cmd, "SETUP"))
2926
        rtsp_cmd_setup(c, url, header);
2927
    else if (!strcmp(cmd, "PLAY"))
2928
        rtsp_cmd_play(c, url, header);
2929
    else if (!strcmp(cmd, "PAUSE"))
2930
        rtsp_cmd_interrupt(c, url, header, 1);
2931
    else if (!strcmp(cmd, "TEARDOWN"))
2932
        rtsp_cmd_interrupt(c, url, header, 0);
2933
    else
2934
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2935

2936
 the_end:
2937
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
    c->pb = NULL; /* safety */
    if (len < 0) {
        /* XXX: cannot do more */
        return -1;
    }
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
    c->state = RTSPSTATE_SEND_REPLY;
    return 0;
}

2949
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2950
                                   struct in_addr my_ip)
2951
{
2952
    AVFormatContext *avc;
2953
    AVStream *avs = NULL;
2954
    AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2955
    AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2956
    int i;
2957

2958
    avc =  avformat_alloc_context();
2959
    if (avc == NULL || !rtp_format) {
2960
        return -1;
2961
    }
2962
    avc->oformat = rtp_format;
2963
    av_dict_set(&avc->metadata, "title",
2964
                entry ? entry->value : "No Title", 0);
2965 2966 2967 2968 2969
    avc->nb_streams = stream->nb_streams;
    if (stream->is_multicast) {
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
                 inet_ntoa(stream->multicast_ip),
                 stream->multicast_port, stream->multicast_ttl);
2970 2971
    } else {
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2972
    }
2973

2974 2975 2976 2977 2978 2979 2980
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
        goto sdp_done;
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
        goto sdp_done;

2981
    for(i = 0; i < stream->nb_streams; i++) {
2982 2983
        avc->streams[i] = &avs[i];
        avc->streams[i]->codec = stream->streams[i]->codec;
2984
    }
2985
    *pbuffer = av_mallocz(2048);
2986
    av_sdp_create(&avc, 1, *pbuffer, 2048);
2987 2988 2989

 sdp_done:
    av_free(avc->streams);
2990
    av_dict_free(&avc->metadata);
2991
    av_free(avc);
2992
    av_free(avs);
2993 2994

    return strlen(*pbuffer);
2995 2996
}

2997 2998 2999
static void rtsp_cmd_options(HTTPContext *c, const char *url)
{
//    rtsp_reply_header(c, RTSP_STATUS_OK);
3000 3001 3002 3003
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
    avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
    avio_printf(c->pb, "\r\n");
3004 3005
}

3006 3007 3008 3009 3010
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
{
    FFStream *stream;
    char path1[1024];
    const char *path;
3011
    uint8_t *content;
3012 3013
    int content_length;
    socklen_t len;
3014
    struct sockaddr_in my_addr;
3015

3016
    /* find which URL is asked */
3017
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3018 3019 3020 3021 3022
    path = path1;
    if (*path == '/')
        path++;

    for(stream = first_stream; stream != NULL; stream = stream->next) {
3023 3024
        if (!stream->is_feed &&
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3025 3026 3027 3028 3029 3030 3031 3032 3033
            !strcmp(path, stream->filename)) {
            goto found;
        }
    }
    /* no stream found */
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
    return;

 found:
3034
    /* prepare the media description in SDP format */
3035 3036 3037 3038 3039

    /* get the host IP */
    len = sizeof(my_addr);
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3040 3041 3042 3043 3044
    if (content_length < 0) {
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
        return;
    }
    rtsp_reply_header(c, RTSP_STATUS_OK);
3045 3046 3047 3048
    avio_printf(c->pb, "Content-Base: %s/\r\n", url);
    avio_printf(c->pb, "Content-Type: application/sdp\r\n");
    avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
    avio_printf(c->pb, "\r\n");
3049
    avio_write(c->pb, content, content_length);
3050
    av_free(content);
3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066
}

static HTTPContext *find_rtp_session(const char *session_id)
{
    HTTPContext *c;

    if (session_id[0] == '\0')
        return NULL;

    for(c = first_http_ctx; c != NULL; c = c->next) {
        if (!strcmp(c->session_id, session_id))
            return c;
    }
    return NULL;
}

3067
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3068 3069 3070 3071 3072 3073
{
    RTSPTransportField *th;
    int i;

    for(i=0;i<h->nb_transports;i++) {
        th = &h->transports[i];
3074
        if (th->lower_transport == lower_transport)
3075 3076 3077 3078 3079
            return th;
    }
    return NULL;
}

3080
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3081
                           RTSPMessageHeader *h)
3082 3083
{
    FFStream *stream;
3084
    int stream_index, rtp_port, rtcp_port;
3085 3086 3087 3088 3089 3090 3091
    char buf[1024];
    char path1[1024];
    const char *path;
    HTTPContext *rtp_c;
    RTSPTransportField *th;
    struct sockaddr_in dest_addr;
    RTSPActionServerSetup setup;
3092

3093
    /* find which URL is asked */
3094
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3095 3096 3097 3098 3099 3100
    path = path1;
    if (*path == '/')
        path++;

    /* now check each stream */
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3101 3102
        if (!stream->is_feed &&
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3103 3104 3105 3106 3107 3108 3109 3110 3111
            /* accept aggregate filenames only if single stream */
            if (!strcmp(path, stream->filename)) {
                if (stream->nb_streams != 1) {
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
                    return;
                }
                stream_index = 0;
                goto found;
            }
3112

3113 3114
            for(stream_index = 0; stream_index < stream->nb_streams;
                stream_index++) {
3115
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127
                         stream->filename, stream_index);
                if (!strcmp(path, buf))
                    goto found;
            }
        }
    }
    /* no stream found */
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
    return;
 found:

    /* generate session id if needed */
3128 3129 3130
    if (h->session_id[0] == '\0') {
        unsigned random0 = av_lfg_get(&random_state);
        unsigned random1 = av_lfg_get(&random_state);
3131
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3132 3133
                 random0, random1);
    }
3134

3135
    /* find RTP session, and create it if none found */
3136 3137
    rtp_c = find_rtp_session(h->session_id);
    if (!rtp_c) {
3138
        /* always prefer UDP */
3139
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3140
        if (!th) {
3141
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3142 3143 3144 3145 3146 3147 3148
            if (!th) {
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
                return;
            }
        }

        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3149
                                   th->lower_transport);
3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160
        if (!rtp_c) {
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
            return;
        }

        /* open input stream */
        if (open_input_stream(rtp_c, "") < 0) {
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
            return;
        }
    }
3161

3162 3163 3164 3165 3166 3167
    /* test if stream is OK (test needed because several SETUP needs
       to be done for a given file) */
    if (rtp_c->stream != stream) {
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
        return;
    }
3168

3169 3170 3171 3172 3173 3174 3175 3176
    /* test if stream is already set up */
    if (rtp_c->rtp_ctx[stream_index]) {
        rtsp_reply_error(c, RTSP_STATUS_STATE);
        return;
    }

    /* check transport */
    th = find_transport(h, rtp_c->rtp_protocol);
3177
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3178 3179 3180 3181 3182 3183 3184 3185 3186
                th->client_port_min <= 0)) {
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
        return;
    }

    /* setup default options */
    setup.transport_option[0] = '\0';
    dest_addr = rtp_c->from_addr;
    dest_addr.sin_port = htons(th->client_port_min);
3187

3188
    /* setup stream */
3189
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3190 3191 3192 3193 3194 3195 3196
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
        return;
    }

    /* now everything is OK, so we can send the connection parameters */
    rtsp_reply_header(c, RTSP_STATUS_OK);
    /* session ID */
3197
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3198 3199

    switch(rtp_c->rtp_protocol) {
3200
    case RTSP_LOWER_TRANSPORT_UDP:
3201 3202
        rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
        rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3203
        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3204
                    "client_port=%d-%d;server_port=%d-%d",
3205 3206
                    th->client_port_min, th->client_port_max,
                    rtp_port, rtcp_port);
3207
        break;
3208
    case RTSP_LOWER_TRANSPORT_TCP:
3209
        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3210 3211 3212 3213 3214
                    stream_index * 2, stream_index * 2 + 1);
        break;
    default:
        break;
    }
3215
    if (setup.transport_option[0] != '\0')
3216 3217
        avio_printf(c->pb, ";%s", setup.transport_option);
    avio_printf(c->pb, "\r\n");
3218

3219

3220
    avio_printf(c->pb, "\r\n");
3221 3222 3223
}


3224
/* find an RTP connection by using the session ID. Check consistency
3225
   with filename */
3226
static HTTPContext *find_rtp_session_with_url(const char *url,
3227 3228 3229 3230 3231
                                              const char *session_id)
{
    HTTPContext *rtp_c;
    char path1[1024];
    const char *path;
3232
    char buf[1024];
3233
    int s, len;
3234 3235 3236 3237 3238

    rtp_c = find_rtp_session(session_id);
    if (!rtp_c)
        return NULL;

3239
    /* find which URL is asked */
3240
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3241 3242 3243
    path = path1;
    if (*path == '/')
        path++;
3244 3245 3246 3247 3248 3249 3250 3251 3252
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
        rtp_c->stream->filename, s);
      if(!strncmp(path, buf, sizeof(buf))) {
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
        return rtp_c;
      }
    }
3253 3254 3255 3256
    len = strlen(path);
    if (len > 0 && path[len - 1] == '/' &&
        !strncmp(path, rtp_c->stream->filename, len - 1))
        return rtp_c;
3257
    return NULL;
3258 3259
}

3260
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3261 3262 3263 3264 3265 3266 3267 3268
{
    HTTPContext *rtp_c;

    rtp_c = find_rtp_session_with_url(url, h->session_id);
    if (!rtp_c) {
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
        return;
    }
3269

3270 3271 3272 3273 3274 3275 3276 3277
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
        rtp_c->state != HTTPSTATE_READY) {
        rtsp_reply_error(c, RTSP_STATUS_STATE);
        return;
    }

    rtp_c->state = HTTPSTATE_SEND_DATA;
3278

3279 3280 3281
    /* now everything is OK, so we can send the connection parameters */
    rtsp_reply_header(c, RTSP_STATUS_OK);
    /* session ID */
3282 3283
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
    avio_printf(c->pb, "\r\n");
3284 3285
}

3286
static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3287 3288 3289 3290 3291 3292 3293 3294
{
    HTTPContext *rtp_c;

    rtp_c = find_rtp_session_with_url(url, h->session_id);
    if (!rtp_c) {
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
        return;
    }
3295

3296 3297 3298 3299 3300 3301 3302 3303
    if (pause_only) {
        if (rtp_c->state != HTTPSTATE_SEND_DATA &&
            rtp_c->state != HTTPSTATE_WAIT_FEED) {
            rtsp_reply_error(c, RTSP_STATUS_STATE);
            return;
        }
        rtp_c->state = HTTPSTATE_READY;
        rtp_c->first_pts = AV_NOPTS_VALUE;
3304
    }
3305

3306 3307 3308
    /* now everything is OK, so we can send the connection parameters */
    rtsp_reply_header(c, RTSP_STATUS_OK);
    /* session ID */
3309
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3310
    avio_printf(c->pb, "\r\n");
3311

3312 3313
    if (!pause_only)
        close_connection(rtp_c);
3314 3315 3316 3317 3318
}

/********************************************************************/
/* RTP handling */

3319
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3320
                                       FFStream *stream, const char *session_id,
3321
                                       enum RTSPLowerTransport rtp_protocol)
3322 3323
{
    HTTPContext *c = NULL;
3324
    const char *proto_str;
3325

3326 3327 3328 3329
    /* XXX: should output a warning page when coming
       close to the connection limit */
    if (nb_connections >= nb_max_connections)
        goto fail;
3330

3331 3332 3333 3334
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
3335

3336 3337
    c->fd = -1;
    c->poll_entry = NULL;
3338
    c->from_addr = *from_addr;
3339 3340 3341 3342 3343 3344
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;
    nb_connections++;
    c->stream = stream;
3345
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3346 3347
    c->state = HTTPSTATE_READY;
    c->is_packetized = 1;
3348 3349
    c->rtp_protocol = rtp_protocol;

3350
    /* protocol is shown in statistics */
3351
    switch(c->rtp_protocol) {
3352
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3353 3354
        proto_str = "MCAST";
        break;
3355
    case RTSP_LOWER_TRANSPORT_UDP:
3356 3357
        proto_str = "UDP";
        break;
3358
    case RTSP_LOWER_TRANSPORT_TCP:
3359 3360 3361 3362 3363 3364
        proto_str = "TCP";
        break;
    default:
        proto_str = "???";
        break;
    }
3365 3366
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3367

3368 3369
    current_bandwidth += stream->bandwidth;

3370 3371 3372
    c->next = first_http_ctx;
    first_http_ctx = c;
    return c;
3373

3374 3375 3376 3377 3378 3379 3380 3381 3382
 fail:
    if (c) {
        av_free(c->buffer);
        av_free(c);
    }
    return NULL;
}

/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3383
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3384
   used. */
3385
static int rtp_new_av_stream(HTTPContext *c,
3386 3387
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c)
3388 3389 3390 3391
{
    AVFormatContext *ctx;
    AVStream *st;
    char *ipaddr;
3392
    URLContext *h = NULL;
3393
    uint8_t *dummy_buf;
3394
    int max_packet_size;
3395

3396
    /* now we can open the relevant output stream */
3397
    ctx = avformat_alloc_context();
3398 3399
    if (!ctx)
        return -1;
3400
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3401 3402 3403 3404 3405

    st = av_mallocz(sizeof(AVStream));
    if (!st)
        goto fail;
    ctx->nb_streams = 1;
3406
    ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
Mike William's avatar
Mike William committed
3407
    if (!ctx->streams)
3408
      goto fail;
3409 3410
    ctx->streams[0] = st;

3411
    if (!c->stream->feed ||
3412
        c->stream->feed == c->stream)
3413
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3414
    else
3415
        memcpy(st,
3416 3417
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
               sizeof(AVStream));
3418
    st->priv_data = NULL;
3419

3420 3421 3422 3423
    /* build destination RTP address */
    ipaddr = inet_ntoa(dest_addr->sin_addr);

    switch(c->rtp_protocol) {
3424 3425
    case RTSP_LOWER_TRANSPORT_UDP:
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3426
        /* RTP/UDP case */
3427

3428 3429 3430 3431 3432 3433 3434
        /* XXX: also pass as parameter to function ? */
        if (c->stream->is_multicast) {
            int ttl;
            ttl = c->stream->multicast_ttl;
            if (!ttl)
                ttl = 16;
            snprintf(ctx->filename, sizeof(ctx->filename),
3435
                     "rtp://%s:%d?multicast=1&ttl=%d",
3436 3437 3438 3439 3440
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
        } else {
            snprintf(ctx->filename, sizeof(ctx->filename),
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
        }
3441

3442
        if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3443 3444
            goto fail;
        c->rtp_handles[stream_index] = h;
3445
        max_packet_size = h->max_packet_size;
3446
        break;
3447
    case RTSP_LOWER_TRANSPORT_TCP:
3448 3449 3450 3451 3452
        /* RTP/TCP case */
        c->rtsp_c = rtsp_c;
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
        break;
    default:
3453 3454 3455
        goto fail;
    }

3456
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3457
             ipaddr, ntohs(dest_addr->sin_port),
3458
             c->stream->filename, stream_index, c->protocol);
3459

3460 3461
    /* normally, no packets should be output here, but the packet size may
     * be checked */
3462
    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3463 3464 3465
        /* XXX: close stream */
        goto fail;
    }
3466
    if (avformat_write_header(ctx, NULL) < 0) {
3467 3468
    fail:
        if (h)
3469
            ffurl_close(h);
3470 3471 3472
        av_free(ctx);
        return -1;
    }
3473
    avio_close_dyn_buf(ctx->pb, &dummy_buf);
3474
    av_free(dummy_buf);
3475

3476 3477 3478 3479 3480 3481 3482
    c->rtp_ctx[stream_index] = ctx;
    return 0;
}

/********************************************************************/
/* ffserver initialization */

3483
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3484 3485 3486
{
    AVStream *fst;

3487 3488 3489
    if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
        return NULL;

3490 3491 3492
    fst = av_mallocz(sizeof(AVStream));
    if (!fst)
        return NULL;
3493
    if (copy) {
3494
        fst->codec = avcodec_alloc_context3(NULL);
3495 3496
        memcpy(fst->codec, codec, sizeof(AVCodecContext));
        if (codec->extradata_size) {
3497
            fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3498 3499 3500 3501 3502
            memcpy(fst->codec->extradata, codec->extradata,
                codec->extradata_size);
        }
    } else {
        /* live streams must use the actual feed's codec since it may be
3503
         * updated later to carry extradata needed by them.
3504 3505 3506
         */
        fst->codec = codec;
    }
3507
    fst->priv_data = av_mallocz(sizeof(FeedData));
3508
    fst->index = stream->nb_streams;
3509
    avpriv_set_pts_info(fst, 33, 1, 90000);
3510
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3511 3512 3513 3514
    stream->streams[stream->nb_streams++] = fst;
    return fst;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3515
/* return the stream number in the feed */
3516
static int add_av_stream(FFStream *feed, AVStream *st)
Fabrice Bellard's avatar
Fabrice Bellard committed
3517 3518 3519 3520 3521
{
    AVStream *fst;
    AVCodecContext *av, *av1;
    int i;

3522
    av = st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
3523 3524
    for(i=0;i<feed->nb_streams;i++) {
        st = feed->streams[i];
3525
        av1 = st->codec;
3526 3527
        if (av1->codec_id == av->codec_id &&
            av1->codec_type == av->codec_type &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3528 3529 3530
            av1->bit_rate == av->bit_rate) {

            switch(av->codec_type) {
3531
            case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3532 3533
                if (av1->channels == av->channels &&
                    av1->sample_rate == av->sample_rate)
3534
                    return i;
Fabrice Bellard's avatar
Fabrice Bellard committed
3535
                break;
3536
            case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3537 3538
                if (av1->width == av->width &&
                    av1->height == av->height &&
3539 3540
                    av1->time_base.den == av->time_base.den &&
                    av1->time_base.num == av->time_base.num &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3541
                    av1->gop_size == av->gop_size)
3542
                    return i;
Fabrice Bellard's avatar
Fabrice Bellard committed
3543
                break;
3544
            default:
3545
                abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
3546 3547 3548
            }
        }
    }
3549

3550
    fst = add_av_stream1(feed, av, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
3551 3552 3553 3554 3555
    if (!fst)
        return -1;
    return feed->nb_streams - 1;
}

3556
static void remove_stream(FFStream *stream)
3557 3558 3559 3560
{
    FFStream **ps;
    ps = &first_stream;
    while (*ps != NULL) {
3561
        if (*ps == stream)
3562
            *ps = (*ps)->next;
3563
        else
3564 3565 3566 3567
            ps = &(*ps)->next;
    }
}

3568
/* specific MPEG4 handling : we extract the raw parameters */
3569
static void extract_mpeg4_header(AVFormatContext *infile)
3570 3571 3572 3573
{
    int mpeg4_count, i, size;
    AVPacket pkt;
    AVStream *st;
3574
    const uint8_t *p;
3575

3576 3577
    infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;

3578 3579 3580
    mpeg4_count = 0;
    for(i=0;i<infile->nb_streams;i++) {
        st = infile->streams[i];
3581
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3582
            st->codec->extradata_size == 0) {
3583 3584 3585 3586 3587 3588
            mpeg4_count++;
        }
    }
    if (!mpeg4_count)
        return;

3589
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3590
    while (mpeg4_count > 0) {
3591
        if (av_read_frame(infile, &pkt) < 0)
3592 3593
            break;
        st = infile->streams[pkt.stream_index];
3594
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3595 3596
            st->codec->extradata_size == 0) {
            av_freep(&st->codec->extradata);
3597 3598 3599 3600 3601
            /* fill extradata with the header */
            /* XXX: we make hard suppositions here ! */
            p = pkt.data;
            while (p < pkt.data + pkt.size - 4) {
                /* stop when vop header is found */
3602
                if (p[0] == 0x00 && p[1] == 0x00 &&
3603 3604
                    p[2] == 0x01 && p[3] == 0xb6) {
                    size = p - pkt.data;
3605
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3606
                    st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3607 3608
                    st->codec->extradata_size = size;
                    memcpy(st->codec->extradata, pkt.data, size);
3609 3610 3611 3612 3613 3614 3615 3616 3617 3618
                    break;
                }
                p++;
            }
            mpeg4_count--;
        }
        av_free_packet(&pkt);
    }
}

3619
/* compute the needed AVStream for each file */
3620
static void build_file_streams(void)
3621 3622
{
    FFStream *stream, *stream_next;
3623
    int i, ret;
3624 3625 3626

    /* gather all streams */
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3627
        AVFormatContext *infile = NULL;
3628 3629 3630 3631 3632 3633
        stream_next = stream->next;
        if (stream->stream_type == STREAM_TYPE_LIVE &&
            !stream->feed) {
            /* the stream comes from a file */
            /* try to open the file */
            /* open stream */
3634
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3635 3636
                /* specific case : if transport stream output to RTP,
                   we use a raw transport stream reader */
3637
                av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3638
            }
3639

3640 3641 3642 3643 3644 3645
            if (!stream->feed_filename[0]) {
                http_log("Unspecified feed file for stream '%s'\n", stream->filename);
                goto fail;
            }

            http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3646
            if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3647
                http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3648 3649 3650 3651 3652 3653
                /* remove stream (no need to spend more time on it) */
            fail:
                remove_stream(stream);
            } else {
                /* find all the AVStreams inside and reference them in
                   'stream' */
3654
                if (avformat_find_stream_info(infile, NULL) < 0) {
3655
                    http_log("Could not find codec parameters from '%s'\n",
3656
                             stream->feed_filename);
3657
                    avformat_close_input(&infile);
3658 3659
                    goto fail;
                }
3660 3661
                extract_mpeg4_header(infile);

3662
                for(i=0;i<infile->nb_streams;i++)
3663
                    add_av_stream1(stream, infile->streams[i]->codec, 1);
3664

3665
                avformat_close_input(&infile);
3666 3667 3668 3669 3670
            }
        }
    }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3671
/* compute the needed AVStream for each feed */
3672
static void build_feed_streams(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3673 3674 3675 3676
{
    FFStream *stream, *feed;
    int i;

3677 3678 3679 3680 3681
    /* gather all streams */
    for(stream = first_stream; stream != NULL; stream = stream->next) {
        feed = stream->feed;
        if (feed) {
            if (stream->is_feed) {
3682
                for(i=0;i<stream->nb_streams;i++)
Fabrice Bellard's avatar
Fabrice Bellard committed
3683
                    stream->feed_streams[i] = i;
3684 3685 3686 3687
            } else {
                /* we handle a stream coming from a feed */
                for(i=0;i<stream->nb_streams;i++)
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
Fabrice Bellard's avatar
Fabrice Bellard committed
3688 3689 3690 3691 3692 3693 3694 3695
            }
        }
    }

    /* create feed files if needed */
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
        int fd;

3696
        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3697
            /* See if it matches */
3698
            AVFormatContext *s = NULL;
3699 3700
            int matches = 0;

3701
            if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3702 3703
                /* set buffer size */
                ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3704 3705 3706 3707 3708 3709 3710 3711 3712 3713
                /* Now see if it matches */
                if (s->nb_streams == feed->nb_streams) {
                    matches = 1;
                    for(i=0;i<s->nb_streams;i++) {
                        AVStream *sf, *ss;
                        sf = feed->streams[i];
                        ss = s->streams[i];

                        if (sf->index != ss->index ||
                            sf->id != ss->id) {
3714
                            http_log("Index & Id do not match for stream %d (%s)\n",
3715
                                   i, feed->feed_filename);
3716 3717 3718 3719
                            matches = 0;
                        } else {
                            AVCodecContext *ccf, *ccs;

3720 3721
                            ccf = sf->codec;
                            ccs = ss->codec;
3722 3723
#define CHECK_CODEC(x)  (ccf->x != ccs->x)

3724
                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3725
                                http_log("Codecs do not match for stream %d\n", i);
3726 3727
                                matches = 0;
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3728
                                http_log("Codec bitrates do not match for stream %d\n", i);
3729
                                matches = 0;
3730
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3731 3732
                                if (CHECK_CODEC(time_base.den) ||
                                    CHECK_CODEC(time_base.num) ||
3733 3734
                                    CHECK_CODEC(width) ||
                                    CHECK_CODEC(height)) {
3735
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3736 3737
                                    matches = 0;
                                }
3738
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3739 3740 3741
                                if (CHECK_CODEC(sample_rate) ||
                                    CHECK_CODEC(channels) ||
                                    CHECK_CODEC(frame_size)) {
3742
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3743 3744 3745
                                    matches = 0;
                                }
                            } else {
3746
                                http_log("Unknown codec type\n");
3747 3748 3749
                                matches = 0;
                            }
                        }
3750
                        if (!matches)
3751 3752
                            break;
                    }
3753
                } else
3754
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3755 3756
                        feed->feed_filename, s->nb_streams, feed->nb_streams);

3757
                avformat_close_input(&s);
3758
            } else
3759
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3760
                        feed->feed_filename);
3761

3762 3763
            if (!matches) {
                if (feed->readonly) {
3764
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3765 3766 3767
                        feed->feed_filename);
                    exit(1);
                }
3768
                unlink(feed->feed_filename);
3769
            }
3770
        }
3771
        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3772
            AVFormatContext *s = avformat_alloc_context();
Fabrice Bellard's avatar
Fabrice Bellard committed
3773

3774
            if (feed->readonly) {
3775
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3776 3777 3778 3779
                    feed->feed_filename);
                exit(1);
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
3780
            /* only write the header of the ffm file */
3781
            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3782 3783
                http_log("Could not open output feed file '%s'\n",
                         feed->feed_filename);
Fabrice Bellard's avatar
Fabrice Bellard committed
3784 3785
                exit(1);
            }
3786
            s->oformat = feed->fmt;
Fabrice Bellard's avatar
Fabrice Bellard committed
3787
            s->nb_streams = feed->nb_streams;
Mike William's avatar
Mike William committed
3788
            s->streams = feed->streams;
3789
            if (avformat_write_header(s, NULL) < 0) {
3790
                http_log("Container doesn't support the required parameters\n");
3791 3792
                exit(1);
            }
3793
            /* XXX: need better API */
3794
            av_freep(&s->priv_data);
3795
            avio_close(s->pb);
3796 3797 3798
            s->streams = NULL;
            s->nb_streams = 0;
            avformat_free_context(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
3799 3800 3801 3802
        }
        /* get feed size and write index */
        fd = open(feed->feed_filename, O_RDONLY);
        if (fd < 0) {
3803
            http_log("Could not open output feed file '%s'\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
3804 3805 3806 3807
                    feed->feed_filename);
            exit(1);
        }

3808
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
3809 3810
        feed->feed_size = lseek(fd, 0, SEEK_END);
        /* ensure that we do not wrap before the end of file */
3811
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
3812 3813 3814 3815 3816 3817
            feed->feed_max_size = feed->feed_size;

        close(fd);
    }
}

3818 3819 3820
/* compute the bandwidth used by each stream */
static void compute_bandwidth(void)
{
3821 3822
    unsigned bandwidth;
    int i;
3823
    FFStream *stream;
3824

3825 3826 3827 3828
    for(stream = first_stream; stream != NULL; stream = stream->next) {
        bandwidth = 0;
        for(i=0;i<stream->nb_streams;i++) {
            AVStream *st = stream->streams[i];
3829
            switch(st->codec->codec_type) {
3830 3831
            case AVMEDIA_TYPE_AUDIO:
            case AVMEDIA_TYPE_VIDEO:
3832
                bandwidth += st->codec->bit_rate;
3833 3834 3835 3836 3837 3838 3839 3840 3841
                break;
            default:
                break;
            }
        }
        stream->bandwidth = (bandwidth + 999) / 1000;
    }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3842
/* add a codec and set the default parameters */
3843
static void add_codec(FFStream *stream, AVCodecContext *av)
Fabrice Bellard's avatar
Fabrice Bellard committed
3844 3845 3846
{
    AVStream *st;

3847
    if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3848
        return;
3849

Fabrice Bellard's avatar
Fabrice Bellard committed
3850 3851
    /* compute default parameters */
    switch(av->codec_type) {
3852
    case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3853 3854 3855 3856 3857 3858 3859
        if (av->bit_rate == 0)
            av->bit_rate = 64000;
        if (av->sample_rate == 0)
            av->sample_rate = 22050;
        if (av->channels == 0)
            av->channels = 1;
        break;
3860
    case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3861 3862
        if (av->bit_rate == 0)
            av->bit_rate = 64000;
3863 3864 3865
        if (av->time_base.num == 0){
            av->time_base.den = 5;
            av->time_base.num = 1;
3866
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
3867 3868 3869 3870
        if (av->width == 0 || av->height == 0) {
            av->width = 160;
            av->height = 128;
        }
3871
        /* Bitrate tolerance is less for streaming */
3872
        if (av->bit_rate_tolerance == 0)
3873 3874
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3875 3876 3877 3878 3879 3880
        if (av->qmin == 0)
            av->qmin = 3;
        if (av->qmax == 0)
            av->qmax = 31;
        if (av->max_qdiff == 0)
            av->max_qdiff = 3;
3881 3882
        av->qcompress = 0.5;
        av->qblur = 0.5;
3883

3884
        if (!av->nsse_weight)
3885 3886 3887
            av->nsse_weight = 8;

        av->frame_skip_cmp = FF_CMP_DCTMAX;
3888
        if (!av->me_method)
Martin Storsjö's avatar
Martin Storsjö committed
3889
            av->me_method = ME_EPZS;
3890 3891
        av->rc_buffer_aggressivity = 1.0;

3892
        if (!av->rc_eq)
3893
            av->rc_eq = av_strdup("tex^qComp");
3894
        if (!av->i_quant_factor)
3895
            av->i_quant_factor = -0.8;
3896 3897 3898 3899
        if (!av->b_quant_factor)
            av->b_quant_factor = 1.25;
        if (!av->b_quant_offset)
            av->b_quant_offset = 1.25;
3900 3901
        if (!av->rc_max_rate)
            av->rc_max_rate = av->bit_rate * 2;
3902

3903 3904 3905 3906 3907
        if (av->rc_max_rate && !av->rc_buffer_size) {
            av->rc_buffer_size = av->rc_max_rate;
        }


Fabrice Bellard's avatar
Fabrice Bellard committed
3908
        break;
3909
    default:
3910
        abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
3911 3912 3913 3914 3915
    }

    st = av_mallocz(sizeof(AVStream));
    if (!st)
        return;
3916
    st->codec = avcodec_alloc_context3(NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3917
    stream->streams[stream->nb_streams++] = st;
3918
    memcpy(st->codec, av, sizeof(AVCodecContext));
Fabrice Bellard's avatar
Fabrice Bellard committed
3919 3920
}

3921
static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3922
{
3923
    AVCodec *codec = avcodec_find_encoder_by_name(name);
3924

3925
    if (!codec || codec->type != type)
3926
        return AV_CODEC_ID_NONE;
3927
    return codec->id;
3928 3929
}

3930
static int ffserver_opt_default(const char *opt, const char *arg,
3931 3932
                       AVCodecContext *avctx, int type)
{
3933
    int ret = 0;
3934
    const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3935
    if(o)
3936
        ret = av_opt_set(avctx, opt, arg, 0);
3937
    return ret;
3938 3939
}

3940 3941
static int ffserver_opt_preset(const char *arg,
                       AVCodecContext *avctx, int type,
3942
                       enum AVCodecID *audio_id, enum AVCodecID *video_id)
3943 3944 3945
{
    FILE *f=NULL;
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3946 3947
    int ret = 0;
    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3948

3949 3950
    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
                              codec ? codec->name : NULL))) {
3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965
        fprintf(stderr, "File for preset '%s' not found\n", arg);
        return 1;
    }

    while(!feof(f)){
        int e= fscanf(f, "%999[^\n]\n", line) - 1;
        if(line[0] == '#' && !e)
            continue;
        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
        if(e){
            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
            ret = 1;
            break;
        }
        if(!strcmp(tmp, "acodec")){
3966
            *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3967
        }else if(!strcmp(tmp, "vcodec")){
3968
            *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982
        }else if(!strcmp(tmp, "scodec")){
            /* opt_subtitle_codec(tmp2); */
        }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
            ret = 1;
            break;
        }
    }

    fclose(f);

    return ret;
}

3983
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
3984
{
3985
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3986 3987 3988 3989 3990 3991

    if (fmt) {
        AVOutputFormat *stream_fmt;
        char stream_format_name[64];

        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3992
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3993 3994 3995 3996 3997 3998 3999 4000

        if (stream_fmt)
            fmt = stream_fmt;
    }

    return fmt;
}

4001
static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4002 4003 4004
{
    va_list vl;
    va_start(vl, fmt);
4005 4006
    av_log(NULL, log_level, "%s:%d: ", filename, line_num);
    av_vlog(NULL, log_level, fmt, vl);
4007 4008 4009 4010 4011
    va_end(vl);

    (*errors)++;
}

4012
static int parse_ffconfig(const char *filename)
Fabrice Bellard's avatar
Fabrice Bellard committed
4013 4014 4015 4016
{
    FILE *f;
    char line[1024];
    char cmd[64];
4017
    char arg[1024], arg2[1024];
Fabrice Bellard's avatar
Fabrice Bellard committed
4018
    const char *p;
4019
    int val, errors, warnings, line_num;
4020
    FFStream **last_stream, *stream, *redirect;
4021
    FFStream **last_feed, *feed, *s;
Fabrice Bellard's avatar
Fabrice Bellard committed
4022
    AVCodecContext audio_enc, video_enc;
4023
    enum AVCodecID audio_id, video_id;
4024
    int ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
4025 4026 4027

    f = fopen(filename, "r");
    if (!f) {
4028 4029 4030
        ret = AVERROR(errno);
        av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
        return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
4031
    }
4032

4033
    errors = warnings = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
4034 4035 4036 4037 4038 4039 4040
    line_num = 0;
    first_stream = NULL;
    last_stream = &first_stream;
    first_feed = NULL;
    last_feed = &first_feed;
    stream = NULL;
    feed = NULL;
4041
    redirect = NULL;
4042 4043
    audio_id = AV_CODEC_ID_NONE;
    video_id = AV_CODEC_ID_NONE;
4044 4045
#define ERROR(...)   report_config_error(filename, line_num, AV_LOG_ERROR,   &errors,   __VA_ARGS__)
#define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4046

Fabrice Bellard's avatar
Fabrice Bellard committed
4047 4048 4049 4050 4051
    for(;;) {
        if (fgets(line, sizeof(line), f) == NULL)
            break;
        line_num++;
        p = line;
4052
        while (av_isspace(*p))
Fabrice Bellard's avatar
Fabrice Bellard committed
4053 4054 4055 4056 4057
            p++;
        if (*p == '\0' || *p == '#')
            continue;

        get_arg(cmd, sizeof(cmd), &p);
4058

4059
        if (!av_strcasecmp(cmd, "Port")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4060
            get_arg(arg, sizeof(arg), &p);
4061 4062
            val = atoi(arg);
            if (val < 1 || val > 65536) {
4063
                ERROR("Invalid_port: %s\n", arg);
4064 4065
            }
            my_http_addr.sin_port = htons(val);
4066
        } else if (!av_strcasecmp(cmd, "BindAddress")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4067
            get_arg(arg, sizeof(arg), &p);
4068
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4069
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4070
            }
4071
        } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4072
            WARNING("NoDaemon option has no effect, you should remove it\n");
4073
        } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4074
            get_arg(arg, sizeof(arg), &p);
4075 4076
            val = atoi(arg);
            if (val < 1 || val > 65536) {
4077
                ERROR("%s:%d: Invalid port: %s\n", arg);
4078 4079
            }
            my_rtsp_addr.sin_port = htons(atoi(arg));
4080
        } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4081
            get_arg(arg, sizeof(arg), &p);
4082
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4083
                ERROR("Invalid host/IP address: %s\n", arg);
Fabrice Bellard's avatar
Fabrice Bellard committed
4084
            }
4085
        } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4086 4087 4088
            get_arg(arg, sizeof(arg), &p);
            val = atoi(arg);
            if (val < 1 || val > 65536) {
4089
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4090 4091
            }
            nb_max_http_connections = val;
4092
        } else if (!av_strcasecmp(cmd, "MaxClients")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4093 4094
            get_arg(arg, sizeof(arg), &p);
            val = atoi(arg);
4095
            if (val < 1 || val > nb_max_http_connections) {
4096
                ERROR("Invalid MaxClients: %s\n", arg);
Fabrice Bellard's avatar
Fabrice Bellard committed
4097 4098 4099
            } else {
                nb_max_connections = val;
            }
4100
        } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4101
            int64_t llval;
4102
            get_arg(arg, sizeof(arg), &p);
4103
            llval = strtoll(arg, NULL, 10);
4104
            if (llval < 10 || llval > 10000000) {
4105
                ERROR("Invalid MaxBandwidth: %s\n", arg);
4106
            } else
4107
                max_bandwidth = llval;
4108
        } else if (!av_strcasecmp(cmd, "CustomLog")) {
4109 4110
            if (!ffserver_debug)
                get_arg(logfilename, sizeof(logfilename), &p);
4111
        } else if (!av_strcasecmp(cmd, "<Feed")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4112 4113 4114 4115
            /*********************************************/
            /* Feed related options */
            char *q;
            if (stream || feed) {
4116
                ERROR("Already in a tag\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
4117 4118
            } else {
                feed = av_mallocz(sizeof(FFStream));
4119 4120 4121 4122
                if (!feed) {
                    ret = AVERROR(ENOMEM);
                    goto end;
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
4123 4124 4125 4126
                get_arg(feed->filename, sizeof(feed->filename), &p);
                q = strrchr(feed->filename, '>');
                if (*q)
                    *q = '\0';
4127 4128 4129

                for (s = first_feed; s; s = s->next) {
                    if (!strcmp(feed->filename, s->filename)) {
4130
                        ERROR("Feed '%s' already registered\n", s->filename);
4131 4132 4133
                    }
                }

4134
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4135
                /* default feed file */
Fabrice Bellard's avatar
Fabrice Bellard committed
4136 4137 4138 4139 4140
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
                         "/tmp/%s.ffm", feed->filename);
                feed->feed_max_size = 5 * 1024 * 1024;
                feed->is_feed = 1;
                feed->feed = feed; /* self feeding :-) */
4141 4142 4143 4144 4145 4146 4147

                /* add in stream list */
                *last_stream = feed;
                last_stream = &feed->next;
                /* add in feed list */
                *last_feed = feed;
                last_feed = &feed->next_feed;
Fabrice Bellard's avatar
Fabrice Bellard committed
4148
            }
4149
        } else if (!av_strcasecmp(cmd, "Launch")) {
4150 4151 4152
            if (feed) {
                int i;

4153
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4154 4155 4156 4157
                if (!feed->child_argv) {
                    ret = AVERROR(ENOMEM);
                    goto end;
                }
4158
                for (i = 0; i < 62; i++) {
Alex Beregszaszi's avatar
Alex Beregszaszi committed
4159 4160
                    get_arg(arg, sizeof(arg), &p);
                    if (!arg[0])
4161 4162
                        break;

Alex Beregszaszi's avatar
Alex Beregszaszi committed
4163
                    feed->child_argv[i] = av_strdup(arg);
4164 4165 4166 4167
                    if (!feed->child_argv[i]) {
                        ret = AVERROR(ENOMEM);
                        goto end;
                    }
4168 4169
                }

4170 4171 4172 4173 4174 4175 4176 4177 4178
                feed->child_argv[i] =
                    av_asprintf("http://%s:%d/%s",
                                (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
                                inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
                                feed->filename);
                if (!feed->child_argv[i]) {
                    ret = AVERROR(ENOMEM);
                    goto end;
                }
4179
            }
4180
        } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4181 4182
            if (feed) {
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4183
                feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4184 4185 4186
            } else if (stream) {
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
            }
4187
        } else if (!av_strcasecmp(cmd, "Truncate")) {
4188 4189
            if (feed) {
                get_arg(arg, sizeof(arg), &p);
4190 4191 4192 4193
                /* assume Truncate is true in case no argument is specified */
                if (!arg[0]) {
                    feed->truncate = 1;
                } else {
4194 4195
                    WARNING("Truncate N syntax in configuration file is deprecated, "
                            "use Truncate alone with no arguments\n");
4196 4197
                    feed->truncate = strtod(arg, NULL);
                }
4198
            }
4199
        } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4200
            if (feed) {
4201
                char *p1;
Fabrice Bellard's avatar
Fabrice Bellard committed
4202 4203 4204 4205
                double fsize;

                get_arg(arg, sizeof(arg), &p);
                p1 = arg;
4206
                fsize = strtod(p1, &p1);
4207
                switch(av_toupper(*p1)) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4208 4209 4210 4211 4212 4213 4214 4215 4216 4217
                case 'K':
                    fsize *= 1024;
                    break;
                case 'M':
                    fsize *= 1024 * 1024;
                    break;
                case 'G':
                    fsize *= 1024 * 1024 * 1024;
                    break;
                }
4218
                feed->feed_max_size = (int64_t)fsize;
4219
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4220
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4221
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
4222
            }
4223
        } else if (!av_strcasecmp(cmd, "</Feed>")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4224
            if (!feed) {
4225
                ERROR("No corresponding <Feed> for </Feed>\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
4226 4227
            }
            feed = NULL;
4228
        } else if (!av_strcasecmp(cmd, "<Stream")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4229 4230 4231 4232
            /*********************************************/
            /* Stream related options */
            char *q;
            if (stream || feed) {
4233
                ERROR("Already in a tag\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
4234
            } else {
4235
                FFStream *s;
Fabrice Bellard's avatar
Fabrice Bellard committed
4236
                stream = av_mallocz(sizeof(FFStream));
4237 4238 4239 4240
                if (!stream) {
                    ret = AVERROR(ENOMEM);
                    goto end;
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
4241 4242
                get_arg(stream->filename, sizeof(stream->filename), &p);
                q = strrchr(stream->filename, '>');
4243
                if (q)
Fabrice Bellard's avatar
Fabrice Bellard committed
4244
                    *q = '\0';
4245 4246 4247

                for (s = first_stream; s; s = s->next) {
                    if (!strcmp(stream->filename, s->filename)) {
4248
                        ERROR("Stream '%s' already registered\n", s->filename);
4249 4250 4251
                    }
                }

4252
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4253 4254
                avcodec_get_context_defaults3(&video_enc, NULL);
                avcodec_get_context_defaults3(&audio_enc, NULL);
4255

4256 4257
                audio_id = AV_CODEC_ID_NONE;
                video_id = AV_CODEC_ID_NONE;
Fabrice Bellard's avatar
Fabrice Bellard committed
4258 4259 4260 4261
                if (stream->fmt) {
                    audio_id = stream->fmt->audio_codec;
                    video_id = stream->fmt->video_codec;
                }
4262 4263 4264

                *last_stream = stream;
                last_stream = &stream->next;
Fabrice Bellard's avatar
Fabrice Bellard committed
4265
            }
4266
        } else if (!av_strcasecmp(cmd, "Feed")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4267 4268 4269
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
                FFStream *sfeed;
4270

Fabrice Bellard's avatar
Fabrice Bellard committed
4271 4272 4273 4274 4275 4276
                sfeed = first_feed;
                while (sfeed != NULL) {
                    if (!strcmp(sfeed->filename, arg))
                        break;
                    sfeed = sfeed->next_feed;
                }
4277
                if (!sfeed)
4278
                    ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4279
                else
Fabrice Bellard's avatar
Fabrice Bellard committed
4280 4281
                    stream->feed = sfeed;
            }
4282
        } else if (!av_strcasecmp(cmd, "Format")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4283
            get_arg(arg, sizeof(arg), &p);
4284
            if (stream) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4285 4286 4287 4288 4289
                if (!strcmp(arg, "status")) {
                    stream->stream_type = STREAM_TYPE_STATUS;
                    stream->fmt = NULL;
                } else {
                    stream->stream_type = STREAM_TYPE_LIVE;
4290
                    /* JPEG cannot be used here, so use single frame MJPEG */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4291 4292
                    if (!strcmp(arg, "jpeg"))
                        strcpy(arg, "mjpeg");
4293
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4294
                    if (!stream->fmt) {
4295
                        ERROR("Unknown Format: %s\n", arg);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4296 4297 4298 4299 4300
                    }
                }
                if (stream->fmt) {
                    audio_id = stream->fmt->audio_codec;
                    video_id = stream->fmt->video_codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
4301
                }
4302
            }
4303
        } else if (!av_strcasecmp(cmd, "InputFormat")) {
4304
            get_arg(arg, sizeof(arg), &p);
4305
            if (stream) {
4306 4307
                stream->ifmt = av_find_input_format(arg);
                if (!stream->ifmt) {
4308
                    ERROR("Unknown input format: %s\n", arg);
4309
                }
4310
            }
4311
        } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4312 4313 4314
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
            } else {
4315
                ERROR("FaviconURL only permitted for status streams\n");
4316
            }
4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329
        } else if (!av_strcasecmp(cmd, "Author")    ||
                   !av_strcasecmp(cmd, "Comment")   ||
                   !av_strcasecmp(cmd, "Copyright") ||
                   !av_strcasecmp(cmd, "Title")) {
            get_arg(arg, sizeof(arg), &p);

            if (stream) {
                char key[32];
                int i, ret;

                for (i = 0; i < strlen(cmd); i++)
                    key[i] = av_tolower(cmd[i]);
                key[i] = 0;
4330 4331
                WARNING("'%s' option in configuration file is deprecated, "
                        "use 'Metadata %s VALUE' instead\n", cmd, key);
4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346
                if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
                    ERROR("Could not set metadata '%s' to value '%s': %s\n",
                          key, arg, av_err2str(ret));
                }
            }
        } else if (!av_strcasecmp(cmd, "Metadata")) {
            get_arg(arg, sizeof(arg), &p);
            get_arg(arg2, sizeof(arg2), &p);
            if (stream) {
                int ret;
                if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
                    ERROR("Could not set metadata '%s' to value '%s': %s\n",
                          arg, arg2, av_err2str(ret));
                }
            }
4347
        } else if (!av_strcasecmp(cmd, "Preroll")) {
4348
            get_arg(arg, sizeof(arg), &p);
4349
            if (stream)
4350
                stream->prebuffer = atof(arg) * 1000;
4351
        } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4352
            if (stream)
4353
                stream->send_on_key = 1;
4354
        } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4355
            get_arg(arg, sizeof(arg), &p);
4356
            audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4357
            if (audio_id == AV_CODEC_ID_NONE) {
4358
                ERROR("Unknown AudioCodec: %s\n", arg);
4359
            }
4360
        } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4361
            get_arg(arg, sizeof(arg), &p);
4362
            video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4363
            if (video_id == AV_CODEC_ID_NONE) {
4364
                ERROR("Unknown VideoCodec: %s\n", arg);
4365
            }
4366
        } else if (!av_strcasecmp(cmd, "MaxTime")) {
4367
            get_arg(arg, sizeof(arg), &p);
4368
            if (stream)
4369
                stream->max_time = atof(arg) * 1000;
4370
        } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4371
            get_arg(arg, sizeof(arg), &p);
4372
            if (stream)
4373
                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4374
        } else if (!av_strcasecmp(cmd, "AudioChannels")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4375
            get_arg(arg, sizeof(arg), &p);
4376
            if (stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
4377
                audio_enc.channels = atoi(arg);
4378
        } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4379
            get_arg(arg, sizeof(arg), &p);
4380
            if (stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
4381
                audio_enc.sample_rate = atoi(arg);
4382
        } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4383 4384 4385 4386 4387 4388 4389 4390 4391
            if (stream) {
                int minrate, maxrate;

                get_arg(arg, sizeof(arg), &p);

                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
                    video_enc.rc_min_rate = minrate * 1000;
                    video_enc.rc_max_rate = maxrate * 1000;
                } else {
4392
                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4393 4394
                }
            }
4395
        } else if (!av_strcasecmp(cmd, "Debug")) {
4396 4397 4398 4399
            if (stream) {
                get_arg(arg, sizeof(arg), &p);
                video_enc.debug = strtol(arg,0,0);
            }
4400
        } else if (!av_strcasecmp(cmd, "Strict")) {
4401 4402 4403 4404
            if (stream) {
                get_arg(arg, sizeof(arg), &p);
                video_enc.strict_std_compliance = atoi(arg);
            }
4405
        } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4406 4407
            if (stream) {
                get_arg(arg, sizeof(arg), &p);
4408
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4409
            }
4410
        } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4411 4412 4413 4414
            if (stream) {
                get_arg(arg, sizeof(arg), &p);
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
            }
4415
        } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4416 4417 4418 4419
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
                video_enc.bit_rate = atoi(arg) * 1000;
            }
4420
        } else if (!av_strcasecmp(cmd, "VideoSize")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4421 4422
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
4423 4424 4425 4426 4427 4428 4429 4430
                ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
                if (ret < 0) {
                    ERROR("Invalid video size '%s'\n", arg);
                } else {
                    if ((video_enc.width % 16) != 0 ||
                        (video_enc.height % 16) != 0) {
                        ERROR("Image size must be a multiple of 16\n");
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
4431 4432
                }
            }
4433
        } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4434 4435
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
4436
                AVRational frame_rate;
4437
                if (av_parse_video_rate(&frame_rate, arg) < 0) {
4438
                    ERROR("Incorrect frame rate: %s\n", arg);
4439 4440 4441 4442
                } else {
                    video_enc.time_base.num = frame_rate.den;
                    video_enc.time_base.den = frame_rate.num;
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
4443
            }
4444 4445 4446 4447 4448 4449 4450 4451
        } else if (!av_strcasecmp(cmd, "PixelFormat")) {
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
                video_enc.pix_fmt = av_get_pix_fmt(arg);
                if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
                    ERROR("Unknown pixel format: %s\n", arg);
                }
            }
4452
        } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4453
            get_arg(arg, sizeof(arg), &p);
4454
            if (stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
4455
                video_enc.gop_size = atoi(arg);
4456
        } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4457
            if (stream)
Fabrice Bellard's avatar
Fabrice Bellard committed
4458
                video_enc.gop_size = 1;
4459
        } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4460
            if (stream)
4461
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4462
        } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4463
            if (stream) {
4464
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4465 4466
                video_enc.flags |= CODEC_FLAG_4MV;
            }
4467 4468
        } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
                   !av_strcasecmp(cmd, "AVOptionAudio")) {
4469 4470 4471 4472
            AVCodecContext *avctx;
            int type;
            get_arg(arg, sizeof(arg), &p);
            get_arg(arg2, sizeof(arg2), &p);
4473
            if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4474 4475 4476 4477 4478 4479
                avctx = &video_enc;
                type = AV_OPT_FLAG_VIDEO_PARAM;
            } else {
                avctx = &audio_enc;
                type = AV_OPT_FLAG_AUDIO_PARAM;
            }
4480
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4481
                ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4482
            }
4483 4484
        } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
                   !av_strcasecmp(cmd, "AVPresetAudio")) {
4485 4486 4487
            AVCodecContext *avctx;
            int type;
            get_arg(arg, sizeof(arg), &p);
4488
            if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499
                avctx = &video_enc;
                video_enc.codec_id = video_id;
                type = AV_OPT_FLAG_VIDEO_PARAM;
            } else {
                avctx = &audio_enc;
                audio_enc.codec_id = audio_id;
                type = AV_OPT_FLAG_AUDIO_PARAM;
            }
            if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
                ERROR("AVPreset error: %s\n", arg);
            }
4500
        } else if (!av_strcasecmp(cmd, "VideoTag")) {
4501
            get_arg(arg, sizeof(arg), &p);
4502
            if ((strlen(arg) == 4) && stream)
4503
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4504
        } else if (!av_strcasecmp(cmd, "BitExact")) {
4505
            if (stream)
4506
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4507
        } else if (!av_strcasecmp(cmd, "DctFastint")) {
4508
            if (stream)
4509
                video_enc.dct_algo  = FF_DCT_FASTINT;
4510
        } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4511
            if (stream)
4512
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4513
        } else if (!av_strcasecmp(cmd, "Qscale")) {
4514 4515 4516 4517 4518
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
                video_enc.flags |= CODEC_FLAG_QSCALE;
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
            }
4519
        } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4520
            get_arg(arg, sizeof(arg), &p);
4521 4522 4523
            if (stream) {
                video_enc.max_qdiff = atoi(arg);
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4524
                    ERROR("VideoQDiff out of range\n");
4525 4526
                }
            }
4527
        } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4528
            get_arg(arg, sizeof(arg), &p);
4529 4530 4531
            if (stream) {
                video_enc.qmax = atoi(arg);
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4532
                    ERROR("VideoQMax out of range\n");
4533 4534
                }
            }
4535
        } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4536
            get_arg(arg, sizeof(arg), &p);
4537 4538 4539
            if (stream) {
                video_enc.qmin = atoi(arg);
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4540
                    ERROR("VideoQMin out of range\n");
4541 4542
                }
            }
4543
        } else if (!av_strcasecmp(cmd, "LumiMask")) {
4544
            get_arg(arg, sizeof(arg), &p);
4545
            if (stream)
4546
                video_enc.lumi_masking = atof(arg);
4547
        } else if (!av_strcasecmp(cmd, "DarkMask")) {
4548
            get_arg(arg, sizeof(arg), &p);
4549
            if (stream)
4550
                video_enc.dark_masking = atof(arg);
4551
        } else if (!av_strcasecmp(cmd, "NoVideo")) {
4552
            video_id = AV_CODEC_ID_NONE;
4553
        } else if (!av_strcasecmp(cmd, "NoAudio")) {
4554
            audio_id = AV_CODEC_ID_NONE;
4555
        } else if (!av_strcasecmp(cmd, "ACL")) {
4556
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4557
        } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4558 4559
            if (stream) {
                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4560
            }
4561
        } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4562 4563 4564
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
                av_freep(&stream->rtsp_option);
Alex Beregszaszi's avatar
Alex Beregszaszi committed
4565
                stream->rtsp_option = av_strdup(arg);
4566
            }
4567
        } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4568 4569
            get_arg(arg, sizeof(arg), &p);
            if (stream) {
4570
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4571
                    ERROR("Invalid host/IP address: %s\n", arg);
4572 4573
                }
                stream->is_multicast = 1;
4574
                stream->loop = 1; /* default is looping */
4575
            }
4576
        } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4577
            get_arg(arg, sizeof(arg), &p);
4578
            if (stream)
4579
                stream->multicast_port = atoi(arg);
4580
        } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4581
            get_arg(arg, sizeof(arg), &p);
4582
            if (stream)
4583
                stream->multicast_ttl = atoi(arg);
4584
        } else if (!av_strcasecmp(cmd, "NoLoop")) {
4585
            if (stream)
4586
                stream->loop = 0;
4587
        } else if (!av_strcasecmp(cmd, "</Stream>")) {
Fabrice Bellard's avatar
Fabrice Bellard committed
4588
            if (!stream) {
4589
                ERROR("No corresponding <Stream> for </Stream>\n");
4590
            } else {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4591
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4592
                    if (audio_id != AV_CODEC_ID_NONE) {
4593
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4594 4595 4596
                        audio_enc.codec_id = audio_id;
                        add_codec(stream, &audio_enc);
                    }
4597
                    if (video_id != AV_CODEC_ID_NONE) {
4598
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4599 4600 4601
                        video_enc.codec_id = video_id;
                        add_codec(stream, &video_enc);
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
4602
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4603
                stream = NULL;
4604
            }
4605
        } else if (!av_strcasecmp(cmd, "<Redirect")) {
4606 4607 4608
            /*********************************************/
            char *q;
            if (stream || feed || redirect) {
4609
                ERROR("Already in a tag\n");
4610 4611
            } else {
                redirect = av_mallocz(sizeof(FFStream));
4612 4613 4614 4615
                if (!redirect) {
                    ret = AVERROR(ENOMEM);
                    goto end;
                }
4616 4617 4618 4619 4620 4621 4622 4623 4624
                *last_stream = redirect;
                last_stream = &redirect->next;

                get_arg(redirect->filename, sizeof(redirect->filename), &p);
                q = strrchr(redirect->filename, '>');
                if (*q)
                    *q = '\0';
                redirect->stream_type = STREAM_TYPE_REDIRECT;
            }
4625
        } else if (!av_strcasecmp(cmd, "URL")) {
4626
            if (redirect)
4627
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4628
        } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4629
            if (!redirect) {
4630
                ERROR("No corresponding <Redirect> for </Redirect>\n");
4631
            } else {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4632
                if (!redirect->feed_filename[0]) {
4633
                    ERROR("No URL found for <Redirect>\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
4634 4635
                }
                redirect = NULL;
4636
            }
4637
        } else if (!av_strcasecmp(cmd, "LoadModule")) {
4638
            ERROR("Loadable modules no longer supported\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
4639
        } else {
4640
            ERROR("Incorrect keyword: '%s'\n", cmd);
Fabrice Bellard's avatar
Fabrice Bellard committed
4641 4642
        }
    }
4643
#undef ERROR
Fabrice Bellard's avatar
Fabrice Bellard committed
4644

4645
end:
Fabrice Bellard's avatar
Fabrice Bellard committed
4646
    fclose(f);
4647 4648
    if (ret < 0)
        return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
4649
    if (errors)
4650
        return AVERROR(EINVAL);
Fabrice Bellard's avatar
Fabrice Bellard committed
4651 4652 4653 4654
    else
        return 0;
}

4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669
static void handle_child_exit(int sig)
{
    pid_t pid;
    int status;

    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        FFStream *feed;

        for (feed = first_feed; feed; feed = feed->next) {
            if (feed->pid == pid) {
                int uptime = time(0) - feed->pid_start;

                feed->pid = 0;
                fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);

4670
                if (uptime < 30)
4671 4672 4673 4674 4675 4676 4677 4678 4679
                    /* Turn off any more restarts */
                    feed->child_argv = 0;
            }
        }
    }

    need_to_start_children = 1;
}

4680
static void opt_debug(void)
4681 4682
{
    ffserver_debug = 1;
4683
    logfilename[0] = '-';
4684 4685
}

4686
void show_help_default(const char *opt, const char *arg)
4687
{
4688
    printf("usage: ffserver [options]\n"
4689 4690
           "Hyper fast multi format Audio/Video streaming server\n");
    printf("\n");
4691
    show_help_options(options, "Main options:", 0, 0, 0);
4692 4693 4694
}

static const OptionDef options[] = {
4695
#include "cmdutils_common_opts.h"
4696 4697 4698 4699 4700 4701
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
    { NULL },
};

Fabrice Bellard's avatar
Fabrice Bellard committed
4702 4703
int main(int argc, char **argv)
{
4704
    struct sigaction sigact = { { 0 } };
4705
    int ret = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
4706

4707
    config_filename = av_strdup("/etc/ffserver.conf");
4708

4709
    parse_loglevel(argc, argv, options);
4710
    av_register_all();
4711
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
4712

4713
    show_banner(argc, argv, options);
4714

4715
    my_program_name = argv[0];
4716

4717
    parse_options(NULL, argc, argv, options, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
4718

4719
    unsetenv("http_proxy");             /* Kill the http_proxy */
4720

4721
    av_lfg_init(&random_state, av_get_random_seed());
4722

4723 4724 4725 4726
    sigact.sa_handler = handle_child_exit;
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    sigaction(SIGCHLD, &sigact, 0);

4727 4728 4729
    if ((ret = parse_ffconfig(config_filename)) < 0) {
        fprintf(stderr, "Error reading configuration file '%s': %s\n",
                config_filename, av_err2str(ret));
Fabrice Bellard's avatar
Fabrice Bellard committed
4730 4731
        exit(1);
    }
4732
    av_freep(&config_filename);
Fabrice Bellard's avatar
Fabrice Bellard committed
4733

4734 4735 4736
    /* open log file if needed */
    if (logfilename[0] != '\0') {
        if (!strcmp(logfilename, "-"))
4737
            logfile = stdout;
4738 4739 4740 4741 4742
        else
            logfile = fopen(logfilename, "a");
        av_log_set_callback(http_av_log);
    }

4743 4744
    build_file_streams();

Fabrice Bellard's avatar
Fabrice Bellard committed
4745 4746
    build_feed_streams();

4747 4748
    compute_bandwidth();

Fabrice Bellard's avatar
Fabrice Bellard committed
4749 4750 4751
    /* signal init */
    signal(SIGPIPE, SIG_IGN);

4752
    if (http_server() < 0) {
4753
        http_log("Could not start server\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
4754 4755 4756 4757 4758
        exit(1);
    }

    return 0;
}