ffserver.c 126 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/random_seed.h"
53
#include "libavutil/parseutils.h"
54
#include "libavutil/opt.h"
55 56
#include "libavutil/time.h"

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

71
#include "cmdutils.h"
72
#include "ffserver_config.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
73

74 75
#define PATH_LENGTH 1024

76
const char program_name[] = "ffserver";
77
const int program_birth_year = 2000;
78

79 80
static const OptionDef options[];

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

    RTSPSTATE_WAIT_REQUEST,
    RTSPSTATE_SEND_REPLY,
93
    RTSPSTATE_SEND_PACKET,
Fabrice Bellard's avatar
Fabrice Bellard committed
94 95
};

96
static const char * const http_state[] = {
97 98 99
    "HTTP_WAIT_REQUEST",
    "HTTP_SEND_HEADER",

Fabrice Bellard's avatar
Fabrice Bellard committed
100 101 102 103 104
    "SEND_DATA_HEADER",
    "SEND_DATA",
    "SEND_DATA_TRAILER",
    "RECEIVE_DATA",
    "WAIT_FEED",
105 106 107 108
    "READY",

    "RTSP_WAIT_REQUEST",
    "RTSP_SEND_REPLY",
109
    "RTSP_SEND_PACKET",
Fabrice Bellard's avatar
Fabrice Bellard committed
110 111
};

112
#define IOBUFFER_INIT_SIZE 8192
Fabrice Bellard's avatar
Fabrice Bellard committed
113 114

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

Fabrice Bellard's avatar
Fabrice Bellard committed
118 119
#define SYNC_TIMEOUT (10 * 1000)

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

125
typedef struct {
126
    int64_t count1, count2;
127
    int64_t time1, time2;
128 129
} DataRateData;

Fabrice Bellard's avatar
Fabrice Bellard committed
130 131 132 133 134 135
/* 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 */
136
    int64_t timeout;
137
    uint8_t *buffer_ptr, *buffer_end;
Fabrice Bellard's avatar
Fabrice Bellard committed
138
    int http_error;
139
    int post;
140 141
    int chunked_encoding;
    int chunk_size;               /* 0 if it needs to be read */
Fabrice Bellard's avatar
Fabrice Bellard committed
142
    struct HTTPContext *next;
143
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
144
    int64_t data_count;
Fabrice Bellard's avatar
Fabrice Bellard committed
145 146 147 148
    /* feed input */
    int feed_fd;
    /* input format handling */
    AVFormatContext *fmt_in;
149
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
150
    int64_t first_pts;            /* initial pts value */
151 152 153 154 155 156 157
    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
158
    /* output format handling */
159
    struct FFServerStream *stream;
160
    /* -1 is invalid stream */
161 162
    int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
    int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
163
    int switch_pending;
164
    AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
Fabrice Bellard's avatar
Fabrice Bellard committed
165
    int last_packet_sent; /* true if last data packet was sent */
166
    int suppress_log;
167
    DataRateData datarate;
168
    int wmp_client_id;
169 170 171
    char protocol[16];
    char method[16];
    char url[128];
172
    int buffer_size;
173
    uint8_t *buffer;
174 175
    int is_packetized; /* if true, the stream is packetized */
    int packet_stream_index; /* current stream for output in state machine */
176

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

182
    /* RTP state specific */
183
    enum RTSPLowerTransport rtp_protocol;
184
    char session_id[32]; /* session id */
185
    AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS];
186

187
    /* RTP/UDP specific */
188
    URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
189 190 191 192

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

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

200
static HTTPContext *first_http_ctx;
201 202 203 204 205

static FFServerConfig config = {
    .nb_max_http_connections = 2000,
    .nb_max_connections = 5,
    .max_bandwidth = 1000,
206
    .use_defaults = 1,
207
};
Fabrice Bellard's avatar
Fabrice Bellard committed
208

209 210 211 212 213
static void new_connection(int server_fd, int is_rtsp);
static void close_connection(HTTPContext *c);

/* HTTP handling */
static int handle_connection(HTTPContext *c);
214
static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream);
215
static void compute_status(HTTPContext *c);
Fabrice Bellard's avatar
Fabrice Bellard committed
216
static int open_input_stream(HTTPContext *c, const char *info);
217 218
static int http_parse_request(HTTPContext *c);
static int http_send_data(HTTPContext *c);
Fabrice Bellard's avatar
Fabrice Bellard committed
219 220
static int http_start_receive_data(HTTPContext *c);
static int http_receive_data(HTTPContext *c);
221 222 223 224

/* RTSP handling */
static int rtsp_parse_request(HTTPContext *c);
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
225
static void rtsp_cmd_options(HTTPContext *c, const char *url);
226 227 228 229 230 231
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
                           RTSPMessageHeader *h);
static void rtsp_cmd_play(HTTPContext *c, const char *url,
                          RTSPMessageHeader *h);
static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
                               RTSPMessageHeader *h, int pause_only);
232

233
/* SDP handling */
234
static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
235 236
                                   struct in_addr my_ip);

237
/* RTP handling */
238
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
239 240
                                       FFServerStream *stream,
                                       const char *session_id,
241
                                       enum RTSPLowerTransport rtp_protocol);
242
static int rtp_new_av_stream(HTTPContext *c,
243 244
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c);
245
/* utils */
246 247
static size_t htmlencode (const char *src, char **dest);
static inline void cp_html_entity (char *buffer, const char *entity);
248 249
static inline int check_codec_match(AVCodecContext *ccf, AVCodecContext *ccs,
                                    int stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
250

251 252
static const char *my_program_name;

253
static int no_launch;
254
static int need_to_start_children;
255

256
/* maximum number of simultaneous HTTP connections */
257
static unsigned int nb_connections;
Fabrice Bellard's avatar
Fabrice Bellard committed
258

259
static uint64_t current_bandwidth;
260

261 262
/* Making this global saves on passing it around everywhere */
static int64_t cur_time;
263

264
static AVLFG random_state;
265

Fabrice Bellard's avatar
Fabrice Bellard committed
266 267
static FILE *logfile = NULL;

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
static inline void cp_html_entity (char *buffer, const char *entity) {
    if (!buffer || !entity)
        return;
    while (*entity)
        *buffer++ = *entity++;
}

/**
 * Substitutes known conflicting chars on a text string with
 * their corresponding HTML entities.
 *
 * Returns the number of bytes in the 'encoded' representation
 * not including the terminating NUL.
 */
static size_t htmlencode (const char *src, char **dest) {
    const char *amp = "&amp;";
    const char *lt  = "&lt;";
    const char *gt  = "&gt;";
    const char *start;
    char *tmp;
    size_t final_size = 0;

    if (!src)
        return 0;

    start = src;

    /* Compute needed dest size */
    while (*src != '\0') {
        switch(*src) {
            case 38: /* & */
                final_size += 5;
                break;
            case 60: /* < */
            case 62: /* > */
                final_size += 4;
                break;
            default:
                final_size++;
        }
        src++;
    }

    src = start;
    *dest = av_mallocz(final_size + 1);
    if (!*dest)
        return 0;

    /* Build dest */
    tmp = *dest;
    while (*src != '\0') {
        switch(*src) {
            case 38: /* & */
                cp_html_entity (tmp, amp);
                tmp += 5;
                break;
            case 60: /* < */
                cp_html_entity (tmp, lt);
                tmp += 4;
                break;
            case 62: /* > */
                cp_html_entity (tmp, gt);
                tmp += 4;
                break;
            default:
                *tmp = *src;
                tmp += 1;
        }
        src++;
337
    }
338 339 340
    *tmp = '\0';

    return final_size;
341 342
}

343 344 345 346
static int64_t ffm_read_write_index(int fd)
{
    uint8_t buf[8];

347 348
    if (lseek(fd, 8, SEEK_SET) < 0)
        return AVERROR(EIO);
349 350 351 352 353 354 355 356 357 358 359 360
    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;
361
    if (lseek(fd, 8, SEEK_SET) < 0)
362
        goto bail_eio;
363
    if (write(fd, buf, 8) != 8)
364 365
        goto bail_eio;

366
    return 8;
367 368 369

bail_eio:
    return AVERROR(EIO);
370 371 372 373 374
}

static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
                                int64_t file_size)
{
375
    av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN);
376 377
    av_opt_set_int(s, "ffm_write_index", pos, AV_OPT_SEARCH_CHILDREN);
    av_opt_set_int(s, "ffm_file_size", file_size, AV_OPT_SEARCH_CHILDREN);
378 379
}

380
static char *ctime1(char *buf2, size_t buf_size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
381 382 383 384 385 386
{
    time_t ti;
    char *p;

    ti = time(NULL);
    p = ctime(&ti);
387 388 389 390
    if (!p || !*p) {
        *buf2 = '\0';
        return buf2;
    }
391
    av_strlcpy(buf2, p, buf_size);
392
    p = buf2 + strlen(buf2) - 1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
393 394 395 396 397
    if (*p == '\n')
        *p = '\0';
    return buf2;
}

398
static void http_vlog(const char *fmt, va_list vargs)
Fabrice Bellard's avatar
Fabrice Bellard committed
399
{
400
    static int print_prefix = 1;
401
    char buf[32];
402 403 404 405

    if (!logfile)
        return;

406 407 408 409 410 411 412
    if (print_prefix) {
        ctime1(buf, sizeof(buf));
        fprintf(logfile, "%s ", buf);
    }
    print_prefix = strstr(fmt, "\n") != NULL;
    vfprintf(logfile, fmt, vargs);
    fflush(logfile);
413 414
}

415 416 417 418
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
static void http_log(const char *fmt, ...)
419 420 421 422 423 424 425 426 427 428 429
{
    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;
430
    if (level > av_log_get_level())
431 432
        return;
    if (print_prefix && avc)
433
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
434 435
    print_prefix = strstr(fmt, "\n") != NULL;
    http_vlog(fmt, vargs);
Fabrice Bellard's avatar
Fabrice Bellard committed
436 437
}

438 439
static void log_connection(HTTPContext *c)
{
440
    if (c->suppress_log)
441 442
        return;

443 444
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
445
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
446 447
}

448
static void update_datarate(DataRateData *drd, int64_t count)
449 450 451 452
{
    if (!drd->time1 && !drd->count1) {
        drd->time1 = drd->time2 = cur_time;
        drd->count1 = drd->count2 = count;
453
    } else if (cur_time - drd->time2 > 5000) {
Alex Beregszaszi's avatar
Alex Beregszaszi committed
454 455 456 457
        drd->time1 = drd->time2;
        drd->count1 = drd->count2;
        drd->time2 = cur_time;
        drd->count2 = count;
458 459 460 461
    }
}

/* In bytes per second */
462
static int compute_datarate(DataRateData *drd, int64_t count)
463 464 465
{
    if (cur_time == drd->time1)
        return 0;
466

467 468 469
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
}

470

471
static void start_children(FFServerStream *feed)
472
{
473
    char *pathname;
474 475
    char *slash;
    int i;
476
    size_t cmd_length;
477

478 479 480
    if (no_launch)
        return;

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    cmd_length = strlen(my_program_name);

   /**
    * FIXME: WIP Safeguard. Remove after clearing all harcoded
    * '1024' path lengths
    */
    if (cmd_length > PATH_LENGTH - 1) {
        http_log("Could not start children. Command line: '%s' exceeds "
                    "path length limit (%d)\n", my_program_name, PATH_LENGTH);
        return;
    }

    pathname = av_strdup (my_program_name);
    if (!pathname) {
        http_log("Could not allocate memory for children cmd line\n");
        return;
    }
498 499 500 501 502 503 504 505 506 507
   /* replace "ffserver" with "ffmpeg" in the path of current
    * program. Ignore user provided path */

    slash = strrchr(pathname, '/');
    if (!slash)
        slash = pathname;
    else
        slash++;
    strcpy(slash, "ffmpeg");

508
    for (; feed; feed = feed->next) {
509 510 511 512

        if (!feed->child_argv || feed->pid)
            continue;

513
        feed->pid_start = time(0);
514

515 516
        feed->pid = fork();
        if (feed->pid < 0) {
517
            http_log("Unable to create children: %s\n", strerror(errno));
518
            av_free (pathname);
519
            exit(EXIT_FAILURE);
520
        }
521

522 523
        if (feed->pid)
            continue;
524

525
        /* In child */
526

527 528
        http_log("Launch command line: ");
        http_log("%s ", pathname);
529

530 531 532
        for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
            http_log("%s ", feed->child_argv[i]);
        http_log("\n");
533

534 535
        for (i = 3; i < 256; i++)
            close(i);
536

537 538 539 540 541 542 543 544
        if (!config.debug) {
            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;");
        }
545

546 547
        signal(SIGPIPE, SIG_DFL);
        execvp(pathname, feed->child_argv);
548
        av_free (pathname);
549
        _exit(1);
550
    }
551
    av_free (pathname);
552 553
}

554 555
/* open a listening socket */
static int socket_open_listen(struct sockaddr_in *my_addr)
Fabrice Bellard's avatar
Fabrice Bellard committed
556
{
557
    int server_fd, tmp;
Fabrice Bellard's avatar
Fabrice Bellard committed
558 559 560 561 562 563

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

Fabrice Bellard's avatar
Fabrice Bellard committed
565
    tmp = 1;
566 567
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
        av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
568

569
    my_addr->sin_family = AF_INET;
570
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
571
        char bindmsg[32];
572 573
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)",
                 ntohs(my_addr->sin_port));
