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;
Fabrice Bellard's avatar
Fabrice Bellard committed
2625

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

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

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

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

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

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

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

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

2734 2735 2736 2737 2738 2739 2740 2741
    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
2742
    if (c->buffer_ptr >= c->buffer_end) {
2743
        FFServerStream *feed = c->stream;
Fabrice Bellard's avatar
Fabrice Bellard committed
2744
        /* a packet has been received : write it in the store, except
2745
         * if header */
Fabrice Bellard's avatar
Fabrice Bellard committed
2746
        if (c->data_count > FFM_PACKET_SIZE) {
2747 2748 2749 2750 2751
            /* 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
2752 2753 2754 2755
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
                http_log("Error writing to feed file: %s\n", strerror(errno));
                goto fail;
            }
2756

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

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

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

2787 2788 2789
            if (!s)
                goto fail;

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

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

2800
            pb->seekable = 0;
2801

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2970 2971
    *pbuffer = NULL;

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

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

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

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

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

 sdp_done:
3005
    av_freep(&avc->streams);
3006
    av_dict_free(&avc->metadata);
3007
    av_free(avc);
3008
    av_free(avs);
3009

3010
    return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
3011 3012
}

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

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

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

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

 found:
3051
    /* prepare the media description in SDP format */
3052 3053 3054 3055

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

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

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

3078
    for(c = first_http_ctx; c; c = c->next) {
3079 3080 3081 3082 3083 3084
        if (!strcmp(c->session_id, session_id))
            return c;
    }
    return NULL;
}

3085
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3086 3087 3088 3089 3090 3091
{
    RTSPTransportField *th;
    int i;

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

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

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

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

3133 3134 3135 3136 3137 3138 3139
        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;
        }
3140 3141 3142 3143 3144 3145 3146
    }
    /* no stream found */
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
    return;
 found:

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

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

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

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

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

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

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

3238

3239
    avio_printf(c->pb, "\r\n");
3240 3241 3242
}


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

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

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

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

3291 3292 3293 3294 3295 3296 3297 3298
    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;
3299

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

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

3318 3319 3320 3321 3322 3323 3324 3325
    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;
3326
    }
3327

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

3334 3335
    if (!pause_only)
        close_connection(rtp_c);
3336 3337 3338 3339 3340
}

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

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

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

3354 3355 3356 3357
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
3358

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

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

3391 3392
    current_bandwidth += stream->bandwidth;

3393 3394 3395
    c->next = first_http_ctx;
    first_http_ctx = c;
    return c;
3396

3397 3398
 fail:
    if (c) {
3399
        av_freep(&c->buffer);
3400 3401 3402 3403 3404
        av_free(c);
    }
    return NULL;
}

3405 3406 3407 3408 3409
/**
 * 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.
 */