574
        perror (bindmsg);
575
        goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
576
    }
577

Fabrice Bellard's avatar
Fabrice Bellard committed
578 579
    if (listen (server_fd, 5) < 0) {
        perror ("listen");
580
        goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
581
    }
582 583 584

    if (ff_socket_nonblock(server_fd, 1) < 0)
        av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
585 586

    return server_fd;
587 588 589 590

fail:
    closesocket(server_fd);
    return -1;
591 592
}

593 594 595
/* start all multicast streams */
static void start_multicast(void)
{
596
    FFServerStream *stream;
597 598
    char session_id[32];
    HTTPContext *rtp_c;
599
    struct sockaddr_in dest_addr = {0};
600
    int default_port, stream_index;
601
    unsigned int random0, random1;
602 603

    default_port = 6000;
604
    for(stream = config.first_stream; stream; stream = stream->next) {
605

606 607
        if (!stream->is_multicast)
            continue;
608

609 610 611 612
        random0 = av_lfg_get(&random_state);
        random1 = av_lfg_get(&random_state);

        /* open the RTP connection */
613
        snprintf(session_id, sizeof(session_id), "%08x%08x", random0, random1);
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641

        /* 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);

        rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
                                   RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
        if (!rtp_c)
            continue;

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

        /* open each RTP stream */
        for(stream_index = 0; stream_index < stream->nb_streams;
            stream_index++) {
            dest_addr.sin_port = htons(stream->multicast_port +
                                       2 * stream_index);
            if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
642
                continue;
643 644 645 646 647 648 649

            http_log("Could not open output stream '%s/streamid=%d'\n",
                     stream->filename, stream_index);
            exit(1);
        }

        rtp_c->state = HTTPSTATE_SEND_DATA;
650 651
    }
}
652

653
/* main loop of the HTTP server */
654 655
static int http_server(void)
{
656
    int server_fd = 0, rtsp_server_fd = 0;
657
    int ret, delay;
658
    struct pollfd *poll_table, *poll_entry;
659 660
    HTTPContext *c, *c_next;

661 662 663 664 665
    poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
                                  sizeof(*poll_table));
    if(!poll_table) {
        http_log("Impossible to allocate a poll table handling %d "
                 "connections.\n", config.nb_max_http_connections);
666 667 668
        return -1;
    }

669 670
    if (config.http_addr.sin_port) {
        server_fd = socket_open_listen(&config.http_addr);
671 672
        if (server_fd < 0)
            goto quit;
673
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
674

675 676
    if (config.rtsp_addr.sin_port) {
        rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
677 678
        if (rtsp_server_fd < 0) {
            closesocket(server_fd);
679
            goto quit;
680
        }
681 682 683 684
    }

    if (!rtsp_server_fd && !server_fd) {
        http_log("HTTP and RTSP disabled.\n");
685
        goto quit;
686
    }
687

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

690
    start_children(config.first_feed);
691

692 693
    start_multicast();

Fabrice Bellard's avatar
Fabrice Bellard committed
694 695
    for(;;) {
        poll_entry = poll_table;
696
        if (server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
697 698 699
            poll_entry->fd = server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
700 701
        }
        if (rtsp_server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
702 703 704
            poll_entry->fd = rtsp_server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
705
        }
706

Fabrice Bellard's avatar
Fabrice Bellard committed
707 708
        /* wait for events on each HTTP handle */
        c = first_http_ctx;
709
        delay = 1000;
710
        while (c) {
Fabrice Bellard's avatar
Fabrice Bellard committed
711 712 713
            int fd;
            fd = c->fd;
            switch(c->state) {
714 715
            case HTTPSTATE_SEND_HEADER:
            case RTSPSTATE_SEND_REPLY:
716
            case RTSPSTATE_SEND_PACKET:
Fabrice Bellard's avatar
Fabrice Bellard committed
717 718
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
719
                poll_entry->events = POLLOUT;
Fabrice Bellard's avatar
Fabrice Bellard committed
720 721 722 723 724
                poll_entry++;
                break;
            case HTTPSTATE_SEND_DATA_HEADER:
            case HTTPSTATE_SEND_DATA:
            case HTTPSTATE_SEND_DATA_TRAILER:
725
                if (!c->is_packetized) {
726 727
                    /* for TCP, we output as much as we can
                     * (may need to put a limit) */
728 729 730 731 732
                    c->poll_entry = poll_entry;
                    poll_entry->fd = fd;
                    poll_entry->events = POLLOUT;
                    poll_entry++;
                } else {
733
                    /* when ffserver is doing the timing, we work by
734 735
                     * looking at which packet needs to be sent every
                     * 10 ms (one tick wait XXX: 10 ms assumed) */
736 737
                    if (delay > 10)
                        delay = 10;
738
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
739
                break;
740
            case HTTPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
741 742
            case HTTPSTATE_RECEIVE_DATA:
            case HTTPSTATE_WAIT_FEED:
743
            case RTSPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
744 745 746
                /* need to catch errors */
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
747
                poll_entry->events = POLLIN;/* Maybe this will work */
Fabrice Bellard's avatar
Fabrice Bellard committed
748 749 750 751 752 753 754 755 756 757
                poll_entry++;
                break;
            default:
                c->poll_entry = NULL;
                break;
            }
            c = c->next;
        }

        /* wait for an event on one connection. We poll at least every
758
         * second to handle timeouts */
Fabrice Bellard's avatar
Fabrice Bellard committed
759
        do {
760
            ret = poll(poll_table, poll_entry - poll_table, delay);
761
            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
762
                ff_neterrno() != AVERROR(EINTR)) {
763
                goto quit;
764
            }
765
        } while (ret < 0);
766

767
        cur_time = av_gettime() / 1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
768

769 770
        if (need_to_start_children) {
            need_to_start_children = 0;
771
            start_children(config.first_feed);
772 773
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
774
        /* now handle the events */
775
        for(c = first_http_ctx; c; c = c_next) {
776 777
            c_next = c->next;
            if (handle_connection(c) < 0) {
778
                log_connection(c);
779
                /* close and free the connection */
780
                close_connection(c);
Fabrice Bellard's avatar
Fabrice Bellard committed
781 782 783 784
            }
        }

        poll_entry = poll_table;
785
        if (server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
786 787 788 789
            /* new HTTP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(server_fd, 0);
            poll_entry++;
790 791
        }
        if (rtsp_server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
792 793 794
            /* new RTSP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(rtsp_server_fd, 1);
795
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
796
    }
797 798 799 800

quit:
    av_free(poll_table);
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
801 802
}

803 804
/* 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
805
{
806 807 808
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */

809 810
    c->state = is_rtsp ? RTSPSTATE_WAIT_REQUEST : HTTPSTATE_WAIT_REQUEST;
    c->timeout = cur_time +
811
                 (is_rtsp ? RTSP_REQUEST_TIMEOUT : HTTP_REQUEST_TIMEOUT);
812 813
}

814 815
static void http_send_too_busy_reply(int fd)
{
816
    char buffer[400];
817
    int len = snprintf(buffer, sizeof(buffer),
818
                       "HTTP/1.0 503 Server too busy\r\n"
819 820
                       "Content-type: text/html\r\n"
                       "\r\n"
821
                       "<!DOCTYPE html>\n"
822
                       "<html><head><title>Too busy</title></head><body>\r\n"
823 824 825 826
                       "<p>The server is too busy to serve your request at "
                       "this time.</p>\r\n"
                       "<p>The number of current connections is %u, and this "
                       "exceeds the limit of %u.</p>\r\n"
827
                       "</body></html>\r\n",
828
                       nb_connections, config.nb_max_connections);
829
    av_assert0(len < sizeof(buffer));
830
    if (send(fd, buffer, len, 0) < len)
831 832
        av_log(NULL, AV_LOG_WARNING,
               "Could not send too-busy reply, send() failed\n");
833 834 835
}


836 837 838
static void new_connection(int server_fd, int is_rtsp)
{
    struct sockaddr_in from_addr;
839 840
    socklen_t len;
    int fd;
841 842 843
    HTTPContext *c = NULL;

    len = sizeof(from_addr);
844
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
845
                &len);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
846 847
    if (fd < 0) {
        http_log("error during accept %s\n", strerror(errno));
848
        return;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
849
    }
850 851
    if (ff_socket_nonblock(fd, 1) < 0)
        av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
852

853
    if (nb_connections >= config.nb_max_connections) {
854
        http_send_too_busy_reply(fd);
855
        goto fail;
856
    }
857

858 859 860 861
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
862

863 864 865 866 867 868 869
    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;
870 871 872

    c->next = first_http_ctx;
    first_http_ctx = c;
873
    nb_connections++;
874

875 876 877 878 879 880
    start_wait_request(c, is_rtsp);

    return;

 fail:
    if (c) {
881
        av_freep(&c->buffer);
882 883
        av_free(c);
    }
884
    closesocket(fd);
885 886 887 888 889 890 891 892 893 894 895
}

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

    /* remove connection from list */
    cp = &first_http_ctx;
896
    while (*cp) {
897
        c1 = *cp;
898
        if (c1 == c)
899
            *cp = c->next;
900
        else
901 902 903
            cp = &c1->next;
    }

904
    /* remove references, if any (XXX: do it faster) */
905
    for(c1 = first_http_ctx; c1; c1 = c1->next) {
906 907 908 909
        if (c1->rtsp_c == c)
            c1->rtsp_c = NULL;
    }

910 911
    /* remove connection associated resources */
    if (c->fd >= 0)
912
        closesocket(c->fd);
913 914 915 916
    if (c->fmt_in) {
        /* close each frame parser */
        for(i=0;i<c->fmt_in->nb_streams;i++) {
            st = c->fmt_in->streams[i];
917
            if (st->codec->codec)
918
                avcodec_close(st->codec);
919
        }
920
        avformat_close_input(&c->fmt_in);
921 922 923 924
    }

    /* free RTP output streams if any */
    nb_streams = 0;
925
    if (c->stream)
926
        nb_streams = c->stream->nb_streams;
927

928 929 930 931
    for(i=0;i<nb_streams;i++) {
        ctx = c->rtp_ctx[i];
        if (ctx) {
            av_write_trailer(ctx);
932
            av_dict_free(&ctx->metadata);
933 934
            av_freep(&ctx->streams[0]);
            av_freep(&ctx);
935
        }
936
        ffurl_close(c->rtp_handles[i]);
937
    }
938

939 940
    ctx = &c->fmt_ctx;

941
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
942 943 944 945 946
        /* prepare header */
        if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
            av_write_trailer(ctx);
            av_freep(&c->pb_buffer);
            avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
947 948 949
        }
    }

950
    for(i=0; i<ctx->nb_streams; i++)
951
        av_freep(&ctx->streams[i]);
952 953
    av_freep(&ctx->streams);
    av_freep(&ctx->priv_data);
954

955
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
956
        current_bandwidth -= c->stream->bandwidth;
957 958 959 960 961 962 963

    /* 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);
    }

964
    av_freep(&c->pb_buffer);
965
    av_freep(&c->packet_buffer);
966
    av_freep(&c->buffer);
967 968 969 970 971 972 973
    av_free(c);
    nb_connections--;
}

static int handle_connection(HTTPContext *c)
{
    int len, ret;
974
    uint8_t *ptr;
975

Fabrice Bellard's avatar
Fabrice Bellard committed
976 977
    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
978
    case RTSPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
979 980 981 982 983 984 985 986 987 988
        /* 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 */
989
    read_loop:
990 991 992
        if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
            return -1;

Fabrice Bellard's avatar
Fabrice Bellard committed
993
        if (len < 0) {
994 995
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
Fabrice Bellard's avatar
Fabrice Bellard committed
996
                return -1;
997 998
            break;
        }
999 1000 1001 1002 1003 1004
        /* search for end of request. */
        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 */
1005
            if (c->state == HTTPSTATE_WAIT_REQUEST)
1006
                ret = http_parse_request(c);
1007
            else
1008
                ret = rtsp_parse_request(c);
1009

1010
            if (ret < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
1011
                return -1;
1012 1013 1014 1015
        } else if (ptr >= c->buffer_end) {
            /* request too long: cannot do anything */
            return -1;
        } else goto read_loop;
1016

Fabrice Bellard's avatar
Fabrice Bellard committed
1017 1018 1019 1020 1021 1022
        break;

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

1023
        /* no need to write if no events */
Fabrice Bellard's avatar
Fabrice Bellard committed
1024 1025
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1026
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
1027
        if (len < 0) {
1028 1029
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1030
                goto close_connection;
Fabrice Bellard's avatar
Fabrice Bellard committed
1031
            }
1032 1033
            break;
        }
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
        c->buffer_ptr += len;
        if (c->stream)
            c->stream->bytes_served += len;
        c->data_count += len;
        if (c->buffer_ptr >= c->buffer_end) {
            av_freep(&c->pb_buffer);
            /* if error, exit */
            if (c->http_error)
                return -1;
            /* all the buffer was sent : synchronize to the incoming
             * stream */
            c->state = HTTPSTATE_SEND_DATA_HEADER;
            c->buffer_ptr = c->buffer_end = c->buffer;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
1048 1049 1050 1051 1052
        break;

    case HTTPSTATE_SEND_DATA:
    case HTTPSTATE_SEND_DATA_HEADER:
    case HTTPSTATE_SEND_DATA_TRAILER:
1053
        /* for packetized output, we consider we can always write (the
1054 1055
         * input streams set the speed). It may be better to verify
         * that we do not rely too much on the kernel queues */
1056 1057 1058
        if (!c->is_packetized) {
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
                return -1;
1059

1060 1061 1062 1063
            /* no need to read if no events */
            if (!(c->poll_entry->revents & POLLOUT))
                return 0;
        }
1064
        if (http_send_data(c) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
1065
            return -1;
1066 1067 1068
        /* close connection if trailer sent */
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
            return -1;
1069 1070 1071 1072
        /* Check if it is a single jpeg frame 123 */
        if (c->stream->single_frame && c->data_count > c->cur_frame_bytes && c->cur_frame_bytes > 0) {
            close_connection(c);
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
        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 */
1085
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
Fabrice Bellard's avatar
Fabrice Bellard committed
1086 1087 1088 1089
            return -1;

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

    case RTSPSTATE_SEND_REPLY:
1092 1093
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            goto close_connection;
1094 1095 1096
        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1097
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1098
        if (len < 0) {
1099 1100
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1101
                goto close_connection;
1102
            }
1103 1104
            break;
        }
1105 1106 1107 1108 1109 1110 1111
        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);
        }
1112
        break;
1113 1114 1115 1116 1117 1118 1119 1120
    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;
1121 1122
        len = send(c->fd, c->packet_buffer_ptr,
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1123
        if (len < 0) {
1124 1125
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1126 1127 1128 1129
                /* error : close connection */
                av_freep(&c->packet_buffer);
                return -1;
            }
1130 1131
            break;
        }
1132 1133 1134 1135 1136 1137
        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;
        }
1138
        break;
1139 1140 1141
    case HTTPSTATE_READY:
        /* nothing to do */
        break;
Fabrice Bellard's avatar
Fabrice Bellard committed
1142 1143 1144 1145
    default:
        return -1;
    }
    return 0;
1146 1147 1148 1149

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

1152 1153 1154 1155 1156
static int extract_rates(char *rates, int ratelen, const char *request)
{
    const char *p;

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

1160
            while (*q && *q != '\n' && av_isspace(*q))
1161 1162
                q++;

1163
            if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1164 1165 1166 1167 1168
                int stream_no;
                int rate_no;

                q += 20;

1169
                memset(rates, 0xff, ratelen);
1170 1171 1172 1173 1174

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

1175
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1176
                        break;
1177

1178
                    stream_no--;
1179
                    if (stream_no < ratelen && stream_no >= 0)
1180 1181
                        rates[stream_no] = rate_no;

1182
                    while (*q && *q != '\n' && !av_isspace(*q))
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
                        q++;
                }

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

        p++;
    }

    return 0;
}

1199 1200
static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
                               int bit_rate)
1201 1202
{
    int i;
1203 1204 1205 1206
    int best_bitrate = 100000000;
    int best = -1;

    for (i = 0; i < feed->nb_streams; i++) {
1207
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1208 1209 1210 1211

        if (feed_codec->codec_id != codec->codec_id ||
            feed_codec->sample_rate != codec->sample_rate ||
            feed_codec->width != codec->width ||
1212
            feed_codec->height != codec->height)
1213 1214 1215 1216
            continue;

        /* Potential stream */

1217
        /* We want the fastest stream less than bit_rate, or the slowest
1218 1219 1220 1221
         * faster than bit_rate
         */

        if (feed_codec->bit_rate <= bit_rate) {
1222 1223
            if (best_bitrate > bit_rate ||
                feed_codec->bit_rate > best_bitrate) {
1224 1225 1226
                best_bitrate = feed_codec->bit_rate;
                best = i;
            }
1227 1228 1229 1230 1231
            continue;
        }
        if (feed_codec->bit_rate < best_bitrate) {
            best_bitrate = feed_codec->bit_rate;
            best = i;
1232 1233 1234 1235 1236 1237 1238 1239
        }
    }
    return best;
}

static int modify_current_stream(HTTPContext *c, char *rates)
{
    int i;
1240
    FFServerStream *req = c->stream;
1241
    int action_required = 0;
1242

1243 1244 1245 1246
    /* Not much we can do for a feed */
    if (!req->feed)
        return 0;

1247
    for (i = 0; i < req->nb_streams; i++) {
1248
        AVCodecContext *codec = req->streams[i]->codec;
1249 1250 1251

        switch(rates[i]) {
            case 0:
1252
                c->switch_feed_streams[i] = req->feed_streams[i];
1253 1254
                break;
            case 1:
1255
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1256 1257
                break;
            case 2:
1258 1259 1260 1261 1262 1263 1264
                /* 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
1265 1266 1267
                break;
        }

1268 1269
        if (c->switch_feed_streams[i] >= 0 &&
            c->switch_feed_streams[i] != c->feed_streams[i]) {
1270
            action_required = 1;
1271
        }
1272
    }
1273

1274 1275
    return action_required;
}
1276

1277 1278 1279 1280 1281 1282
static void get_word(char *buf, int buf_size, const char **pp)
{
    const char *p;
    char *q;

    p = *pp;
1283
    p += strspn(p, SPACE_CHARS);
1284
    q = buf;
1285
    while (!av_isspace(*p) && *p != '\0') {
1286 1287 1288 1289 1290 1291 1292 1293 1294
        if ((q - buf) < buf_size - 1)
            *q++ = *p;
        p++;
    }
    if (buf_size > 0)
        *q = '\0';
    *pp = p;
}

1295 1296
static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
                                               HTTPContext *c)
1297 1298 1299 1300
{
    FILE* f;
    char line[1024];
    char  cmd[1024];
1301
    FFServerIPAddressACL *acl = NULL;
1302 1303 1304 1305 1306 1307 1308 1309 1310
    int line_num = 0;
    const char *p;

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

1311
    acl = av_mallocz(sizeof(FFServerIPAddressACL));
1312 1313 1314 1315
    if (!acl) {
        fclose(f);
        return NULL;
    }
1316 1317

    /* Build ACL */
1318
    while (fgets(line, sizeof(line), f)) {
1319 1320
        line_num++;
        p = line;
1321
        while (av_isspace(*p))
1322 1323 1324
            p++;
        if (*p == '\0' || *p == '#')
            continue;
1325
        ffserver_get_arg(cmd, sizeof(cmd), &p);
1326

1327
        if (!av_strcasecmp(cmd, "ACL"))
1328 1329
            ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
                                   line_num);
1330 1331 1332 1333 1334 1335
    }
    fclose(f);
    return acl;
}


1336
static void free_acl_list(FFServerIPAddressACL *in_acl)
1337
{
1338
    FFServerIPAddressACL *pacl, *pacl2;
1339 1340 1341 1342 1343 1344 1345 1346 1347

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

1348
static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1349
{
1350 1351
    enum FFServerIPAddressAction last_action = IP_DENY;
    FFServerIPAddressACL *acl;
1352
    struct in_addr *src = &c->from_addr.sin_addr;
1353
    unsigned long src_addr = src->s_addr;
1354

1355
    for (acl = in_acl; acl; acl = acl->next) {
1356
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1357 1358 1359 1360 1361 1362 1363 1364
            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;
}

1365
static int validate_acl(FFServerStream *stream, HTTPContext *c)
1366 1367
{
    int ret = 0;
1368
    FFServerIPAddressACL *acl;
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381

    /* 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;
}

1382 1383 1384 1385
/**
 * compute the real filename of a file by matching it without its
 * extensions to all the stream's filenames
 */
1386 1387 1388 1389 1390
static void compute_real_filename(char *filename, int max_size)
{
    char file1[1024];
    char file2[1024];
    char *p;
1391
    FFServerStream *stream;
1392

1393
    av_strlcpy(file1, filename, sizeof(file1));
1394 1395 1396
    p = strrchr(file1, '.');
    if (p)
        *p = '\0';
1397
    for(stream = config.first_stream; stream; stream = stream->next) {
1398
        av_strlcpy(file2, stream->filename, sizeof(file2));
1399 1400 1401 1402
        p = strrchr(file2, '.');
        if (p)
            *p = '\0';
        if (!strcmp(file1, file2)) {
1403
            av_strlcpy(filename, stream->filename, max_size);
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
            break;
        }
    }
}

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

1418
/* parse HTTP request and prepare header */
Fabrice Bellard's avatar
Fabrice Bellard committed
1419 1420
static int http_parse_request(HTTPContext *c)
{
1421 1422
    const char *p;
    char *p1;
1423
    enum RedirType redir_type;
Fabrice Bellard's avatar
Fabrice Bellard committed
1424
    char cmd[32];
1425
    char info[1024], filename[1024];
Fabrice Bellard's avatar
Fabrice Bellard committed
1426 1427 1428
    char url[1024], *q;
    char protocol[32];
    char msg[1024];
1429
    char *encoded_msg = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
1430
    const char *mime_type;
1431
    FFServerStream *stream;
1432
    int i;
1433
    char ratebuf[32];
1434
    const char *useragent = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1435 1436

    p = c->buffer;
1437
    get_word(cmd, sizeof(cmd), &p);
1438
    av_strlcpy(c->method, cmd, sizeof(c->method));
1439

Fabrice Bellard's avatar
Fabrice Bellard committed
1440
    if (!strcmp(cmd, "GET"))
1441
        c->post = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1442
    else if (!strcmp(cmd, "POST"))
1443
        c->post = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1444 1445 1446
    else
        return -1;

1447
    get_word(url, sizeof(url), &p);
1448
    av_strlcpy(c->url, url, sizeof(c->url));
1449

1450
    get_word(protocol, sizeof(protocol), (const char **)&p);
Fabrice Bellard's avatar
Fabrice Bellard committed
1451 1452
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
        return -1;
1453

1454
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1455

1456
    if (config.debug)
1457 1458
        http_log("%s - - New connection: %s %s\n",
                 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1459

Fabrice Bellard's avatar
Fabrice Bellard committed
1460
    /* find the filename and the optional info string in the request */
1461 1462 1463 1464
    p1 = strchr(url, '?');
    if (p1) {
        av_strlcpy(info, p1, sizeof(info));
        *p1 = '\0';
1465
    } else
Fabrice Bellard's avatar
Fabrice Bellard committed
1466 1467
        info[0] = '\0';

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

1470
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1471
        if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1472
            useragent = p + 11;
1473
            if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
                useragent++;
            break;
        }
        p = strchr(p, '\n');
        if (!p)
            break;

        p++;
    }

1484
    redir_type = REDIR_NONE;
1485
    if (av_match_ext(filename, "asx")) {
1486
        redir_type = REDIR_ASX;
1487
        filename[strlen(filename)-1] = 'f';
1488
    } else if (av_match_ext(filename, "asf") &&
1489
        (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1490
        /* if this isn't WMP or lookalike, return the redirector file */
1491
        redir_type = REDIR_ASF;
1492
    } else if (av_match_ext(filename, "rpm,ram")) {
1493
        redir_type = REDIR_RAM;
1494
        strcpy(filename + strlen(filename)-2, "m");
1495
    } else if (av_match_ext(filename, "rtsp")) {
1496
        redir_type = REDIR_RTSP;
1497
        compute_real_filename(filename, sizeof(filename) - 1);
1498
    } else if (av_match_ext(filename, "sdp")) {
1499
        redir_type = REDIR_SDP;
1500
        compute_real_filename(filename, sizeof(filename) - 1);
1501
    }
1502

1503
    /* "redirect" request to index.html */
1504
    if (!strlen(filename))
1505
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1506

1507
    stream = config.first_stream;
1508
    while (stream) {
1509
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
Fabrice Bellard's avatar
Fabrice Bellard committed
1510 1511 1512
            break;
        stream = stream->next;
    }
1513
    if (!stream) {
1514
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1515
        http_log("File '%s' not found\n", url);
Fabrice Bellard's avatar
Fabrice Bellard committed
1516 1517
        goto send_error;
    }
1518

1519 1520 1521 1522 1523 1524 1525
    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;
1526
        snprintf(q, c->buffer_size,
1527 1528 1529 1530
                      "HTTP/1.0 301 Moved\r\n"
                      "Location: %s\r\n"
                      "Content-type: text/html\r\n"
                      "\r\n"
1531
                      "<!DOCTYPE html>\n"
1532 1533
                      "<html><head><title>Moved</title></head><body>\r\n"
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1534 1535
                      "</body></html>\r\n",
                 stream->feed_filename, stream->feed_filename);
1536
        q += strlen(q);
1537 1538 1539 1540 1541 1542 1543
        /* prepare output buffer */
        c->buffer_ptr = c->buffer;
        c->buffer_end = q;
        c->state = HTTPSTATE_SEND_HEADER;
        return 0;
    }

1544 1545
    /* If this is WMP, get the rate information */
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1546
        if (modify_current_stream(c, ratebuf)) {
1547
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1548
                if (c->switch_feed_streams[i] >= 0)
Reinhard Tartler's avatar
Reinhard Tartler committed
1549
                    c->switch_feed_streams[i] = -1;
1550 1551
            }
        }
1552 1553
    }

1554 1555 1556
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
        current_bandwidth += stream->bandwidth;

1557
    /* If already streaming this feed, do not let another feeder start */
1558 1559
    if (stream->feed_opened) {
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1560
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1561 1562 1563
        goto send_error;
    }

1564
    if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1565
        c->http_error = 503;
1566
        q = c->buffer;
1567
        snprintf(q, c->buffer_size,
1568
                      "HTTP/1.0 503 Server too busy\r\n"
1569 1570
                      "Content-type: text/html\r\n"
                      "\r\n"
1571
                      "<!DOCTYPE html>\n"
1572
                      "<html><head><title>Too busy</title></head><body>\r\n"
1573 1574 1575
                      "<p>The server is too busy to serve your request at "
                      "this time.</p>\r\n"
                      "<p>The bandwidth being served (including your stream) "
1576 1577
                      "is %"PRIu64"kbit/s, and this exceeds the limit of "
                      "%"PRIu64"kbit/s.</p>\r\n"
1578 1579
                      "</body></html>\r\n",
                 current_bandwidth, config.max_bandwidth);
1580
        q += strlen(q);
1581 1582 1583 1584 1585 1586
        /* prepare output buffer */
        c->buffer_ptr = c->buffer;
        c->buffer_end = q;
        c->state = HTTPSTATE_SEND_HEADER;
        return 0;
    }
1587

1588
    if (redir_type != REDIR_NONE) {
1589
        const char *hostinfo = 0;
1590

1591
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1592
            if (av_strncasecmp(p, "Host:", 5) == 0) {
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
                hostinfo = p + 5;
                break;
            }
            p = strchr(p, '\n');
            if (!p)
                break;

            p++;
        }

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

1607
            while (av_isspace(*hostinfo))
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
                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;
1621 1622
                    switch(redir_type) {
                    case REDIR_ASX:
1623
                        snprintf(q, c->buffer_size,
1624 1625 1626 1627 1628 1629 1630
                                      "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);
1631
                        q += strlen(q);
1632 1633
                        break;
                    case REDIR_RAM:
1634
                        snprintf(q, c->buffer_size,
1635 1636 1637 1638 1639
                                      "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);
1640
                        q += strlen(q);
1641 1642
                        break;
                    case REDIR_ASF:
1643
                        snprintf(q, c->buffer_size,
1644 1645 1646 1647 1648
                                      "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);
1649
                        q += strlen(q);
1650 1651 1652 1653 1654
                        break;
                    case REDIR_RTSP:
                        {
                            char hostname[256], *p;
                            /* extract only hostname */
1655
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1656 1657 1658
                            p = strrchr(hostname, ':');
                            if (p)
                                *p = '\0';
1659
                            snprintf(q, c->buffer_size,
1660
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1661
                                          /* XXX: incorrect MIME type ? */
1662 1663
                                          "Content-type: application/x-rtsp\r\n"
                                          "\r\n"
1664
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1665
                            q += strlen(q);
1666 1667 1668 1669
                        }
                        break;
                    case REDIR_SDP:
                        {
1670
                            uint8_t *sdp_data;
1671 1672
                            int sdp_data_size;
                            socklen_t len;
1673 1674
                            struct sockaddr_in my_addr;

1675
                            snprintf(q, c->buffer_size,
1676 1677 1678
                                          "HTTP/1.0 200 OK\r\n"
                                          "Content-type: application/sdp\r\n"
                                          "\r\n");
1679
                            q += strlen(q);
1680 1681

                            len = sizeof(my_addr);
1682 1683 1684 1685

                            /* XXX: Should probably fail? */
                            if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
                                http_log("getsockname() failed\n");
1686

1687
                            /* XXX: should use a dynamic buffer */
1688 1689
                            sdp_data_size = prepare_sdp_description(stream,
                                                                    &sdp_data,
1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
                                                                    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:
1700
                        abort();
1701
                        break;
1702
                    }
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712

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

1713
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1714
        goto send_error;
Fabrice Bellard's avatar
Fabrice Bellard committed
1715 1716
    }

1717
    stream->conns_served++;
1718

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

1721
    if (c->post) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1722 1723
        /* if post, it means a feed is being sent */
        if (!stream->is_feed) {
Diego Biurrun's avatar
Diego Biurrun committed
1724
            /* However it might be a status report from WMP! Let us log the
1725
             * data as it might come handy one day. */
1726
            const char *logline = 0;
1727
            int client_id = 0;
1728

1729
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1730
                if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1731 1732 1733
                    logline = p;
                    break;
                }
1734
                if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1735
                    client_id = strtol(p + 18, 0, 10);
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
                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
1751
                    http_log("%.*s\n", (int) (eol - logline), logline);
1752 1753 1754
                    c->suppress_log = 1;
                }
            }
1755

1756
#ifdef DEBUG
1757
            http_log("\nGot request:\n%s\n", c->buffer);
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
#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;
                }

1769 1770
                if (wmpc && modify_current_stream(wmpc, ratebuf))
                    wmpc->switch_pending = 1;
1771
            }
1772

1773
            snprintf(msg, sizeof(msg), "POST command not handled");
1774
            c->stream = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1775 1776 1777
            goto send_error;
        }
        if (http_start_receive_data(c) < 0) {
1778
            snprintf(msg, sizeof(msg), "could not open feed");
Fabrice Bellard's avatar
Fabrice Bellard committed
1779 1780 1781 1782 1783 1784 1785
            goto send_error;
        }
        c->http_error = 0;
        c->state = HTTPSTATE_RECEIVE_DATA;
        return 0;
    }