3410
static int rtp_new_av_stream(HTTPContext *c,
3411 3412
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c)
3413 3414 3415 3416
{
    AVFormatContext *ctx;
    AVStream *st;
    char *ipaddr;
3417
    URLContext *h = NULL;
3418
    uint8_t *dummy_buf;
3419
    int max_packet_size;
3420
    void *st_internal;
3421

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

3428
    st = avformat_new_stream(ctx, NULL);
3429 3430
    if (!st)
        goto fail;
3431 3432 3433 3434

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

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

3446 3447 3448 3449
    /* build destination RTP address */
    ipaddr = inet_ntoa(dest_addr->sin_addr);

    switch(c->rtp_protocol) {
3450 3451
    case RTSP_LOWER_TRANSPORT_UDP:
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3452
        /* RTP/UDP case */
3453

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

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

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

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

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

3504 3505 3506 3507 3508 3509 3510
    c->rtp_ctx[stream_index] = ctx;
    return 0;
}

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

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

3517 3518 3519
    if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
        return NULL;

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

3536
    fst->priv_data = av_mallocz(sizeof(FeedData));
3537
    fst->internal = av_mallocz(sizeof(*fst->internal));
3538
    fst->index = stream->nb_streams;
3539
    avpriv_set_pts_info(fst, 33, 1, 90000);
3540
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3541 3542 3543 3544
    stream->streams[stream->nb_streams++] = fst;
    return fst;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3545
/* return the stream number in the feed */
3546
static int add_av_stream(FFServerStream *feed, AVStream *st)
Fabrice Bellard's avatar
Fabrice Bellard committed
3547 3548 3549 3550 3551
{
    AVStream *fst;
    AVCodecContext *av, *av1;
    int i;

3552
    av = st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
3553
    for(i=0;i<feed->nb_streams;i++) {
3554
        av1 = feed->streams[i]->codec;
3555 3556
        if (av1->codec_id == av->codec_id &&
            av1->codec_type == av->codec_type &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3557 3558 3559
            av1->bit_rate == av->bit_rate) {

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

3579
    fst = add_av_stream1(feed, av, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
3580 3581
    if (!fst)
        return -1;
3582 3583 3584
    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
3585 3586 3587
    return feed->nb_streams - 1;
}

3588
static void remove_stream(FFServerStream *stream)
3589
{
3590 3591
    FFServerStream **ps;
    ps = &config.first_stream;
3592
    while (*ps) {
3593
        if (*ps == stream)
3594
            *ps = (*ps)->next;
3595
        else
3596 3597 3598 3599
            ps = &(*ps)->next;
    }
}

3600
/* specific MPEG4 handling : we extract the raw parameters */
3601
static void extract_mpeg4_header(AVFormatContext *infile)
3602 3603 3604 3605
{
    int mpeg4_count, i, size;
    AVPacket pkt;
    AVStream *st;
3606
    const uint8_t *p;
3607

3608 3609
    infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;

3610 3611 3612
    mpeg4_count = 0;
    for(i=0;i<infile->nb_streams;i++) {
        st = infile->streams[i];
3613
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3614
            st->codec->extradata_size == 0) {
3615 3616 3617 3618 3619 3620
            mpeg4_count++;
        }
    }
    if (!mpeg4_count)
        return;

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

3651
/* compute the needed AVStream for each file */
3652
static void build_file_streams(void)
3653
{
3654 3655
    FFServerStream *stream;
    AVFormatContext *infile;
3656
    int i, ret;
3657 3658

    /* gather all streams */
3659 3660
    for(stream = config.first_stream; stream; stream = stream->next) {
        infile = NULL;
3661

3662 3663 3664 3665 3666 3667
        if (stream->stream_type != STREAM_TYPE_LIVE || stream->feed)
            continue;

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

3669

3670 3671 3672 3673
        /* 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);
3674

3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697
        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);
3698
                avformat_close_input(&infile);
3699
                goto fail;
3700
            }
3701 3702 3703 3704 3705 3706
            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);
3707 3708 3709 3710
        }
    }
}

3711 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
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
3746
/* compute the needed AVStream for each feed */
3747
static int build_feed_streams(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3748
{
3749
    FFServerStream *stream, *feed;
3750
    int i, fd;
Fabrice Bellard's avatar
Fabrice Bellard committed
3751

3752
    /* gather all streams */
3753
    for(stream = config.first_stream; stream; stream = stream->next) {
3754
        feed = stream->feed;
3755 3756 3757 3758 3759 3760
        if (!feed)
            continue;

        if (stream->is_feed) {
            for(i=0;i<stream->nb_streams;i++)
                stream->feed_streams[i] = i;
3761
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
3762
        }
3763 3764 3765
        /* 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
3766 3767 3768
    }

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

3771
        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3772
            AVFormatContext *s = NULL;
3773 3774
            int matches = 0;

3775
            /* See if it matches */
3776

3777 3778 3779 3780 3781 3782
            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;
            }
3783

3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804
            /* 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];
3805

3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819
                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)
3820
                avformat_close_input(&s);
3821

3822 3823
            if (!matches) {
                if (feed->readonly) {
3824 3825
                    http_log("Unable to delete read-only feed file '%s'\n",
                             feed->feed_filename);
3826
                    goto bail;
3827
                }
3828
                unlink(feed->feed_filename);
3829
            }
3830
        }
3831

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

3835 3836
            if (!s) {
                http_log("Failed to allocate context\n");
3837
                goto bail;
3838 3839
            }

3840
            if (feed->readonly) {
3841 3842 3843 3844
                http_log("Unable to create feed file '%s' as it is "
                            "marked readonly\n",
                         feed->feed_filename);
                avformat_free_context(s);
3845
                goto bail;
3846 3847
            }

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

Fabrice Bellard's avatar
Fabrice Bellard committed
3872 3873 3874
        /* get feed size and write index */
        fd = open(feed->feed_filename, O_RDONLY);
        if (fd < 0) {
3875
            http_log("Could not open output feed file '%s'\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
3876
                    feed->feed_filename);
3877
            goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
3878 3879
        }

3880 3881
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                       FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
3882 3883
        feed->feed_size = lseek(fd, 0, SEEK_END);
        /* ensure that we do not wrap before the end of file */
3884
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
3885 3886 3887 3888
            feed->feed_max_size = feed->feed_size;

        close(fd);
    }
3889 3890 3891 3892
    return 0;

bail:
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3893 3894
}

3895 3896 3897
/* compute the bandwidth used by each stream */
static void compute_bandwidth(void)
{
3898 3899
    unsigned bandwidth;
    int i;
3900
    FFServerStream *stream;
3901

3902
    for(stream = config.first_stream; stream; stream = stream->next) {
3903 3904 3905
        bandwidth = 0;
        for(i=0;i<stream->nb_streams;i++) {
            AVStream *st = stream->streams[i];
3906
            switch(st->codec->codec_type) {
3907 3908
            case AVMEDIA_TYPE_AUDIO:
            case AVMEDIA_TYPE_VIDEO:
3909
                bandwidth += st->codec->bit_rate;
3910 3911 3912 3913 3914 3915 3916 3917 3918
                break;
            default:
                break;
            }
        }
        stream->bandwidth = (bandwidth + 999) / 1000;
    }
}

3919 3920 3921
static void handle_child_exit(int sig)
{
    pid_t pid;
3922 3923
    int status;
    time_t uptime;
3924 3925

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

3928
        for (feed = config.first_feed; feed; feed = feed->next) {
3929 3930
            if (feed->pid != pid)
                continue;
3931

3932 3933 3934
            uptime = time(0) - feed->pid_start;
            feed->pid = 0;
            fprintf(stderr,
3935 3936
                    "%s: Pid %"PRId64" exited with status %d after %"PRId64" "
                        "seconds\n",
3937
                    feed->filename, (int64_t) pid, status, (int64_t)uptime);
3938

3939 3940 3941
            if (uptime < 30)
                /* Turn off any more restarts */
                ffserver_free_child_args(&feed->child_argv);
3942 3943 3944 3945 3946 3947
        }
    }

    need_to_start_children = 1;
}

3948
static void opt_debug(void)
3949
{
3950 3951
    config.debug = 1;
    snprintf(config.logfilename, sizeof(config.logfilename), "-");
3952 3953
}

3954
void show_help_default(const char *opt, const char *arg)
3955
{
3956
    printf("usage: ffserver [options]\n"
3957 3958
           "Hyper fast multi format Audio/Video streaming server\n");
    printf("\n");
3959
    show_help_options(options, "Main options:", 0, 0, 0);
3960 3961 3962
}

static const OptionDef options[] = {
3963
#include "cmdutils_common_opts.h"
3964 3965
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3966
    { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3967 3968 3969
    { NULL },
};

Fabrice Bellard's avatar
Fabrice Bellard committed
3970 3971
int main(int argc, char **argv)
{
3972
    struct sigaction sigact = { { 0 } };
3973 3974 3975
    int cfg_parsed;
    int ret = EXIT_FAILURE;

Fabrice Bellard's avatar
Fabrice Bellard committed
3976

3977
    config.filename = av_strdup("/etc/ffserver.conf");
3978

3979
    parse_loglevel(argc, argv, options);
3980
    av_register_all();
3981
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3982

3983
    show_banner(argc, argv, options);
3984

3985
    my_program_name = argv[0];
3986

3987
    parse_options(NULL, argc, argv, options, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3988

3989
    unsetenv("http_proxy");             /* Kill the http_proxy */
3990

3991
    av_lfg_init(&random_state, av_get_random_seed());
3992

3993 3994 3995 3996
    sigact.sa_handler = handle_child_exit;
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    sigaction(SIGCHLD, &sigact, 0);

3997
    if ((cfg_parsed = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3998
        fprintf(stderr, "Error reading configuration file '%s': %s\n",
3999 4000
                config.filename, av_err2str(cfg_parsed));
        goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
4001 4002
    }

4003
    /* open log file if needed */
4004 4005
    if (config.logfilename[0] != '\0') {
        if (!strcmp(config.logfilename, "-"))
4006
            logfile = stdout;
4007
        else
4008
            logfile = fopen(config.logfilename, "a");
4009 4010 4011
        av_log_set_callback(http_av_log);
    }

4012 4013
    build_file_streams();

4014 4015 4016 4017
    if (build_feed_streams() < 0) {
        http_log("Could not setup feed streams\n");
        goto bail;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
4018

4019 4020
    compute_bandwidth();

Fabrice Bellard's avatar
Fabrice Bellard committed
4021 4022 4023
    /* signal init */
    signal(SIGPIPE, SIG_IGN);

4024
    if (http_server() < 0) {
4025
        http_log("Could not start server\n");
4026
        goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
4027 4028
    }

4029 4030 4031 4032 4033 4034
    ret=EXIT_SUCCESS;

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