1786
#ifdef DEBUG
1787
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1788
        http_log("\nGot request:\n%s\n", c->buffer);
1789 1790
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
1791
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1792
        goto send_status;
Fabrice Bellard's avatar
Fabrice Bellard committed
1793 1794 1795

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

1800
    /* prepare HTTP header */
1801 1802
    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
1803 1804
    mime_type = c->stream->fmt->mime_type;
    if (!mime_type)
1805
        mime_type = "application/x-octet-stream";
1806
    av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
1807 1808

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

1812
        c->wmp_client_id = av_lfg_get(&random_state);
1813

1814
        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
1815
    }
1816 1817 1818
    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);
1819

Fabrice Bellard's avatar
Fabrice Bellard committed
1820 1821 1822 1823 1824 1825 1826 1827 1828
    /* 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;
1829 1830 1831
    if (!htmlencode(msg, &encoded_msg)) {
        http_log("Could not encode filename '%s' as HTML\n", msg);
    }
1832
    snprintf(q, c->buffer_size,
1833 1834 1835
                  "HTTP/1.0 404 Not Found\r\n"
                  "Content-type: text/html\r\n"
                  "\r\n"
1836
                  "<!DOCTYPE html>\n"
1837
                  "<html>\n"
1838
                  "<head>\n"
1839
                  "<meta charset=\"UTF-8\">\n"
1840 1841
                  "<title>404 Not Found</title>\n"
                  "</head>\n"
1842
                  "<body>%s</body>\n"
1843
                  "</html>\n", encoded_msg? encoded_msg : "File not found");
1844
    q += strlen(q);
Fabrice Bellard's avatar
Fabrice Bellard committed
1845 1846 1847 1848
    /* prepare output buffer */
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;
1849
    av_freep(&encoded_msg);
Fabrice Bellard's avatar
Fabrice Bellard committed
1850
    return 0;
1851 1852
 send_status:
    compute_status(c);
1853 1854 1855
    /* horrible: we use this value to avoid
     * going to the send data state */
    c->http_error = 200;
Fabrice Bellard's avatar
Fabrice Bellard committed
1856 1857 1858 1859
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
}

1860
static void fmt_bytecount(AVIOContext *pb, int64_t count)
1861
{
1862
    static const char suffix[] = " kMGTP";
1863 1864
    const char *s;

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

1867
    avio_printf(pb, "%"PRId64"%c", count, *s);
1868 1869
}

1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880
static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream)
{
    int i, stream_no;
    const char *type = "unknown";
    char parameters[64];
    AVStream *st;
    AVCodec *codec;

    stream_no = stream->nb_streams;

    avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1881
                    "type<th>kbit/s<th align=left>codec<th align=left>"
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906
                    "Parameters\n");

    for (i = 0; i < stream_no; i++) {
        st = stream->streams[i];
        codec = avcodec_find_encoder(st->codec->codec_id);

        parameters[0] = 0;

        switch(st->codec->codec_type) {
        case AVMEDIA_TYPE_AUDIO:
            type = "audio";
            snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
                     st->codec->channels, st->codec->sample_rate);
            break;
        case AVMEDIA_TYPE_VIDEO:
            type = "video";
            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);
            break;
        default:
            abort();
        }

1907
        avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%"PRId64
1908
                        "<td>%s<td>%s\n",
1909
                    i, type, (int64_t)st->codec->bit_rate/1000,
1910 1911 1912 1913 1914 1915
                    codec ? codec->name : "", parameters);
     }

     avio_printf(pb, "</table>\n");
}

1916
static void compute_status(HTTPContext *c)
Fabrice Bellard's avatar
Fabrice Bellard committed
1917 1918
{
    HTTPContext *c1;
1919
    FFServerStream *stream;
1920
    char *p;
Fabrice Bellard's avatar
Fabrice Bellard committed
1921
    time_t ti;
1922
    int i, len;
1923
    AVIOContext *pb;
1924

1925
    if (avio_open_dyn_buf(&pb) < 0) {
1926
        /* XXX: return an error ? */
1927
        c->buffer_ptr = c->buffer;
1928 1929
        c->buffer_end = c->buffer;
        return;
1930
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1931

1932
    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1933
    avio_printf(pb, "Content-type: text/html\r\n");
1934 1935
    avio_printf(pb, "Pragma: no-cache\r\n");
    avio_printf(pb, "\r\n");
1936

1937
    avio_printf(pb, "<!DOCTYPE html>\n");
1938
    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1939
    if (c->stream->feed_filename[0])
1940 1941
        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
                    c->stream->feed_filename);
1942 1943
    avio_printf(pb, "</head>\n<body>");
    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
Fabrice Bellard's avatar
Fabrice Bellard committed
1944
    /* format status */
1945 1946
    avio_printf(pb, "<h2>Available Streams</h2>\n");
    avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1947
    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>kbit/s<th align=left>Video<br>kbit/s<th><br>Codec<th align=left>Audio<br>kbit/s<th><br>Codec<th align=left valign=top>Feed\n");
1948
    stream = config.first_stream;
1949
    while (stream) {
1950 1951 1952
        char sfilename[1024];
        char *eosf;

1953 1954 1955 1956
        if (stream->feed == stream) {
            stream = stream->next;
            continue;
        }
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966

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

1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
        avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
                    sfilename, stream->filename);
        avio_printf(pb, "<td align=right> %d <td align=right> ",
                    stream->conns_served);
        fmt_bytecount(pb, stream->bytes_served);

        switch(stream->stream_type) {
        case STREAM_TYPE_LIVE: {
            int audio_bit_rate = 0;
            int video_bit_rate = 0;
            const char *audio_codec_name = "";
            const char *video_codec_name = "";
            const char *audio_codec_name_extra = "";
            const char *video_codec_name_extra = "";

            for(i=0;i<stream->nb_streams;i++) {
                AVStream *st = stream->streams[i];
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);

                switch(st->codec->codec_type) {
                case AVMEDIA_TYPE_AUDIO:
                    audio_bit_rate += st->codec->bit_rate;
                    if (codec) {
                        if (*audio_codec_name)
                            audio_codec_name_extra = "...";
                        audio_codec_name = codec->name;
Fabrice Bellard's avatar
Fabrice Bellard committed
2005
                    }
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
                    break;
                case AVMEDIA_TYPE_VIDEO:
                    video_bit_rate += st->codec->bit_rate;
                    if (codec) {
                        if (*video_codec_name)
                            video_codec_name_extra = "...";
                        video_codec_name = codec->name;
                    }
                    break;
                case AVMEDIA_TYPE_DATA:
                    video_bit_rate += st->codec->bit_rate;
                    break;
                default:
                    abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
2020 2021
                }
            }
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042

            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",
                        stream->fmt->name, stream->bandwidth,
                        video_bit_rate / 1000, video_codec_name,
                        video_codec_name_extra, audio_bit_rate / 1000,
                        audio_codec_name, audio_codec_name_extra);

            if (stream->feed)
                avio_printf(pb, "<td>%s", stream->feed->filename);
            else
                avio_printf(pb, "<td>%s", stream->feed_filename);
            avio_printf(pb, "\n");
        }
            break;
        default:
            avio_printf(pb, "<td align=center> - <td align=right> - "
                            "<td align=right> - <td><td align=right> - <td>\n");
            break;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2043 2044
        stream = stream->next;
    }
2045
    avio_printf(pb, "</table>\n");
2046

2047
    stream = config.first_stream;
2048
    while (stream) {
2049

2050 2051 2052 2053
        if (stream->feed != stream) {
            stream = stream->next;
            continue;
        }
2054 2055 2056

        avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
        if (stream->pid) {
2057
            avio_printf(pb, "Running as pid %"PRId64".\n", (int64_t) stream->pid);
2058

2059
#if defined(linux)
2060 2061 2062 2063 2064 2065
            {
                FILE *pid_stat;
                char ps_cmd[64];

                /* This is somewhat linux specific I guess */
                snprintf(ps_cmd, sizeof(ps_cmd),
2066 2067
                         "ps -o \"%%cpu,cputime\" --no-headers %"PRId64"",
                         (int64_t) stream->pid);
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081

                 pid_stat = popen(ps_cmd, "r");
                 if (pid_stat) {
                     char cpuperc[10];
                     char cpuused[64];

                     if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
                         avio_printf(pb, "Currently using %s%% of the cpu. "
                                         "Total time used %s.\n",
                                     cpuperc, cpuused);
                     }
                     fclose(pid_stat);
                 }
            }
2082 2083
#endif

2084 2085
            avio_printf(pb, "<p>");
        }
2086

2087
        print_stream_params(pb, stream);
2088 2089
        stream = stream->next;
    }
2090

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

2094
    avio_printf(pb, "Number of connections: %d / %d<br>\n",
2095
                nb_connections, config.nb_max_connections);
Fabrice Bellard's avatar
Fabrice Bellard committed
2096

2097
    avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2098
                current_bandwidth, config.max_bandwidth);
2099

2100
    avio_printf(pb, "<table>\n");
2101
    avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
2102
                    "bit/s<th>Actual bit/s<th>Bytes transferred\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2103 2104
    c1 = first_http_ctx;
    i = 0;
2105
    while (c1) {
2106 2107 2108 2109
        int bitrate;
        int j;

        bitrate = 0;
2110 2111
        if (c1->stream) {
            for (j = 0; j < c1->stream->nb_streams; j++) {
2112
                if (!c1->stream->feed)
2113
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2114 2115
                else if (c1->feed_streams[j] >= 0)
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2116 2117 2118
            }
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2119 2120
        i++;
        p = inet_ntoa(c1->from_addr.sin_addr);
2121 2122 2123 2124 2125
        avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
                        "<td align=right>",
                    i, c1->stream ? c1->stream->filename : "",
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
                    c1->protocol, http_state[c1->state]);
2126
        fmt_bytecount(pb, bitrate);
2127
        avio_printf(pb, "<td align=right>");
2128
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2129
        avio_printf(pb, "<td align=right>");
2130
        fmt_bytecount(pb, c1->data_count);
2131
        avio_printf(pb, "\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2132 2133
        c1 = c1->next;
    }
2134
    avio_printf(pb, "</table>\n");
2135

Fabrice Bellard's avatar
Fabrice Bellard committed
2136 2137 2138
    /* date */
    ti = time(NULL);
    p = ctime(&ti);
2139 2140
    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
2141

2142
    len = avio_close_dyn_buf(pb, &c->pb_buffer);
2143 2144
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
Fabrice Bellard's avatar
Fabrice Bellard committed
2145 2146 2147 2148 2149 2150
}

static int open_input_stream(HTTPContext *c, const char *info)
{
    char buf[128];
    char input_filename[1024];
2151
    AVFormatContext *s = NULL;
2152
    int buf_size, i, ret;
2153
    int64_t stream_pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
2154 2155 2156 2157

    /* find file name */
    if (c->stream->feed) {
        strcpy(input_filename, c->stream->feed->feed_filename);
2158
        buf_size = FFM_PACKET_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
2159
        /* compute position (absolute time) */
2160
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2161 2162
            if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
                http_log("Invalid date specification '%s' for stream\n", buf);
2163
                return ret;
2164
            }
2165
        } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2166
            int prebuffer = strtol(buf, 0, 10);
2167
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2168
        } else
2169
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
2170 2171
    } else {
        strcpy(input_filename, c->stream->feed_filename);
2172
        buf_size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2173
        /* compute position (relative time) */
2174
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2175 2176
            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
                http_log("Invalid date specification '%s' for stream\n", buf);
2177
                return ret;
2178
            }
2179
        } else
Fabrice Bellard's avatar
Fabrice Bellard committed
2180 2181
            stream_pos = 0;
    }
2182 2183 2184 2185
    if (!input_filename[0]) {
        http_log("No filename was specified for stream\n");
        return AVERROR(EINVAL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2186 2187

    /* open stream */
2188 2189 2190
    ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
                              &c->stream->in_opts);
    if (ret < 0) {
2191 2192
        http_log("Could not open input '%s': %s\n",
                 input_filename, av_err2str(ret));
2193
        return ret;
2194
    }
2195 2196

    /* set buffer size */
2197 2198 2199 2200 2201 2202 2203
    if (buf_size > 0) {
        ret = ffio_set_buf_size(s->pb, buf_size);
        if (ret < 0) {
            http_log("Failed to set buffer size\n");
            return ret;
        }
    }
2204

2205
    s->flags |= AVFMT_FLAG_GENPTS;
Fabrice Bellard's avatar
Fabrice Bellard committed
2206
    c->fmt_in = s;
2207 2208 2209
    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);
2210
        avformat_close_input(&s);
2211
        return ret;
2212
    }
2213

2214 2215
    /* choose stream as clock source (we favor the video stream if
     * present) for packet sending */
2216 2217
    c->pts_stream_index = 0;
    for(i=0;i<c->stream->nb_streams;i++) {
2218
        if (c->pts_stream_index == 0 &&
2219
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2220 2221 2222
            c->pts_stream_index = i;
        }
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2223

2224
    if (c->fmt_in->iformat->read_seek)
2225
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2226 2227 2228
    /* 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
2229 2230 2231
    return 0;
}

2232 2233
/* return the server clock (in us) */
static int64_t get_server_clock(HTTPContext *c)
2234
{
2235
    /* compute current pts value from system time */
2236
    return (cur_time - c->start_time) * 1000;
2237 2238
}

2239
/* return the estimated time (in us) at which the current packet must be sent */
2240
static int64_t get_packet_send_clock(HTTPContext *c)
2241
{
2242
    int bytes_left, bytes_sent, frame_bytes;
2243

2244
    frame_bytes = c->cur_frame_bytes;
2245
    if (frame_bytes <= 0)
2246
        return c->cur_pts;
2247 2248 2249 2250

    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;
2251 2252 2253 2254 2255 2256 2257 2258
}


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

2259
    av_freep(&c->pb_buffer);
2260 2261
    switch(c->state) {
    case HTTPSTATE_SEND_DATA_HEADER:
2262
        ctx = avformat_alloc_context();
2263 2264
        if (!ctx)
            return AVERROR(ENOMEM);
2265 2266
        c->fmt_ctx = *ctx;
        av_freep(&ctx);
2267
        av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2268 2269
        c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
                                              sizeof(AVStream *));
2270 2271
        if (!c->fmt_ctx.streams)
            return AVERROR(ENOMEM);
2272

2273
        for(i=0;i<c->stream->nb_streams;i++) {
2274
            AVStream *src;
2275
            c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2276

2277 2278
            /* if file or feed, then just take streams from FFServerStream
             * struct */
2279
            if (!c->stream->feed ||
2280
                c->stream->feed == c->stream)
2281
                src = c->stream->streams[i];
2282
            else
2283 2284
                src = c->stream->feed->streams[c->stream->feed_streams[i]];

2285 2286
            *(c->fmt_ctx.streams[i]) = *src;
            c->fmt_ctx.streams[i]->priv_data = 0;
2287 2288
            /* XXX: should be done in AVStream, not in codec */
            c->fmt_ctx.streams[i]->codec->frame_number = 0;
2289
        }
2290 2291 2292 2293
        /* set output format parameters */
        c->fmt_ctx.oformat = c->stream->fmt;
        c->fmt_ctx.nb_streams = c->stream->nb_streams;

2294 2295 2296
        c->got_key_frame = 0;

        /* prepare header and save header data in a stream */
2297
        if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2298 2299 2300
            /* XXX: potential leak */
            return -1;
        }
2301
        c->fmt_ctx.pb->seekable = 0;
2302

2303
        /*
2304
         * HACK to avoid MPEG-PS muxer to spit many underflow errors
2305
         * Default value from FFmpeg
2306
         * Try to set it using configuration option
2307 2308 2309
         */
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);

2310 2311 2312 2313
        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
2314
        }
2315
        av_dict_free(&c->fmt_ctx.metadata);
2316

2317
        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2318 2319 2320 2321
        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
2322 2323 2324 2325
        c->last_packet_sent = 0;
        break;
    case HTTPSTATE_SEND_DATA:
        /* find a new packet */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
        /* 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:
2339 2340 2341
            ret = av_read_frame(c->fmt_in, &pkt);
            if (ret < 0) {
                if (c->stream->feed) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2342
                    /* if coming from feed, it means we reached the end of the
2343
                     * ffm file, so must wait for more data */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2344 2345
                    c->state = HTTPSTATE_WAIT_FEED;
                    return 1; /* state changed */
2346 2347
                }
                if (ret == AVERROR(EAGAIN)) {
2348 2349
                    /* input not ready, come back later */
                    return 0;
2350 2351 2352 2353 2354 2355
                }
                if (c->stream->loop) {
                    avformat_close_input(&c->fmt_in);
                    if (open_input_stream(c, "") < 0)
                        goto no_loop;
                    goto redo;
2356
                } else {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2357
                    no_loop:
2358
                        /* must send trailer now because EOF or error */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2359 2360 2361
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
                }
            } else {
2362
                int source_index = pkt.stream_index;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2363
                /* update first pts if needed */
2364
                if (c->first_pts == AV_NOPTS_VALUE && pkt.dts != AV_NOPTS_VALUE) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2365 2366 2367 2368 2369 2370 2371 2372
                    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;
2373
                        for(i=0;i<c->stream->nb_streams;i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2374
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2375
                                if (pkt.flags & AV_PKT_FLAG_KEY)
Reinhard Tartler's avatar
Reinhard Tartler committed
2376
                                    c->switch_feed_streams[i] = -1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2377 2378
                            if (c->switch_feed_streams[i] >= 0)
                                c->switch_pending = 1;
2379
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2380 2381
                    }
                    for(i=0;i<c->stream->nb_streams;i++) {
2382
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2383
                            AVStream *st = c->fmt_in->streams[source_index];
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2384
                            pkt.stream_index = i;
2385
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2386
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2387
                                 c->stream->nb_streams == 1))
2388 2389
                                c->got_key_frame = 1;
                            if (!c->stream->send_on_key || c->got_key_frame)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2390 2391 2392 2393 2394
                                goto send_it;
                        }
                    }
                } else {
                    AVCodecContext *codec;
2395 2396 2397
                    AVStream *ist, *ost;
                send_it:
                    ist = c->fmt_in->streams[source_index];
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2398
                    /* specific handling for RTP: we use several
2399 2400
                     * output streams (one for each RTP connection).
                     * XXX: need more abstract handling */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2401 2402
                    if (c->is_packetized) {
                        /* compute send time and duration */
2403 2404 2405 2406
                        if (pkt.dts != AV_NOPTS_VALUE) {
                            c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
                            c->cur_pts -= c->first_pts;
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2407
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2408 2409 2410 2411
                        /* find RTP context */
                        c->packet_stream_index = pkt.stream_index;
                        ctx = c->rtp_ctx[c->packet_stream_index];
                        if(!ctx) {
2412
                            av_packet_unref(&pkt);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2413
                            break;
2414
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2415 2416 2417 2418 2419 2420
                        codec = ctx->streams[0]->codec;
                        /* only one stream per RTP connection */
                        pkt.stream_index = 0;
                    } else {
                        ctx = &c->fmt_ctx;
                        /* Fudge here */
2421
                        codec = ctx->streams[pkt.stream_index]->codec;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2422 2423 2424 2425
                    }

                    if (c->is_packetized) {
                        int max_packet_size;
2426
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2427 2428
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
                        else
2429
                            max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2430 2431
                        ret = ffio_open_dyn_packet_buf(&ctx->pb,
                                                       max_packet_size);
2432
                    } else
2433
                        ret = avio_open_dyn_buf(&ctx->pb);
2434

Baptiste Coudurier's avatar
Baptiste Coudurier committed
2435 2436 2437 2438
                    if (ret < 0) {
                        /* XXX: potential leak */
                        return -1;
                    }
2439 2440
                    ost = ctx->streams[pkt.stream_index];

2441
                    ctx->pb->seekable = 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2442
                    if (pkt.dts != AV_NOPTS_VALUE)
2443 2444
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
                                               ost->time_base);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2445
                    if (pkt.pts != AV_NOPTS_VALUE)
2446 2447 2448 2449
                        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);
2450 2451 2452
                    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
2453
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2454
                    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2455

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

                    codec->frame_number++;
                    if (len == 0) {
2465
                        av_packet_unref(&pkt);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2466
                        goto redo;
2467
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2468
                }
2469
                av_packet_unref(&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 2499
 * (either UDP or TCP)
 */
2500
static int http_send_data(HTTPContext *c)
Fabrice Bellard's avatar
Fabrice Bellard committed
2501
{
2502
    int len, ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2503

2504 2505 2506 2507 2508
    for(;;) {
        if (c->buffer_ptr >= c->buffer_end) {
            ret = http_prepare_data(c);
            if (ret < 0)
                return -1;
2509
            else if (ret)
2510 2511
                /* state change requested */
                break;
2512
        } else {
2513 2514 2515 2516 2517 2518 2519
            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;
2520 2521
                    return 0;
                }
2522 2523 2524 2525 2526 2527
                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;
2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
                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;

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

2545 2546 2547 2548 2549
                    rtsp_c = c->rtsp_c;
                    /* if no RTSP connection left, error */
                    if (!rtsp_c)
                        return -1;
                    /* if already sending something, then wait. */
2550
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2551
                        break;
2552
                    if (avio_open_dyn_buf(&pb) < 0)
2553 2554 2555 2556 2557 2558 2559 2560 2561 2562
                        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;
2563
                    avio_write(pb, header, 4);
2564 2565
                    /* write RTP packet data */
                    c->buffer_ptr += 4;
2566
                    avio_write(pb, c->buffer_ptr, len);
2567
                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
2568 2569 2570
                    /* prepare asynchronous TCP sending */
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2571
                    c->buffer_ptr += len;
2572

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

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

static int http_start_receive_data(HTTPContext *c)
{
    int fd;
2624
    int ret;
2625
    int64_t ret64;
Fabrice Bellard's avatar
Fabrice Bellard committed
2626

2627
    if (c->stream->feed_opened) {
2628 2629
        http_log("Stream feed '%s' was not opened\n",
                 c->stream->feed_filename);
2630 2631
        return AVERROR(EINVAL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2632

2633
    /* Don't permit writing to this one */
2634
    if (c->stream->readonly) {
2635 2636
        http_log("Cannot write to read-only file '%s'\n",
                 c->stream->feed_filename);
2637 2638
        return AVERROR(EINVAL);
    }
2639

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

2650 2651 2652 2653
    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);
2654
        if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2655 2656 2657 2658
            ret = AVERROR(errno);
            http_log("Error truncating feed file '%s': %s\n",
                     c->stream->feed_filename, strerror(errno));
            return ret;
2659
        }
2660
    } else {
2661 2662
        ret64 = ffm_read_write_index(fd);
        if (ret64 < 0) {
2663 2664
            http_log("Error reading write index from feed file '%s': %s\n",
                     c->stream->feed_filename, strerror(errno));
2665
            return ret64;
2666
        }
2667
        c->stream->feed_write_index = ret64;
2668 2669
    }

2670 2671
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                        FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
2672 2673 2674 2675 2676 2677 2678
    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;
2679
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
Fabrice Bellard's avatar
Fabrice Bellard committed
2680 2681
    return 0;
}
2682

Fabrice Bellard's avatar
Fabrice Bellard committed
2683 2684 2685
static int http_receive_data(HTTPContext *c)
{
    HTTPContext *c1;
2686
    int len, loop_run = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2687

2688 2689 2690 2691 2692 2693
    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) {
2694 2695
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
2696 2697
                /* error : close connection */
                goto fail;
2698
            return 0;
2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
        } 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;
2709
        } else if (++loop_run > 10)
2710 2711
            /* no chunk header, abort */
            goto fail;
2712
        else
2713 2714
            c->buffer_ptr++;
    }
2715

2716 2717 2718
    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);
2719
        if (len < 0) {
2720 2721
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
2722 2723
                /* error : close connection */
                goto fail;
2724
        } else if (len == 0)
2725 2726
            /* end of connection : close it */
            goto fail;
2727
        else {
2728
            c->chunk_size -= len;
2729 2730
            c->buffer_ptr += len;
            c->data_count += len;
2731
            update_datarate(&c->datarate, c->data_count);
2732 2733 2734
        }
    }

2735 2736 2737 2738 2739 2740 2741 2742
    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
2743
    if (c->buffer_ptr >= c->buffer_end) {
2744
        FFServerStream *feed = c->stream;
Fabrice Bellard's avatar
Fabrice Bellard committed
2745
        /* a packet has been received : write it in the store, except
2746
         * if header */
Fabrice Bellard's avatar
Fabrice Bellard committed
2747
        if (c->data_count > FFM_PACKET_SIZE) {
2748 2749 2750 2751 2752
            /* XXX: use llseek or url_seek
             * XXX: Should probably fail? */
            if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
                http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);

Baptiste Coudurier's avatar
Baptiste Coudurier committed
2753 2754 2755 2756
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
                http_log("Error writing to feed file: %s\n", strerror(errno));
                goto fail;
            }
2757

Fabrice Bellard's avatar
Fabrice Bellard committed
2758 2759 2760 2761 2762 2763
            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 */
2764 2765
            if (c->stream->feed_max_size &&
                feed->feed_write_index >= c->stream->feed_max_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
2766 2767 2768
                feed->feed_write_index = FFM_PACKET_SIZE;

            /* write index */
2769
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2770 2771
                http_log("Error writing index to feed file: %s\n",
                         strerror(errno));
2772 2773
                goto fail;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2774 2775

            /* wake up any waiting connections */
2776
            for(c1 = first_http_ctx; c1; c1 = c1->next) {
2777
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2778
                    c1->stream->feed == c->stream->feed)
Fabrice Bellard's avatar
Fabrice Bellard committed
2779 2780
                    c1->state = HTTPSTATE_SEND_DATA;
            }
2781 2782
        } else {
            /* We have a header in our hands that contains useful data */
2783
            AVFormatContext *s = avformat_alloc_context();
2784
            AVIOContext *pb;
2785
            AVInputFormat *fmt_in;
2786 2787
            int i;

2788 2789 2790
            if (!s)
                goto fail;

2791 2792 2793 2794 2795
            /* use feed output format name to find corresponding input format */
            fmt_in = av_find_input_format(feed->fmt->name);
            if (!fmt_in)
                goto fail;

2796 2797
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
                                    0, NULL, NULL, NULL, NULL);
2798 2799 2800
            if (!pb)
                goto fail;

2801
            pb->seekable = 0;
2802

2803 2804
            s->pb = pb;
            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2805
                av_freep(&pb);
2806 2807
                goto fail;
            }
2808 2809

            /* Now we have the actual streams */
2810
            if (s->nb_streams != feed->nb_streams) {
2811
                avformat_close_input(&s);
2812
                av_freep(&pb);
2813 2814
                http_log("Feed '%s' stream number does not match registered feed\n",
                         c->stream->feed_filename);
2815 2816
                goto fail;
            }
2817

2818 2819 2820
            for (i = 0; i < s->nb_streams; i++) {
                AVStream *fst = feed->streams[i];
                AVStream *st = s->streams[i];
2821
                avcodec_copy_context(fst->codec, st->codec);
2822
            }
2823

2824
            avformat_close_input(&s);
2825
            av_freep(&pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
2826 2827 2828 2829 2830 2831 2832 2833
        }
        c->buffer_ptr = c->buffer;
    }

    return 0;
 fail:
    c->stream->feed_opened = 0;
    close(c->feed_fd);
2834
    /* wake up any waiting connections to stop waiting for feed */
2835
    for(c1 = first_http_ctx; c1; c1 = c1->next) {
2836 2837 2838 2839
        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
2840 2841 2842
    return -1;
}

2843 2844 2845 2846 2847 2848 2849
/********************************************************************/
/* RTSP handling */

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

2853 2854
    str = RTSP_STATUS_CODE2STRING(error_number);
    if (!str)
2855
        str = "Unknown Error";
2856

2857 2858
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2859 2860 2861

    /* output GMT time */
    ti = time(NULL);
2862 2863
    tm = gmtime(&ti);
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2864
    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2865 2866 2867 2868 2869
}

static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
{
    rtsp_reply_header(c, error_number);
2870
    avio_printf(c->pb, "\r\n");
2871 2872 2873 2874 2875 2876 2877 2878 2879 2880
}

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;
2881
    RTSPMessageHeader header1 = { 0 }, *header = &header1;
2882

2883 2884
    c->buffer_ptr[0] = '\0';
    p = c->buffer;
2885

2886 2887 2888 2889
    get_word(cmd, sizeof(cmd), &p);
    get_word(url, sizeof(url), &p);
    get_word(protocol, sizeof(protocol), &p);

2890 2891 2892
    av_strlcpy(c->method, cmd, sizeof(c->method));
    av_strlcpy(c->url, url, sizeof(c->url));
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2893

2894
    if (avio_open_dyn_buf(&c->pb) < 0) {
2895 2896 2897 2898 2899 2900
        /* XXX: cannot do more */
        c->pb = NULL; /* safety */
        return -1;
    }

    /* check version name */
2901
    if (strcmp(protocol, "RTSP/1.0")) {
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
        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') {
2913
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926
        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';
2927
        ff_rtsp_parse_line(NULL, header, line, NULL, NULL);
2928 2929 2930 2931 2932 2933
        p = p1 + 1;
    }

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

2934
    if (!strcmp(cmd, "DESCRIBE"))
2935
        rtsp_cmd_describe(c, url);
2936
    else if (!strcmp(cmd, "OPTIONS"))
2937
        rtsp_cmd_options(c, url);
2938
    else if (!strcmp(cmd, "SETUP"))
2939
        rtsp_cmd_setup(c, url, header);
2940
    else if (!strcmp(cmd, "PLAY"))
2941
        rtsp_cmd_play(c, url, header);
2942
    else if (!strcmp(cmd, "PAUSE"))
2943
        rtsp_cmd_interrupt(c, url, header, 1);
2944
    else if (!strcmp(cmd, "TEARDOWN"))
2945
        rtsp_cmd_interrupt(c, url, header, 0);
2946
    else
2947
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2948

2949
 the_end:
2950
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2951
    c->pb = NULL; /* safety */
2952
    if (len < 0)
2953 2954
        /* XXX: cannot do more */
        return -1;
2955

2956 2957 2958 2959 2960 2961
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
    c->state = RTSPSTATE_SEND_REPLY;
    return 0;
}

2962
static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2963
                                   struct in_addr my_ip)
2964
{
2965
    AVFormatContext *avc;
2966
    AVStream *avs = NULL;
2967
    AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2968
    AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2969
    int i;
2970

2971 2972
    *pbuffer = NULL;

2973
    avc =  avformat_alloc_context();
2974
    if (!avc || !rtp_format)
2975
        return -1;
2976

2977
    avc->oformat = rtp_format;
2978
    av_dict_set(&avc->metadata, "title",
2979
                entry ? entry->value : "No Title", 0);
2980 2981 2982 2983 2984
    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);
2985
    } else
2986
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2987

2988 2989
    avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams));
    if (!avc->streams)
2990
        goto sdp_done;
2991 2992 2993

    avs = av_malloc_array(avc->nb_streams, sizeof(*avs));
    if (!avs)
2994 2995
        goto sdp_done;

2996
    for(i = 0; i < stream->nb_streams; i++) {
2997 2998
        avc->streams[i] = &avs[i];
        avc->streams[i]->codec = stream->streams[i]->codec;
2999 3000
        avcodec_parameters_from_context(stream->streams[i]->codecpar, stream->streams[i]->codec);
        avc->streams[i]->codecpar = stream->streams[i]->codecpar;
3001
    }
3002
    *pbuffer = av_mallocz(2048);
3003 3004
    if (!*pbuffer)
        goto sdp_done;
3005
    av_sdp_create(&avc, 1, *pbuffer, 2048);
3006 3007

 sdp_done:
3008
    av_freep(&avc->streams);
3009
    av_dict_free(&avc->metadata);
3010
    av_free(avc);
3011
    av_free(avs);
3012

3013
    return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
3014 3015
}

3016 3017
static void rtsp_cmd_options(HTTPContext *c, const char *url)
{
3018
    /* rtsp_reply_header(c, RTSP_STATUS_OK); */
3019 3020
    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);
3021 3022
    avio_printf(c->pb, "Public: %s\r\n",
                "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3023
    avio_printf(c->pb, "\r\n");
3024 3025
}

3026 3027
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
{
3028
    FFServerStream *stream;
3029 3030
    char path1[1024];
    const char *path;
3031
    uint8_t *content;
3032 3033
    int content_length;
    socklen_t len;
3034
    struct sockaddr_in my_addr;
3035

3036
    /* find which URL is asked */
3037
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3038 3039 3040 3041
    path = path1;
    if (*path == '/')
        path++;

3042
    for(stream = config.first_stream; stream; stream = stream->next) {
3043 3044
        if (!stream->is_feed &&
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3045 3046 3047 3048 3049
            !strcmp(path, stream->filename)) {
            goto found;
        }
    }
    /* no stream found */
3050
    rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
3051 3052 3053
    return;

 found:
3054
    /* prepare the media description in SDP format */
3055 3056 3057 3058

    /* get the host IP */
    len = sizeof(my_addr);
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3059 3060
    content_length = prepare_sdp_description(stream, &content,
                                             my_addr.sin_addr);
3061 3062 3063 3064 3065
    if (content_length < 0) {
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
        return;
    }
    rtsp_reply_header(c, RTSP_STATUS_OK);
3066 3067 3068 3069
    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");
3070
    avio_write(c->pb, content, content_length);
3071
    av_free(content);
3072 3073 3074 3075 3076 3077 3078 3079 3080
}

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

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

3081
    for(c = first_http_ctx; c; c = c->next) {
3082 3083 3084 3085 3086 3087
        if (!strcmp(c->session_id, session_id))
            return c;
    }
    return NULL;
}

3088
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3089 3090 3091 3092 3093 3094
{
    RTSPTransportField *th;
    int i;

    for(i=0;i<h->nb_transports;i++) {
        th = &h->transports[i];
3095
        if (th->lower_transport == lower_transport)
3096 3097 3098 3099 3100
            return th;
    }
    return NULL;
}

3101
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3102
                           RTSPMessageHeader *h)
3103
{
3104
    FFServerStream *stream;
3105
    int stream_index, rtp_port, rtcp_port;
3106 3107 3108 3109 3110 3111 3112
    char buf[1024];
    char path1[1024];
    const char *path;
    HTTPContext *rtp_c;
    RTSPTransportField *th;
    struct sockaddr_in dest_addr;
    RTSPActionServerSetup setup;
3113

3114
    /* find which URL is asked */
3115
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3116 3117 3118 3119 3120
    path = path1;
    if (*path == '/')
        path++;

    /* now check each stream */
3121
    for(stream = config.first_stream; stream; stream = stream->next) {
3122 3123 3124 3125
        if (stream->is_feed || !stream->fmt ||
            strcmp(stream->fmt->name, "rtp")) {
            continue;
        }
3126 3127 3128 3129 3130
        /* 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;
3131
            }
3132 3133 3134
            stream_index = 0;
            goto found;
        }
3135

3136 3137 3138 3139 3140 3141 3142
        for(stream_index = 0; stream_index < stream->nb_streams;
            stream_index++) {
            snprintf(buf, sizeof(buf), "%s/streamid=%d",
                     stream->filename, stream_index);
            if (!strcmp(path, buf))
                goto found;
        }
3143 3144 3145 3146 3147 3148 3149
    }
    /* no stream found */
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
    return;
 found:

    /* generate session id if needed */
3150 3151 3152
    if (h->session_id[0] == '\0') {
        unsigned random0 = av_lfg_get(&random_state);
        unsigned random1 = av_lfg_get(&random_state);
3153
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3154 3155
                 random0, random1);
    }
3156

3157
    /* find RTP session, and create it if none found */
3158 3159
    rtp_c = find_rtp_session(h->session_id);
    if (!rtp_c) {
3160
        /* always prefer UDP */
3161
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3162
        if (!th) {
3163
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3164 3165 3166 3167 3168 3169 3170
            if (!th) {
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
                return;
            }
        }

        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3171
                                   th->lower_transport);
3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182
        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;
        }
    }
3183

3184
    /* test if stream is OK (test needed because several SETUP needs
3185
     * to be done for a given file) */
3186 3187 3188 3189
    if (rtp_c->stream != stream) {
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
        return;
    }
3190

3191 3192 3193 3194 3195 3196 3197 3198
    /* 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);
3199
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3200 3201 3202 3203 3204 3205 3206 3207 3208
                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);
3209

3210
    /* setup stream */
3211
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3212 3213 3214 3215 3216 3217 3218
        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 */
3219
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3220 3221

    switch(rtp_c->rtp_protocol) {
3222
    case RTSP_LOWER_TRANSPORT_UDP:
3223 3224
        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]);
3225
        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3226
                    "client_port=%d-%d;server_port=%d-%d",
3227 3228
                    th->client_port_min, th->client_port_max,
                    rtp_port, rtcp_port);
3229
        break;
3230
    case RTSP_LOWER_TRANSPORT_TCP:
3231
        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3232 3233 3234 3235 3236
                    stream_index * 2, stream_index * 2 + 1);
        break;
    default:
        break;
    }
3237
    if (setup.transport_option[0] != '\0')
3238 3239
        avio_printf(c->pb, ";%s", setup.transport_option);
    avio_printf(c->pb, "\r\n");
3240

3241

3242
    avio_printf(c->pb, "\r\n");
3243 3244 3245
}


3246 3247 3248 3249
/**
 * find an RTP connection by using the session ID. Check consistency
 * with filename
 */
3250
static HTTPContext *find_rtp_session_with_url(const char *url,
3251 3252 3253 3254 3255
                                              const char *session_id)
{
    HTTPContext *rtp_c;
    char path1[1024];
    const char *path;
3256
    char buf[1024];
3257
    int s, len;
3258 3259 3260 3261 3262

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

3263
    /* find which URL is asked */
3264
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3265 3266 3267
    path = path1;
    if (*path == '/')
        path++;
3268 3269 3270 3271
    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);
3272 3273 3274
      if(!strncmp(path, buf, sizeof(buf)))
        /* XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE
         * if nb_streams>1? */
3275 3276
        return rtp_c;
    }
3277 3278 3279 3280
    len = strlen(path);
    if (len > 0 && path[len - 1] == '/' &&
        !strncmp(path, rtp_c->stream->filename, len - 1))
        return rtp_c;
3281
    return NULL;
3282 3283
}

3284
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3285 3286 3287 3288 3289 3290 3291 3292
{
    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;
    }
3293

3294 3295 3296 3297 3298 3299 3300 3301
    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;
3302

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

3310 3311
static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
                               RTSPMessageHeader *h, int pause_only)
3312 3313 3314 3315 3316 3317 3318 3319
{
    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;
    }
3320

3321 3322 3323 3324 3325 3326 3327 3328
    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;
3329
    }
3330

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

3337 3338
    if (!pause_only)
        close_connection(rtp_c);
3339 3340 3341 3342 3343
}

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

3344
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3345 3346
                                       FFServerStream *stream,
                                       const char *session_id,
3347
                                       enum RTSPLowerTransport rtp_protocol)
3348 3349
{
    HTTPContext *c = NULL;
3350
    const char *proto_str;
3351

3352
    /* XXX: should output a warning page when coming
3353
     * close to the connection limit */
3354
    if (nb_connections >= config.nb_max_connections)
3355
        goto fail;
3356

3357 3358 3359 3360
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
3361

3362 3363
    c->fd = -1;
    c->poll_entry = NULL;
3364
    c->from_addr = *from_addr;
3365 3366 3367 3368 3369 3370
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;
    nb_connections++;
    c->stream = stream;
3371
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3372 3373
    c->state = HTTPSTATE_READY;
    c->is_packetized = 1;
3374 3375
    c->rtp_protocol = rtp_protocol;

3376
    /* protocol is shown in statistics */
3377
    switch(c->rtp_protocol) {
3378
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3379 3380
        proto_str = "MCAST";
        break;
3381
    case RTSP_LOWER_TRANSPORT_UDP:
3382 3383
        proto_str = "UDP";
        break;
3384
    case RTSP_LOWER_TRANSPORT_TCP:
3385 3386 3387 3388 3389 3390
        proto_str = "TCP";
        break;
    default:
        proto_str = "???";
        break;
    }
3391 3392
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3393

3394 3395
    current_bandwidth += stream->bandwidth;

3396 3397 3398
    c->next = first_http_ctx;
    first_http_ctx = c;
    return c;
3399

3400 3401
 fail:
    if (c) {
3402
        av_freep(&c->buffer);
3403 3404 3405 3406 3407
        av_free(c);
    }
    return NULL;
}

3408 3409 3410 3411 3412
/**
 * add a new RTP stream in an RTP connection (used in RTSP SETUP
 * command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
 * used.
 */
3413
static int rtp_new_av_stream(HTTPContext *c,
3414 3415
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c)
3416 3417 3418 3419
{
    AVFormatContext *ctx;
    AVStream *st;
    char *ipaddr;
3420
    URLContext *h = NULL;
3421
    uint8_t *dummy_buf;
3422
    int max_packet_size;
3423
    void *st_internal;
3424

3425
    /* now we can open the relevant output stream */
3426
    ctx = avformat_alloc_context();
3427 3428
    if (!ctx)
        return -1;
3429
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3430

3431
    st = avformat_new_stream(ctx, NULL);
3432 3433
    if (!st)
        goto fail;
3434 3435 3436 3437

    av_freep(&st->codec);
    av_freep(&st->info);
    st_internal = st->internal;
3438

3439
    if (!c->stream->feed ||
3440
        c->stream->feed == c->stream)
3441
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3442
    else
3443
        memcpy(st,
3444 3445
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
               sizeof(AVStream));
3446
    st->priv_data = NULL;
3447
    st->internal = st_internal;
3448

3449 3450 3451 3452
    /* build destination RTP address */
    ipaddr = inet_ntoa(dest_addr->sin_addr);

    switch(c->rtp_protocol) {
3453 3454
    case RTSP_LOWER_TRANSPORT_UDP:
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3455
        /* RTP/UDP case */
3456

3457 3458 3459 3460 3461 3462 3463
        /* 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),
3464
                     "rtp://%s:%d?multicast=1&ttl=%d",
3465 3466 3467 3468 3469
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
        } else {
            snprintf(ctx->filename, sizeof(ctx->filename),
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
        }
3470

3471
        if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3472 3473
            goto fail;
        c->rtp_handles[stream_index] = h;
3474
        max_packet_size = h->max_packet_size;
3475
        break;
3476
    case RTSP_LOWER_TRANSPORT_TCP:
3477 3478 3479 3480 3481
        /* RTP/TCP case */
        c->rtsp_c = rtsp_c;
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
        break;
    default:
3482 3483 3484
        goto fail;
    }

3485
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3486
             ipaddr, ntohs(dest_addr->sin_port),
3487
             c->stream->filename, stream_index, c->protocol);
3488

3489 3490
    /* normally, no packets should be output here, but the packet size may
     * be checked */
3491
    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0)
3492 3493
        /* XXX: close stream */
        goto fail;
3494

3495
    if (avformat_write_header(ctx, NULL) < 0) {
3496 3497
    fail:
        if (h)
3498
            ffurl_close(h);
3499
        av_free(st);
3500 3501 3502
        av_free(ctx);
        return -1;
    }
3503
    avio_close_dyn_buf(ctx->pb, &dummy_buf);
3504
    ctx->pb = NULL;
3505
    av_free(dummy_buf);
3506

3507 3508 3509 3510 3511 3512 3513
    c->rtp_ctx[stream_index] = ctx;
    return 0;
}

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

3514
/* FIXME: This code should use avformat_new_stream() */
3515 3516
static AVStream *add_av_stream1(FFServerStream *stream,
                                AVCodecContext *codec, int copy)
3517 3518 3519
{
    AVStream *fst;

3520 3521 3522
    if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
        return NULL;

3523 3524 3525
    fst = av_mallocz(sizeof(AVStream));
    if (!fst)
        return NULL;
3526
    if (copy) {
3527
        fst->codec = avcodec_alloc_context3(codec->codec);
3528 3529 3530 3531
        if (!fst->codec) {
            av_free(fst);
            return NULL;
        }
3532
        avcodec_copy_context(fst->codec, codec);
3533
    } else
3534
        /* live streams must use the actual feed's codec since it may be
3535
         * updated later to carry extradata needed by them.
3536 3537
         */
        fst->codec = codec;
3538

3539
    fst->priv_data = av_mallocz(sizeof(FeedData));
3540
    fst->internal = av_mallocz(sizeof(*fst->internal));
3541 3542
    fst->internal->avctx = avcodec_alloc_context3(NULL);
    fst->codecpar = avcodec_parameters_alloc();
3543
    fst->index = stream->nb_streams;
3544
    avpriv_set_pts_info(fst, 33, 1, 90000);
3545
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3546 3547 3548 3549
    stream->streams[stream->nb_streams++] = fst;
    return fst;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3550
/* return the stream number in the feed */
3551
static int add_av_stream(FFServerStream *feed, AVStream *st)
Fabrice Bellard's avatar
Fabrice Bellard committed
3552 3553 3554 3555 3556
{
    AVStream *fst;
    AVCodecContext *av, *av1;
    int i;

3557
    av = st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
3558
    for(i=0;i<feed->nb_streams;i++) {
3559
        av1 = feed->streams[i]->codec;
3560 3561
        if (av1->codec_id == av->codec_id &&
            av1->codec_type == av->codec_type &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3562 3563 3564
            av1->bit_rate == av->bit_rate) {

            switch(av->codec_type) {
3565
            case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3566 3567
                if (av1->channels == av->channels &&
                    av1->sample_rate == av->sample_rate)
3568
                    return i;
Fabrice Bellard's avatar
Fabrice Bellard committed
3569
                break;
3570
            case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3571 3572
                if (av1->width == av->width &&
                    av1->height == av->height &&
3573 3574
                    av1->time_base.den == av->time_base.den &&
                    av1->time_base.num == av->time_base.num &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3575
                    av1->gop_size == av->gop_size)
3576
                    return i;
Fabrice Bellard's avatar
Fabrice Bellard committed
3577
                break;
3578
            default:
3579
                abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
3580 3581 3582
            }
        }
    }
3583

3584
    fst = add_av_stream1(feed, av, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
3585 3586
    if (!fst)
        return -1;
3587 3588 3589
    if (av_stream_get_recommended_encoder_configuration(st))
        av_stream_set_recommended_encoder_configuration(fst,
            av_strdup(av_stream_get_recommended_encoder_configuration(st)));
Fabrice Bellard's avatar
Fabrice Bellard committed
3590 3591 3592
    return feed->nb_streams - 1;
}

3593
static void remove_stream(FFServerStream *stream)
3594
{
3595 3596
    FFServerStream **ps;
    ps = &config.first_stream;
3597
    while (*ps) {
3598
        if (*ps == stream)
3599
            *ps = (*ps)->next;
3600
        else
3601 3602 3603 3604
            ps = &(*ps)->next;
    }
}

3605
/* specific MPEG4 handling : we extract the raw parameters */
3606
static void extract_mpeg4_header(AVFormatContext *infile)
3607 3608 3609 3610
{
    int mpeg4_count, i, size;
    AVPacket pkt;
    AVStream *st;
3611
    const uint8_t *p;
3612

3613 3614
    infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;

3615 3616 3617
    mpeg4_count = 0;
    for(i=0;i<infile->nb_streams;i++) {
        st = infile->streams[i];
3618
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3619
            st->codec->extradata_size == 0) {
3620 3621 3622 3623 3624 3625
            mpeg4_count++;
        }
    }
    if (!mpeg4_count)
        return;

3626 3627
    printf("MPEG4 without extra data: trying to find header in %s\n",
           infile->filename);
3628
    while (mpeg4_count > 0) {
3629
        if (av_read_frame(infile, &pkt) < 0)
3630 3631
            break;
        st = infile->streams[pkt.stream_index];
3632
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3633 3634
            st->codec->extradata_size == 0) {
            av_freep(&st->codec->extradata);
3635 3636 3637 3638 3639
            /* 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 */
3640
                if (p[0] == 0x00 && p[1] == 0x00 &&
3641 3642
                    p[2] == 0x01 && p[3] == 0xb6) {
                    size = p - pkt.data;
3643
                    st->codec->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
3644 3645
                    st->codec->extradata_size = size;
                    memcpy(st->codec->extradata, pkt.data, size);
3646 3647 3648 3649 3650 3651
                    break;
                }
                p++;
            }
            mpeg4_count--;
        }
3652
        av_packet_unref(&pkt);
3653 3654 3655
    }
}

3656
/* compute the needed AVStream for each file */
3657
static void build_file_streams(void)
3658
{
3659 3660
    FFServerStream *stream;
    AVFormatContext *infile;
3661
    int i, ret;
3662 3663

    /* gather all streams */
3664 3665
    for(stream = config.first_stream; stream; stream = stream->next) {
        infile = NULL;
3666

3667 3668 3669 3670 3671 3672
        if (stream->stream_type != STREAM_TYPE_LIVE || stream->feed)
            continue;

        /* the stream comes from a file */
        /* try to open the file */
        /* open stream */
3673

3674

3675 3676 3677 3678
        /* specific case: if transport stream output to RTP,
         * we use a raw transport stream reader */
        if (stream->fmt && !strcmp(stream->fmt->name, "rtp"))
            av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3679

3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702
        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);

        ret = avformat_open_input(&infile, stream->feed_filename,
                                  stream->ifmt, &stream->in_opts);
        if (ret < 0) {
            http_log("Could not open '%s': %s\n", stream->feed_filename,
                     av_err2str(ret));
            /* 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' */
            if (avformat_find_stream_info(infile, NULL) < 0) {
                http_log("Could not find codec parameters from '%s'\n",
                         stream->feed_filename);
3703
                avformat_close_input(&infile);
3704
                goto fail;
3705
            }
3706 3707 3708 3709 3710 3711
            extract_mpeg4_header(infile);

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

            avformat_close_input(&infile);
3712 3713 3714 3715
        }
    }
}

3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750
static inline
int check_codec_match(AVCodecContext *ccf, AVCodecContext *ccs, int stream)
{
    int matches = 1;

#define CHECK_CODEC(x)  (ccf->x != ccs->x)
    if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
        http_log("Codecs do not match for stream %d\n", stream);
        matches = 0;
    } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
        http_log("Codec bitrates do not match for stream %d\n", stream);
        matches = 0;
    } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
        if (CHECK_CODEC(time_base.den) ||
            CHECK_CODEC(time_base.num) ||
            CHECK_CODEC(width) ||
            CHECK_CODEC(height)) {
            http_log("Codec width, height or framerate do not match for stream %d\n", stream);
            matches = 0;
        }
    } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
        if (CHECK_CODEC(sample_rate) ||
            CHECK_CODEC(channels) ||
            CHECK_CODEC(frame_size)) {
            http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", stream);
            matches = 0;
        }
    } else {
        http_log("Unknown codec type for stream %d\n", stream);
        matches = 0;
    }

    return matches;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3751
/* compute the needed AVStream for each feed */
3752
static int build_feed_streams(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3753
{
3754
    FFServerStream *stream, *feed;
3755
    int i, fd;
Fabrice Bellard's avatar
Fabrice Bellard committed
3756

3757
    /* gather all streams */
3758
    for(stream = config.first_stream; stream; stream = stream->next) {
3759
        feed = stream->feed;
3760 3761 3762 3763 3764 3765
        if (!feed)
            continue;

        if (stream->is_feed) {
            for(i=0;i<stream->nb_streams;i++)
                stream->feed_streams[i] = i;
3766
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
3767
        }
3768 3769 3770
        /* 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
3771 3772 3773
    }

    /* create feed files if needed */
3774
    for(feed = config.first_feed; feed; feed = feed->next_feed) {
Fabrice Bellard's avatar
Fabrice Bellard committed
3775

3776
        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3777
            AVFormatContext *s = NULL;
3778 3779
            int matches = 0;

3780
            /* See if it matches */
3781

3782 3783 3784 3785 3786 3787
            if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) < 0) {
                http_log("Deleting feed file '%s' as it appears "
                            "to be corrupt\n",
                         feed->feed_filename);
                goto drop;
            }
3788

3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809
            /* set buffer size */
            if (ffio_set_buf_size(s->pb, FFM_PACKET_SIZE) < 0) {
                http_log("Failed to set buffer size\n");
                avformat_close_input(&s);
                goto bail;
            }

            /* Now see if it matches */
            if (s->nb_streams != feed->nb_streams) {
                http_log("Deleting feed file '%s' as stream counts "
                            "differ (%d != %d)\n",
                         feed->feed_filename, s->nb_streams, feed->nb_streams);
                goto drop;
            }

            matches = 1;
            for(i=0;i<s->nb_streams;i++) {
                AVStream *sf, *ss;

                sf = feed->streams[i];
                ss = s->streams[i];
3810

3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824
                if (sf->index != ss->index || sf->id != ss->id) {
                    http_log("Index & Id do not match for stream %d (%s)\n",
                             i, feed->feed_filename);
                    matches = 0;
                    break;
                }

                matches = check_codec_match (sf->codec, ss->codec, i);
                if (!matches)
                    break;
            }

drop:
            if (s)
3825
                avformat_close_input(&s);
3826

3827 3828
            if (!matches) {
                if (feed->readonly) {
3829 3830
                    http_log("Unable to delete read-only feed file '%s'\n",
                             feed->feed_filename);
3831
                    goto bail;
3832
                }
3833
                unlink(feed->feed_filename);
3834
            }
3835
        }
3836

3837
        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3838
            AVFormatContext *s = avformat_alloc_context();
Fabrice Bellard's avatar
Fabrice Bellard committed
3839

3840 3841
            if (!s) {
                http_log("Failed to allocate context\n");
3842
                goto bail;
3843 3844
            }

3845
            if (feed->readonly) {
3846 3847 3848 3849
                http_log("Unable to create feed file '%s' as it is "
                            "marked readonly\n",
                         feed->feed_filename);
                avformat_free_context(s);
3850
                goto bail;
3851 3852
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
3853
            /* only write the header of the ffm file */
3854
            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3855 3856
                http_log("Could not open output feed file '%s'\n",
                         feed->feed_filename);
3857
                avformat_free_context(s);
3858
                goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
3859
            }
3860
            s->oformat = feed->fmt;
Fabrice Bellard's avatar
Fabrice Bellard committed
3861
            s->nb_streams = feed->nb_streams;
Mike William's avatar
Mike William committed
3862
            s->streams = feed->streams;
3863
            if (avformat_write_header(s, NULL) < 0) {
3864
                http_log("Container doesn't support the required parameters\n");
3865
                avio_closep(&s->pb);
3866 3867
                s->streams = NULL;
                s->nb_streams = 0;
3868
                avformat_free_context(s);
3869
                goto bail;
3870
            }
3871
            /* XXX: need better API */
3872
            av_freep(&s->priv_data);
3873
            avio_closep(&s->pb);
3874 3875 3876
            s->streams = NULL;
            s->nb_streams = 0;
            avformat_free_context(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
3877
        }
3878

Fabrice Bellard's avatar
Fabrice Bellard committed
3879 3880 3881
        /* get feed size and write index */
        fd = open(feed->feed_filename, O_RDONLY);
        if (fd < 0) {
3882
            http_log("Could not open output feed file '%s'\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
3883
                    feed->feed_filename);
3884
            goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
3885 3886
        }

3887 3888
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                       FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
3889 3890
        feed->feed_size = lseek(fd, 0, SEEK_END);
        /* ensure that we do not wrap before the end of file */
3891
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
3892 3893 3894 3895
            feed->feed_max_size = feed->feed_size;

        close(fd);
    }
3896 3897 3898 3899
    return 0;

bail:
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3900 3901
}

3902 3903 3904
/* compute the bandwidth used by each stream */
static void compute_bandwidth(void)
{
3905 3906
    unsigned bandwidth;
    int i;
3907
    FFServerStream *stream;
3908

3909
    for(stream = config.first_stream; stream; stream = stream->next) {
3910 3911 3912
        bandwidth = 0;
        for(i=0;i<stream->nb_streams;i++) {
            AVStream *st = stream->streams[i];
3913
            switch(st->codec->codec_type) {
3914 3915
            case AVMEDIA_TYPE_AUDIO:
            case AVMEDIA_TYPE_VIDEO:
3916
                bandwidth += st->codec->bit_rate;
3917 3918 3919 3920 3921 3922 3923 3924 3925
                break;
            default:
                break;
            }
        }
        stream->bandwidth = (bandwidth + 999) / 1000;
    }
}

3926 3927 3928
static void handle_child_exit(int sig)
{
    pid_t pid;
3929 3930
    int status;
    time_t uptime;
3931 3932

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

3935
        for (feed = config.first_feed; feed; feed = feed->next) {
3936 3937
            if (feed->pid != pid)
                continue;
3938

3939 3940 3941
            uptime = time(0) - feed->pid_start;
            feed->pid = 0;
            fprintf(stderr,
3942 3943
                    "%s: Pid %"PRId64" exited with status %d after %"PRId64" "
                        "seconds\n",
3944
                    feed->filename, (int64_t) pid, status, (int64_t)uptime);
3945

3946 3947 3948
            if (uptime < 30)
                /* Turn off any more restarts */
                ffserver_free_child_args(&feed->child_argv);
3949 3950 3951 3952 3953 3954
        }
    }

    need_to_start_children = 1;
}

3955
static void opt_debug(void)
3956
{
3957 3958
    config.debug = 1;
    snprintf(config.logfilename, sizeof(config.logfilename), "-");
3959 3960
}

3961
void show_help_default(const char *opt, const char *arg)
3962
{
3963
    printf("usage: ffserver [options]\n"
3964 3965
           "Hyper fast multi format Audio/Video streaming server\n");
    printf("\n");
3966
    show_help_options(options, "Main options:", 0, 0, 0);
3967 3968 3969
}

static const OptionDef options[] = {
3970
#include "cmdutils_common_opts.h"
3971 3972
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3973
    { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3974 3975 3976
    { NULL },
};

Fabrice Bellard's avatar
Fabrice Bellard committed
3977 3978
int main(int argc, char **argv)
{
3979
    struct sigaction sigact = { { 0 } };
3980 3981 3982
    int cfg_parsed;
    int ret = EXIT_FAILURE;

3983
    init_dynload();
Fabrice Bellard's avatar
Fabrice Bellard committed
3984

3985
    config.filename = av_strdup("/etc/ffserver.conf");
3986

3987
    parse_loglevel(argc, argv, options);
3988
    av_register_all();
3989
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3990

3991
    show_banner(argc, argv, options);
3992

3993
    my_program_name = argv[0];
3994

3995
    parse_options(NULL, argc, argv, options, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3996

3997
    unsetenv("http_proxy");             /* Kill the http_proxy */
3998

3999
    av_lfg_init(&random_state, av_get_random_seed());
4000

4001 4002 4003 4004
    sigact.sa_handler = handle_child_exit;
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    sigaction(SIGCHLD, &sigact, 0);

4005
    if ((cfg_parsed = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
4006
        fprintf(stderr, "Error reading configuration file '%s': %s\n",
4007 4008
                config.filename, av_err2str(cfg_parsed));
        goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
4009 4010
    }

4011
    /* open log file if needed */
4012 4013
    if (config.logfilename[0] != '\0') {
        if (!strcmp(config.logfilename, "-"))
4014
            logfile = stdout;
4015
        else
4016
            logfile = fopen(config.logfilename, "a");
4017 4018 4019
        av_log_set_callback(http_av_log);
    }

4020 4021
    build_file_streams();

4022 4023 4024 4025
    if (build_feed_streams() < 0) {
        http_log("Could not setup feed streams\n");
        goto bail;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
4026

4027 4028
    compute_bandwidth();

Fabrice Bellard's avatar
Fabrice Bellard committed
4029 4030 4031
    /* signal init */
    signal(SIGPIPE, SIG_IGN);

4032
    if (http_server() < 0) {
4033
        http_log("Could not start server\n");
4034
        goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
4035 4036
    }

4037 4038 4039 4040 4041 4042
    ret=EXIT_SUCCESS;

bail:
    av_freep (&config.filename);
    avformat_network_deinit();
    return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
4043
}