ffserver.c 125 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/rtpproto.h"
36
#include "libavformat/rtsp.h"
37
#include "libavformat/avio_internal.h"
38 39
#include "libavformat/internal.h"

40
#include "libavutil/avassert.h"
41
#include "libavutil/avstring.h"
42
#include "libavutil/lfg.h"
43
#include "libavutil/dict.h"
44
#include "libavutil/intreadwrite.h"
45
#include "libavutil/mathematics.h"
46
#include "libavutil/random_seed.h"
47
#include "libavutil/rational.h"
48
#include "libavutil/parseutils.h"
49
#include "libavutil/opt.h"
50 51
#include "libavutil/time.h"

Fabrice Bellard's avatar
Fabrice Bellard committed
52
#include <stdarg.h>
53
#if HAVE_UNISTD_H
Fabrice Bellard's avatar
Fabrice Bellard committed
54
#include <unistd.h>
55
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
56 57
#include <fcntl.h>
#include <sys/ioctl.h>
58
#if HAVE_POLL_H
59
#include <poll.h>
60
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
61 62
#include <errno.h>
#include <time.h>
63
#include <sys/wait.h>
Fabrice Bellard's avatar
Fabrice Bellard committed
64
#include <signal.h>
65

66
#include "cmdutils.h"
67
#include "ffserver_config.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
68

69 70
#define PATH_LENGTH 1024

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

74 75
static const OptionDef options[];

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

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

91
static const char * const http_state[] = {
92 93 94
    "HTTP_WAIT_REQUEST",
    "HTTP_SEND_HEADER",

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

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

107
#define IOBUFFER_INIT_SIZE 8192
Fabrice Bellard's avatar
Fabrice Bellard committed
108 109

/* timeouts are in ms */
110 111 112
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)

Fabrice Bellard's avatar
Fabrice Bellard committed
113 114
#define SYNC_TIMEOUT (10 * 1000)

115 116 117 118 119
typedef struct RTSPActionServerSetup {
    uint32_t ipaddr;
    char transport_option[512];
} RTSPActionServerSetup;

120
typedef struct {
121
    int64_t count1, count2;
122
    int64_t time1, time2;
123 124
} DataRateData;

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

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

178
    /* RTP state specific */
179
    enum RTSPLowerTransport rtp_protocol;
180
    char session_id[32]; /* session id */
181
    AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS];
182

183
    /* RTP/UDP specific */
184
    URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
185 186 187 188

    /* RTP/TCP specific */
    struct HTTPContext *rtsp_c;
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
Fabrice Bellard's avatar
Fabrice Bellard committed
189 190
} HTTPContext;

191
static HTTPContext *first_http_ctx;
192 193 194 195 196

static FFServerConfig config = {
    .nb_max_http_connections = 2000,
    .nb_max_connections = 5,
    .max_bandwidth = 1000,
197
    .use_defaults = 1,
198
};
Fabrice Bellard's avatar
Fabrice Bellard committed
199

200 201 202 203 204
static void new_connection(int server_fd, int is_rtsp);
static void close_connection(HTTPContext *c);

/* HTTP handling */
static int handle_connection(HTTPContext *c);
205
static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream);
206
static void compute_status(HTTPContext *c);
Fabrice Bellard's avatar
Fabrice Bellard committed
207
static int open_input_stream(HTTPContext *c, const char *info);
208 209
static int http_parse_request(HTTPContext *c);
static int http_send_data(HTTPContext *c);
Fabrice Bellard's avatar
Fabrice Bellard committed
210 211
static int http_start_receive_data(HTTPContext *c);
static int http_receive_data(HTTPContext *c);
212 213 214 215

/* RTSP handling */
static int rtsp_parse_request(HTTPContext *c);
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
216
static void rtsp_cmd_options(HTTPContext *c, const char *url);
217 218 219 220 221 222
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);
223

224
/* SDP handling */
225
static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
226 227
                                   struct in_addr my_ip);

228
/* RTP handling */
229
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
230 231
                                       FFServerStream *stream,
                                       const char *session_id,
232
                                       enum RTSPLowerTransport rtp_protocol);
233
static int rtp_new_av_stream(HTTPContext *c,
234 235
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c);
236
/* utils */
237 238
static size_t htmlencode (const char *src, char **dest);
static inline void cp_html_entity (char *buffer, const char *entity);
239
static inline int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream);
Fabrice Bellard's avatar
Fabrice Bellard committed
240

241 242
static const char *my_program_name;

243
static int no_launch;
244
static int need_to_start_children;
245

246
/* maximum number of simultaneous HTTP connections */
247
static unsigned int nb_connections;
Fabrice Bellard's avatar
Fabrice Bellard committed
248

249
static uint64_t current_bandwidth;
250

251 252
/* Making this global saves on passing it around everywhere */
static int64_t cur_time;
253

254
static AVLFG random_state;
255

Fabrice Bellard's avatar
Fabrice Bellard committed
256 257
static FILE *logfile = NULL;

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
static void unlayer_stream(AVStream *st, LayeredAVStream *lst)
{
    avcodec_free_context(&st->codec);
    avcodec_parameters_free(&st->codecpar);
#define COPY(a) st->a = lst->a;
    COPY(index)
    COPY(id)
    COPY(codec)
    COPY(codecpar)
    COPY(time_base)
    COPY(pts_wrap_bits)
    COPY(sample_aspect_ratio)
    COPY(recommended_encoder_configuration)
}

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 337 338 339 340 341
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++;
342
    }
343 344 345
    *tmp = '\0';

    return final_size;
346 347
}

348 349 350 351
static int64_t ffm_read_write_index(int fd)
{
    uint8_t buf[8];

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

371
    return 8;
372 373 374

bail_eio:
    return AVERROR(EIO);
375 376 377 378 379
}

static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
                                int64_t file_size)
{
380
    av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN);
381 382
    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);
383 384
}

385
static char *ctime1(char *buf2, size_t buf_size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
386 387 388 389 390 391
{
    time_t ti;
    char *p;

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

403
static void http_vlog(const char *fmt, va_list vargs)
Fabrice Bellard's avatar
Fabrice Bellard committed
404
{
405
    static int print_prefix = 1;
406
    char buf[32];
407 408 409 410

    if (!logfile)
        return;

411 412 413 414 415 416 417
    if (print_prefix) {
        ctime1(buf, sizeof(buf));
        fprintf(logfile, "%s ", buf);
    }
    print_prefix = strstr(fmt, "\n") != NULL;
    vfprintf(logfile, fmt, vargs);
    fflush(logfile);
418 419
}

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

443 444
static void log_connection(HTTPContext *c)
{
445
    if (c->suppress_log)
446 447
        return;

448 449
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
450
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
451 452
}

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

/* In bytes per second */
467
static int compute_datarate(DataRateData *drd, int64_t count)
468 469 470
{
    if (cur_time == drd->time1)
        return 0;
471

472 473 474
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
}

475

476
static void start_children(FFServerStream *feed)
477
{
478
    char *pathname;
479 480
    char *slash;
    int i;
481
    size_t cmd_length;
482

483 484 485
    if (no_launch)
        return;

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

498 499 500 501 502 503 504 505 506
    slash = strrchr(my_program_name, '/');
    if (!slash) {
        pathname = av_mallocz(sizeof("ffmpeg"));
    } else {
        pathname = av_mallocz(slash - my_program_name + sizeof("ffmpeg"));
        if (pathname != NULL) {
            memcpy(pathname, my_program_name, slash - my_program_name);
        }
    }
507 508 509 510
    if (!pathname) {
        http_log("Could not allocate memory for children cmd line\n");
        return;
    }
511 512 513
   /* use "ffmpeg" in the path of current program. Ignore user provided path */

    strcat(pathname, "ffmpeg");
514

515
    for (; feed; feed = feed->next) {
516 517 518 519

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

520
        feed->pid_start = time(0);
521

522 523
        feed->pid = fork();
        if (feed->pid < 0) {
524
            http_log("Unable to create children: %s\n", strerror(errno));
525
            av_free (pathname);
526
            exit(EXIT_FAILURE);
527
        }
528

529 530
        if (feed->pid)
            continue;
531

532
        /* In child */
533

534 535
        http_log("Launch command line: ");
        http_log("%s ", pathname);
536

537 538 539
        for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
            http_log("%s ", feed->child_argv[i]);
        http_log("\n");
540

541 542
        for (i = 3; i < 256; i++)
            close(i);
543

544 545 546 547 548 549 550 551
        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;");
        }
552

553 554
        signal(SIGPIPE, SIG_DFL);
        execvp(pathname, feed->child_argv);
555
        av_free (pathname);
556
        _exit(1);
557
    }
558
    av_free (pathname);
559 560
}

561 562
/* open a listening socket */
static int socket_open_listen(struct sockaddr_in *my_addr)
Fabrice Bellard's avatar
Fabrice Bellard committed
563
{
564
    int server_fd, tmp;
Fabrice Bellard's avatar
Fabrice Bellard committed
565 566 567 568 569 570

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

Fabrice Bellard's avatar
Fabrice Bellard committed
572
    tmp = 1;
573 574
    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
575

576
    my_addr->sin_family = AF_INET;
577
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
578
        char bindmsg[32];
579 580
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)",
                 ntohs(my_addr->sin_port));
581
        perror (bindmsg);
582
        goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
583
    }
584

Fabrice Bellard's avatar
Fabrice Bellard committed
585 586
    if (listen (server_fd, 5) < 0) {
        perror ("listen");
587
        goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
588
    }
589 590 591

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

    return server_fd;
594 595 596 597

fail:
    closesocket(server_fd);
    return -1;
598 599
}

600 601 602
/* start all multicast streams */
static void start_multicast(void)
{
603
    FFServerStream *stream;
604 605
    char session_id[32];
    HTTPContext *rtp_c;
606
    struct sockaddr_in dest_addr = {0};
607
    int default_port, stream_index;
608
    unsigned int random0, random1;
609 610

    default_port = 6000;
611
    for(stream = config.first_stream; stream; stream = stream->next) {
612

613 614
        if (!stream->is_multicast)
            continue;
615

616 617 618 619
        random0 = av_lfg_get(&random_state);
        random1 = av_lfg_get(&random_state);

        /* open the RTP connection */
620
        snprintf(session_id, sizeof(session_id), "%08x%08x", random0, random1);
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648

        /* 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)
649
                continue;
650 651 652 653 654 655 656

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

        rtp_c->state = HTTPSTATE_SEND_DATA;
657 658
    }
}
659

660
/* main loop of the HTTP server */
661 662
static int http_server(void)
{
663
    int server_fd = 0, rtsp_server_fd = 0;
664
    int ret, delay;
665
    struct pollfd *poll_table, *poll_entry;
666 667
    HTTPContext *c, *c_next;

668 669 670 671 672
    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);
673 674 675
        return -1;
    }

676 677
    if (config.http_addr.sin_port) {
        server_fd = socket_open_listen(&config.http_addr);
678 679
        if (server_fd < 0)
            goto quit;
680
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
681

682 683
    if (config.rtsp_addr.sin_port) {
        rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
684 685
        if (rtsp_server_fd < 0) {
            closesocket(server_fd);
686
            goto quit;
687
        }
688 689 690 691
    }

    if (!rtsp_server_fd && !server_fd) {
        http_log("HTTP and RTSP disabled.\n");
692
        goto quit;
693
    }
694

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

697
    start_children(config.first_feed);
698

699 700
    start_multicast();

Fabrice Bellard's avatar
Fabrice Bellard committed
701 702
    for(;;) {
        poll_entry = poll_table;
703
        if (server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
704 705 706
            poll_entry->fd = server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
707 708
        }
        if (rtsp_server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
709 710 711
            poll_entry->fd = rtsp_server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
712
        }
713

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

        /* wait for an event on one connection. We poll at least every
765
         * second to handle timeouts */
Fabrice Bellard's avatar
Fabrice Bellard committed
766
        do {
767
            ret = poll(poll_table, poll_entry - poll_table, delay);
768
            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
769
                ff_neterrno() != AVERROR(EINTR)) {
770
                goto quit;
771
            }
772
        } while (ret < 0);
773

774
        cur_time = av_gettime() / 1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
775

776 777
        if (need_to_start_children) {
            need_to_start_children = 0;
778
            start_children(config.first_feed);
779 780
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
781
        /* now handle the events */
782
        for(c = first_http_ctx; c; c = c_next) {
783 784
            c_next = c->next;
            if (handle_connection(c) < 0) {
785
                log_connection(c);
786
                /* close and free the connection */
787
                close_connection(c);
Fabrice Bellard's avatar
Fabrice Bellard committed
788 789 790 791
            }
        }

        poll_entry = poll_table;
792
        if (server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
793 794 795 796
            /* new HTTP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(server_fd, 0);
            poll_entry++;
797 798
        }
        if (rtsp_server_fd) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
799 800 801
            /* new RTSP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(rtsp_server_fd, 1);
802
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
803
    }
804 805 806 807

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

810 811
/* 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
812
{
813 814 815
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */

816 817
    c->state = is_rtsp ? RTSPSTATE_WAIT_REQUEST : HTTPSTATE_WAIT_REQUEST;
    c->timeout = cur_time +
818
                 (is_rtsp ? RTSP_REQUEST_TIMEOUT : HTTP_REQUEST_TIMEOUT);
819 820
}

821 822
static void http_send_too_busy_reply(int fd)
{
823
    char buffer[400];
824
    int len = snprintf(buffer, sizeof(buffer),
825
                       "HTTP/1.0 503 Server too busy\r\n"
826 827
                       "Content-type: text/html\r\n"
                       "\r\n"
828
                       "<!DOCTYPE html>\n"
829
                       "<html><head><title>Too busy</title></head><body>\r\n"
830 831 832 833
                       "<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"
834
                       "</body></html>\r\n",
835
                       nb_connections, config.nb_max_connections);
836
    av_assert0(len < sizeof(buffer));
837
    if (send(fd, buffer, len, 0) < len)
838 839
        av_log(NULL, AV_LOG_WARNING,
               "Could not send too-busy reply, send() failed\n");
840 841 842
}


843 844 845
static void new_connection(int server_fd, int is_rtsp)
{
    struct sockaddr_in from_addr;
846 847
    socklen_t len;
    int fd;
848 849 850
    HTTPContext *c = NULL;

    len = sizeof(from_addr);
851
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
852
                &len);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
853 854
    if (fd < 0) {
        http_log("error during accept %s\n", strerror(errno));
855
        return;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
856
    }
857 858
    if (ff_socket_nonblock(fd, 1) < 0)
        av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
859

860
    if (nb_connections >= config.nb_max_connections) {
861
        http_send_too_busy_reply(fd);
862
        goto fail;
863
    }
864

865 866 867 868
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
869

870 871 872 873 874 875 876
    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;
877 878 879

    c->next = first_http_ctx;
    first_http_ctx = c;
880
    nb_connections++;
881

882 883 884 885 886 887
    start_wait_request(c, is_rtsp);

    return;

 fail:
    if (c) {
888
        av_freep(&c->buffer);
889 890
        av_free(c);
    }
891
    closesocket(fd);
892 893 894 895 896 897 898 899 900 901 902
}

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;
903
    while (*cp) {
904
        c1 = *cp;
905
        if (c1 == c)
906
            *cp = c->next;
907
        else
908 909 910
            cp = &c1->next;
    }

911
    /* remove references, if any (XXX: do it faster) */
912
    for(c1 = first_http_ctx; c1; c1 = c1->next) {
913 914 915 916
        if (c1->rtsp_c == c)
            c1->rtsp_c = NULL;
    }

917 918
    /* remove connection associated resources */
    if (c->fd >= 0)
919
        closesocket(c->fd);
920 921 922 923
    if (c->fmt_in) {
        /* close each frame parser */
        for(i=0;i<c->fmt_in->nb_streams;i++) {
            st = c->fmt_in->streams[i];
924
            if (st->codec->codec)
925
                avcodec_close(st->codec);
926
        }
927
        avformat_close_input(&c->fmt_in);
928 929 930 931
    }

    /* free RTP output streams if any */
    nb_streams = 0;
932
    if (c->stream)
933
        nb_streams = c->stream->nb_streams;
934

935 936 937 938
    for(i=0;i<nb_streams;i++) {
        ctx = c->rtp_ctx[i];
        if (ctx) {
            av_write_trailer(ctx);
939
            av_dict_free(&ctx->metadata);
940 941
            av_freep(&ctx->streams[0]);
            av_freep(&ctx);
942
        }
943
        ffurl_close(c->rtp_handles[i]);
944
    }
945

946
    ctx = c->pfmt_ctx;
947

948 949 950 951 952 953 954 955 956 957 958 959 960
    if (ctx) {
        if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
            /* 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);
            }
        }
        for(i=0; i<ctx->nb_streams; i++)
            av_freep(&ctx->streams[i]);
        av_freep(&ctx->streams);
        av_freep(&ctx->priv_data);
961
        }
962

963
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
964
        current_bandwidth -= c->stream->bandwidth;
965 966 967 968 969 970 971

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

972
    av_freep(&c->pb_buffer);
973
    av_freep(&c->packet_buffer);
974
    av_freep(&c->buffer);
975 976 977 978 979 980 981
    av_free(c);
    nb_connections--;
}

static int handle_connection(HTTPContext *c)
{
    int len, ret;
982
    uint8_t *ptr;
983

Fabrice Bellard's avatar
Fabrice Bellard committed
984 985
    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
986
    case RTSPSTATE_WAIT_REQUEST:
Fabrice Bellard's avatar
Fabrice Bellard committed
987 988 989 990 991 992 993 994 995 996
        /* 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 */
997
    read_loop:
998 999 1000
        if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
            return -1;

Fabrice Bellard's avatar
Fabrice Bellard committed
1001
        if (len < 0) {
1002 1003
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
Fabrice Bellard's avatar
Fabrice Bellard committed
1004
                return -1;
1005 1006
            break;
        }
1007 1008 1009 1010 1011 1012
        /* 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 */
1013
            if (c->state == HTTPSTATE_WAIT_REQUEST)
1014
                ret = http_parse_request(c);
1015
            else
1016
                ret = rtsp_parse_request(c);
1017

1018
            if (ret < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
1019
                return -1;
1020 1021 1022 1023
        } else if (ptr >= c->buffer_end) {
            /* request too long: cannot do anything */
            return -1;
        } else goto read_loop;
1024

Fabrice Bellard's avatar
Fabrice Bellard committed
1025 1026 1027 1028 1029 1030
        break;

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

1031
        /* no need to write if no events */
Fabrice Bellard's avatar
Fabrice Bellard committed
1032 1033
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1034
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
1035
        if (len < 0) {
1036 1037
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1038
                goto close_connection;
Fabrice Bellard's avatar
Fabrice Bellard committed
1039
            }
1040 1041
            break;
        }
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
        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
1056 1057 1058 1059 1060
        break;

    case HTTPSTATE_SEND_DATA:
    case HTTPSTATE_SEND_DATA_HEADER:
    case HTTPSTATE_SEND_DATA_TRAILER:
1061
        /* for packetized output, we consider we can always write (the
1062 1063
         * input streams set the speed). It may be better to verify
         * that we do not rely too much on the kernel queues */
1064 1065 1066
        if (!c->is_packetized) {
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
                return -1;
1067

1068 1069 1070 1071
            /* no need to read if no events */
            if (!(c->poll_entry->revents & POLLOUT))
                return 0;
        }
1072
        if (http_send_data(c) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
1073
            return -1;
1074 1075 1076
        /* close connection if trailer sent */
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
            return -1;
1077 1078 1079 1080
        /* 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
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
        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 */
1093
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
Fabrice Bellard's avatar
Fabrice Bellard committed
1094 1095 1096 1097
            return -1;

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

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

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

1160 1161 1162 1163 1164
static int extract_rates(char *rates, int ratelen, const char *request)
{
    const char *p;

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

1168
            while (*q && *q != '\n' && av_isspace(*q))
1169 1170
                q++;

1171
            if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1172 1173 1174 1175 1176
                int stream_no;
                int rate_no;

                q += 20;

1177
                memset(rates, 0xff, ratelen);
1178 1179 1180 1181 1182

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

1183
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1184
                        break;
1185

1186
                    stream_no--;
1187
                    if (stream_no < ratelen && stream_no >= 0)
1188 1189
                        rates[stream_no] = rate_no;

1190
                    while (*q && *q != '\n' && !av_isspace(*q))
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
                        q++;
                }

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

        p++;
    }

    return 0;
}

1207
static int find_stream_in_feed(FFServerStream *feed, AVCodecParameters *codec,
1208
                               int bit_rate)
1209 1210
{
    int i;
1211 1212 1213 1214
    int best_bitrate = 100000000;
    int best = -1;

    for (i = 0; i < feed->nb_streams; i++) {
1215
        AVCodecParameters *feed_codec = feed->streams[i]->codecpar;
1216 1217 1218 1219

        if (feed_codec->codec_id != codec->codec_id ||
            feed_codec->sample_rate != codec->sample_rate ||
            feed_codec->width != codec->width ||
1220
            feed_codec->height != codec->height)
1221 1222 1223 1224
            continue;

        /* Potential stream */

1225
        /* We want the fastest stream less than bit_rate, or the slowest
1226 1227 1228 1229
         * faster than bit_rate
         */

        if (feed_codec->bit_rate <= bit_rate) {
1230 1231
            if (best_bitrate > bit_rate ||
                feed_codec->bit_rate > best_bitrate) {
1232 1233 1234
                best_bitrate = feed_codec->bit_rate;
                best = i;
            }
1235 1236 1237 1238 1239
            continue;
        }
        if (feed_codec->bit_rate < best_bitrate) {
            best_bitrate = feed_codec->bit_rate;
            best = i;
1240 1241 1242 1243 1244 1245 1246 1247
        }
    }
    return best;
}

static int modify_current_stream(HTTPContext *c, char *rates)
{
    int i;
1248
    FFServerStream *req = c->stream;
1249
    int action_required = 0;
1250

1251 1252 1253 1254
    /* Not much we can do for a feed */
    if (!req->feed)
        return 0;

1255
    for (i = 0; i < req->nb_streams; i++) {
1256
        AVCodecParameters *codec = req->streams[i]->codecpar;
1257 1258 1259

        switch(rates[i]) {
            case 0:
1260
                c->switch_feed_streams[i] = req->feed_streams[i];
1261 1262
                break;
            case 1:
1263
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1264 1265
                break;
            case 2:
1266 1267 1268 1269 1270 1271 1272
                /* 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
1273 1274 1275
                break;
        }

1276 1277
        if (c->switch_feed_streams[i] >= 0 &&
            c->switch_feed_streams[i] != c->feed_streams[i]) {
1278
            action_required = 1;
1279
        }
1280
    }
1281

1282 1283
    return action_required;
}
1284

1285 1286 1287 1288 1289
static void get_word(char *buf, int buf_size, const char **pp)
{
    const char *p;
    char *q;

1290 1291
#define SPACE_CHARS " \t\r\n"

1292
    p = *pp;
1293
    p += strspn(p, SPACE_CHARS);
1294
    q = buf;
1295
    while (!av_isspace(*p) && *p != '\0') {
1296 1297 1298 1299 1300 1301 1302 1303 1304
        if ((q - buf) < buf_size - 1)
            *q++ = *p;
        p++;
    }
    if (buf_size > 0)
        *q = '\0';
    *pp = p;
}

1305 1306
static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
                                               HTTPContext *c)
1307 1308 1309 1310
{
    FILE* f;
    char line[1024];
    char  cmd[1024];
1311
    FFServerIPAddressACL *acl = NULL;
1312 1313 1314 1315 1316 1317 1318 1319 1320
    int line_num = 0;
    const char *p;

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

1321
    acl = av_mallocz(sizeof(FFServerIPAddressACL));
1322 1323 1324 1325
    if (!acl) {
        fclose(f);
        return NULL;
    }
1326 1327

    /* Build ACL */
1328
    while (fgets(line, sizeof(line), f)) {
1329 1330
        line_num++;
        p = line;
1331
        while (av_isspace(*p))
1332 1333 1334
            p++;
        if (*p == '\0' || *p == '#')
            continue;
1335
        ffserver_get_arg(cmd, sizeof(cmd), &p);
1336

1337
        if (!av_strcasecmp(cmd, "ACL"))
1338 1339
            ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
                                   line_num);
1340 1341 1342 1343 1344 1345
    }
    fclose(f);
    return acl;
}


1346
static void free_acl_list(FFServerIPAddressACL *in_acl)
1347
{
1348
    FFServerIPAddressACL *pacl, *pacl2;
1349 1350 1351 1352 1353 1354 1355 1356 1357

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

1358
static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1359
{
1360 1361
    enum FFServerIPAddressAction last_action = IP_DENY;
    FFServerIPAddressACL *acl;
1362
    struct in_addr *src = &c->from_addr.sin_addr;
1363
    unsigned long src_addr = src->s_addr;
1364

1365
    for (acl = in_acl; acl; acl = acl->next) {
1366
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1367 1368 1369 1370 1371 1372 1373 1374
            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;
}

1375
static int validate_acl(FFServerStream *stream, HTTPContext *c)
1376 1377
{
    int ret = 0;
1378
    FFServerIPAddressACL *acl;
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391

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

1392 1393 1394 1395
/**
 * compute the real filename of a file by matching it without its
 * extensions to all the stream's filenames
 */
1396 1397 1398 1399 1400
static void compute_real_filename(char *filename, int max_size)
{
    char file1[1024];
    char file2[1024];
    char *p;
1401
    FFServerStream *stream;
1402

1403
    av_strlcpy(file1, filename, sizeof(file1));
1404 1405 1406
    p = strrchr(file1, '.');
    if (p)
        *p = '\0';
1407
    for(stream = config.first_stream; stream; stream = stream->next) {
1408
        av_strlcpy(file2, stream->filename, sizeof(file2));
1409 1410 1411 1412
        p = strrchr(file2, '.');
        if (p)
            *p = '\0';
        if (!strcmp(file1, file2)) {
1413
            av_strlcpy(filename, stream->filename, max_size);
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
            break;
        }
    }
}

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

1428
/* parse HTTP request and prepare header */
Fabrice Bellard's avatar
Fabrice Bellard committed
1429 1430
static int http_parse_request(HTTPContext *c)
{
1431 1432
    const char *p;
    char *p1;
1433
    enum RedirType redir_type;
Fabrice Bellard's avatar
Fabrice Bellard committed
1434
    char cmd[32];
1435
    char info[1024], filename[1024];
Fabrice Bellard's avatar
Fabrice Bellard committed
1436 1437 1438
    char url[1024], *q;
    char protocol[32];
    char msg[1024];
1439
    char *encoded_msg = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
1440
    const char *mime_type;
1441
    FFServerStream *stream;
1442
    int i;
1443
    char ratebuf[32];
1444
    const char *useragent = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1445 1446

    p = c->buffer;
1447
    get_word(cmd, sizeof(cmd), &p);
1448
    av_strlcpy(c->method, cmd, sizeof(c->method));
1449

Fabrice Bellard's avatar
Fabrice Bellard committed
1450
    if (!strcmp(cmd, "GET"))
1451
        c->post = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1452
    else if (!strcmp(cmd, "POST"))
1453
        c->post = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1454 1455 1456
    else
        return -1;

1457
    get_word(url, sizeof(url), &p);
1458
    av_strlcpy(c->url, url, sizeof(c->url));
1459

1460
    get_word(protocol, sizeof(protocol), (const char **)&p);
Fabrice Bellard's avatar
Fabrice Bellard committed
1461 1462
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
        return -1;
1463

1464
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1465

1466
    if (config.debug)
1467 1468
        http_log("%s - - New connection: %s %s\n",
                 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1469

Fabrice Bellard's avatar
Fabrice Bellard committed
1470
    /* find the filename and the optional info string in the request */
1471 1472 1473 1474
    p1 = strchr(url, '?');
    if (p1) {
        av_strlcpy(info, p1, sizeof(info));
        *p1 = '\0';
1475
    } else
Fabrice Bellard's avatar
Fabrice Bellard committed
1476 1477
        info[0] = '\0';

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

1480
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1481
        if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1482
            useragent = p + 11;
1483
            if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
                useragent++;
            break;
        }
        p = strchr(p, '\n');
        if (!p)
            break;

        p++;
    }

1494
    redir_type = REDIR_NONE;
1495
    if (av_match_ext(filename, "asx")) {
1496
        redir_type = REDIR_ASX;
1497
        filename[strlen(filename)-1] = 'f';
1498
    } else if (av_match_ext(filename, "asf") &&
1499
        (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1500
        /* if this isn't WMP or lookalike, return the redirector file */
1501
        redir_type = REDIR_ASF;
1502
    } else if (av_match_ext(filename, "rpm,ram")) {
1503
        redir_type = REDIR_RAM;
1504
        strcpy(filename + strlen(filename)-2, "m");
1505
    } else if (av_match_ext(filename, "rtsp")) {
1506
        redir_type = REDIR_RTSP;
1507
        compute_real_filename(filename, sizeof(filename) - 1);
1508
    } else if (av_match_ext(filename, "sdp")) {
1509
        redir_type = REDIR_SDP;
1510
        compute_real_filename(filename, sizeof(filename) - 1);
1511
    }
1512

1513
    /* "redirect" request to index.html */
1514
    if (!strlen(filename))
1515
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1516

1517
    stream = config.first_stream;
1518
    while (stream) {
1519
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
Fabrice Bellard's avatar
Fabrice Bellard committed
1520 1521 1522
            break;
        stream = stream->next;
    }
1523
    if (!stream) {
1524
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1525
        http_log("File '%s' not found\n", url);
Fabrice Bellard's avatar
Fabrice Bellard committed
1526 1527
        goto send_error;
    }
1528

1529 1530 1531 1532 1533 1534 1535
    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;
1536
        snprintf(q, c->buffer_size,
1537 1538 1539 1540
                      "HTTP/1.0 301 Moved\r\n"
                      "Location: %s\r\n"
                      "Content-type: text/html\r\n"
                      "\r\n"
1541
                      "<!DOCTYPE html>\n"
1542 1543
                      "<html><head><title>Moved</title></head><body>\r\n"
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1544 1545
                      "</body></html>\r\n",
                 stream->feed_filename, stream->feed_filename);
1546
        q += strlen(q);
1547 1548 1549 1550 1551 1552 1553
        /* prepare output buffer */
        c->buffer_ptr = c->buffer;
        c->buffer_end = q;
        c->state = HTTPSTATE_SEND_HEADER;
        return 0;
    }

1554 1555
    /* If this is WMP, get the rate information */
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1556
        if (modify_current_stream(c, ratebuf)) {
1557
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1558
                if (c->switch_feed_streams[i] >= 0)
Reinhard Tartler's avatar
Reinhard Tartler committed
1559
                    c->switch_feed_streams[i] = -1;
1560 1561
            }
        }
1562 1563
    }

1564 1565 1566
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
        current_bandwidth += stream->bandwidth;

1567
    /* If already streaming this feed, do not let another feeder start */
1568 1569
    if (stream->feed_opened) {
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1570
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1571 1572 1573
        goto send_error;
    }

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

1598
    if (redir_type != REDIR_NONE) {
1599
        const char *hostinfo = 0;
1600

1601
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1602
            if (av_strncasecmp(p, "Host:", 5) == 0) {
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
                hostinfo = p + 5;
                break;
            }
            p = strchr(p, '\n');
            if (!p)
                break;

            p++;
        }

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

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

1685
                            snprintf(q, c->buffer_size,
1686 1687 1688
                                          "HTTP/1.0 200 OK\r\n"
                                          "Content-type: application/sdp\r\n"
                                          "\r\n");
1689
                            q += strlen(q);
1690 1691

                            len = sizeof(my_addr);
1692 1693 1694 1695

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

1697
                            /* XXX: should use a dynamic buffer */
1698 1699
                            sdp_data_size = prepare_sdp_description(stream,
                                                                    &sdp_data,
1700 1701 1702 1703 1704
                                                                    my_addr.sin_addr);
                            if (sdp_data_size > 0) {
                                memcpy(q, sdp_data, sdp_data_size);
                                q += sdp_data_size;
                                *q = '\0';
1705
                                av_freep(&sdp_data);
1706 1707 1708 1709
                            }
                        }
                        break;
                    default:
1710
                        abort();
1711
                        break;
1712
                    }
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722

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

1723
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1724
        goto send_error;
Fabrice Bellard's avatar
Fabrice Bellard committed
1725 1726
    }

1727
    stream->conns_served++;
1728

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

1731
    if (c->post) {
Fabrice Bellard's avatar
Fabrice Bellard committed
1732 1733
        /* if post, it means a feed is being sent */
        if (!stream->is_feed) {
Diego Biurrun's avatar
Diego Biurrun committed
1734
            /* However it might be a status report from WMP! Let us log the
1735
             * data as it might come handy one day. */
1736
            const char *logline = 0;
1737
            int client_id = 0;
1738

1739
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1740
                if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1741 1742 1743
                    logline = p;
                    break;
                }
1744
                if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1745
                    client_id = strtol(p + 18, 0, 10);
1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
                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
1761
                    http_log("%.*s\n", (int) (eol - logline), logline);
1762 1763 1764
                    c->suppress_log = 1;
                }
            }
1765

1766
#ifdef DEBUG
1767
            http_log("\nGot request:\n%s\n", c->buffer);
1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
#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;
                }

1779 1780
                if (wmpc && modify_current_stream(wmpc, ratebuf))
                    wmpc->switch_pending = 1;
1781
            }
1782

1783
            snprintf(msg, sizeof(msg), "POST command not handled");
1784
            c->stream = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1785 1786 1787
            goto send_error;
        }
        if (http_start_receive_data(c) < 0) {
1788
            snprintf(msg, sizeof(msg), "could not open feed");
Fabrice Bellard's avatar
Fabrice Bellard committed
1789 1790 1791 1792 1793 1794 1795
            goto send_error;
        }
        c->http_error = 0;
        c->state = HTTPSTATE_RECEIVE_DATA;
        return 0;
    }

1796
#ifdef DEBUG
1797
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1798
        http_log("\nGot request:\n%s\n", c->buffer);
1799 1800
#endif

Fabrice Bellard's avatar
Fabrice Bellard committed
1801
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1802
        goto send_status;
Fabrice Bellard's avatar
Fabrice Bellard committed
1803 1804 1805

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

1810
    /* prepare HTTP header */
1811 1812
    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
1813 1814
    mime_type = c->stream->fmt->mime_type;
    if (!mime_type)
1815
        mime_type = "application/x-octet-stream";
1816
    av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
1817 1818

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

1822
        c->wmp_client_id = av_lfg_get(&random_state);
1823

1824
        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
1825
    }
1826 1827 1828
    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);
1829

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

1870
static void fmt_bytecount(AVIOContext *pb, int64_t count)
1871
{
1872
    static const char suffix[] = " kMGTP";
1873 1874
    const char *s;

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

1877
    avio_printf(pb, "%"PRId64"%c", count, *s);
1878 1879
}

1880 1881 1882 1883 1884
static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream)
{
    int i, stream_no;
    const char *type = "unknown";
    char parameters[64];
1885
    LayeredAVStream *st;
1886 1887 1888 1889
    AVCodec *codec;

    stream_no = stream->nb_streams;

1890 1891
    avio_printf(pb, "<table><tr><th>Stream<th>"
                    "type<th>kbit/s<th>codec<th>"
1892 1893 1894 1895
                    "Parameters\n");

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

        parameters[0] = 0;

1900
        switch(st->codecpar->codec_type) {
1901 1902 1903
        case AVMEDIA_TYPE_AUDIO:
            type = "audio";
            snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1904
                     st->codecpar->channels, st->codecpar->sample_rate);
1905 1906 1907 1908
            break;
        case AVMEDIA_TYPE_VIDEO:
            type = "video";
            snprintf(parameters, sizeof(parameters),
1909 1910
                     "%dx%d, q=%d-%d, fps=%d", st->codecpar->width,
                     st->codecpar->height, st->codec->qmin, st->codec->qmax,
1911
                     st->time_base.den / st->time_base.num);
1912 1913 1914 1915 1916
            break;
        default:
            abort();
        }

1917
        avio_printf(pb, "<tr><td>%d<td>%s<td>%"PRId64
1918
                        "<td>%s<td>%s\n",
1919
                    i, type, (int64_t)st->codecpar->bit_rate/1000,
1920 1921 1922 1923 1924 1925
                    codec ? codec->name : "", parameters);
     }

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

1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
static void clean_html(char *clean, int clean_len, char *dirty)
{
    int i, o;

    for (o = i = 0; o+10 < clean_len && dirty[i];) {
        int len = strspn(dirty+i, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$-_.+!*(),?/ :;%");
        if (len) {
            if (o + len >= clean_len)
                break;
            memcpy(clean + o, dirty + i, len);
            i += len;
            o += len;
        } else {
            int c = dirty[i++];
            switch (c) {
            case  '&': av_strlcat(clean+o, "&amp;"  , clean_len - o); break;
            case  '<': av_strlcat(clean+o, "&lt;"   , clean_len - o); break;
            case  '>': av_strlcat(clean+o, "&gt;"   , clean_len - o); break;
            case '\'': av_strlcat(clean+o, "&apos;" , clean_len - o); break;
            case '\"': av_strlcat(clean+o, "&quot;" , clean_len - o); break;
            default:   av_strlcat(clean+o, "&#9785;", clean_len - o); break;
            }
            o += strlen(clean+o);
        }
    }
    clean[o] = 0;
}

1954
static void compute_status(HTTPContext *c)
Fabrice Bellard's avatar
Fabrice Bellard committed
1955 1956
{
    HTTPContext *c1;
1957
    FFServerStream *stream;
1958
    char *p;
Fabrice Bellard's avatar
Fabrice Bellard committed
1959
    time_t ti;
1960
    int i, len;
1961
    AVIOContext *pb;
1962

1963
    if (avio_open_dyn_buf(&pb) < 0) {
1964
        /* XXX: return an error ? */
1965
        c->buffer_ptr = c->buffer;
1966 1967
        c->buffer_end = c->buffer;
        return;
1968
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
1969

1970
    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1971
    avio_printf(pb, "Content-type: text/html\r\n");
1972 1973
    avio_printf(pb, "Pragma: no-cache\r\n");
    avio_printf(pb, "\r\n");
1974

1975
    avio_printf(pb, "<!DOCTYPE html>\n");
1976
    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1977
    if (c->stream->feed_filename[0])
1978 1979
        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
                    c->stream->feed_filename);
1980 1981
    avio_printf(pb, "</head>\n<body>");
    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
Fabrice Bellard's avatar
Fabrice Bellard committed
1982
    /* format status */
1983
    avio_printf(pb, "<h2>Available Streams</h2>\n");
1984 1985
    avio_printf(pb, "<table>\n");
    avio_printf(pb, "<tr><th>Path<th>Served<br>Conns<th><br>bytes<th>Format<th>Bit rate<br>kbit/s<th>Video<br>kbit/s<th><br>Codec<th>Audio<br>kbit/s<th><br>Codec<th>Feed\n");
1986
    stream = config.first_stream;
1987
    while (stream) {
1988 1989 1990
        char sfilename[1024];
        char *eosf;

1991 1992 1993 1994
        if (stream->feed == stream) {
            stream = stream->next;
            continue;
        }
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004

        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
2005 2006
                 * unicast. Generate an SDP redirector if
                 * multicast */
2007 2008 2009 2010 2011 2012 2013
                eosf = strrchr(sfilename, '.');
                if (!eosf)
                    eosf = sfilename + strlen(sfilename);
                if (stream->is_multicast)
                    strcpy(eosf, ".sdp");
                else
                    strcpy(eosf, ".rtsp");
2014
            }
2015
        }
2016

2017 2018
        avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
                    sfilename, stream->filename);
2019
        avio_printf(pb, "<td> %d <td> ",
2020
                    stream->conns_served);
2021 2022 2023
        // TODO: Investigate if we can make http bitexact so it always produces the same count of bytes
        if (!config.bitexact)
            fmt_bytecount(pb, stream->bytes_served);
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034

        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++) {
2035
                LayeredAVStream *st = stream->streams[i];
2036
                AVCodec *codec = avcodec_find_encoder(st->codecpar->codec_id);
2037

2038
                switch(st->codecpar->codec_type) {
2039
                case AVMEDIA_TYPE_AUDIO:
2040
                    audio_bit_rate += st->codecpar->bit_rate;
2041 2042 2043 2044
                    if (codec) {
                        if (*audio_codec_name)
                            audio_codec_name_extra = "...";
                        audio_codec_name = codec->name;
Fabrice Bellard's avatar
Fabrice Bellard committed
2045
                    }
2046 2047
                    break;
                case AVMEDIA_TYPE_VIDEO:
2048
                    video_bit_rate += st->codecpar->bit_rate;
2049 2050 2051 2052 2053 2054 2055
                    if (codec) {
                        if (*video_codec_name)
                            video_codec_name_extra = "...";
                        video_codec_name = codec->name;
                    }
                    break;
                case AVMEDIA_TYPE_DATA:
2056
                    video_bit_rate += st->codecpar->bit_rate;
2057 2058 2059
                    break;
                default:
                    abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
2060 2061
                }
            }
2062

2063
            avio_printf(pb, "<td> %s <td> %d <td> %d <td> %s %s <td> "
2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077
                            "%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:
2078 2079
            avio_printf(pb, "<td> - <td> - "
                            "<td> - <td><td> - <td>\n");
2080 2081
            break;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2082 2083
        stream = stream->next;
    }
2084
    avio_printf(pb, "</table>\n");
2085

2086
    stream = config.first_stream;
2087
    while (stream) {
2088

2089 2090 2091 2092
        if (stream->feed != stream) {
            stream = stream->next;
            continue;
        }
2093 2094 2095

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

2098
#if defined(linux)
2099 2100 2101 2102 2103 2104
            {
                FILE *pid_stat;
                char ps_cmd[64];

                /* This is somewhat linux specific I guess */
                snprintf(ps_cmd, sizeof(ps_cmd),
2105 2106
                         "ps -o \"%%cpu,cputime\" --no-headers %"PRId64"",
                         (int64_t) stream->pid);
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120

                 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);
                 }
            }
2121 2122
#endif

2123 2124
            avio_printf(pb, "<p>");
        }
2125

2126
        print_stream_params(pb, stream);
2127 2128
        stream = stream->next;
    }
2129

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

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

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

2139
    avio_printf(pb, "<table>\n");
2140
    avio_printf(pb, "<tr><th>#<th>File<th>IP<th>URL<th>Proto<th>State<th>Target "
2141
                    "bit/s<th>Actual bit/s<th>Bytes transferred\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2142 2143
    c1 = first_http_ctx;
    i = 0;
2144
    while (c1) {
2145 2146 2147 2148
        int bitrate;
        int j;

        bitrate = 0;
2149 2150
        if (c1->stream) {
            for (j = 0; j < c1->stream->nb_streams; j++) {
2151
                if (!c1->stream->feed)
2152
                    bitrate += c1->stream->streams[j]->codecpar->bit_rate;
2153
                else if (c1->feed_streams[j] >= 0)
2154
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codecpar->bit_rate;
2155 2156 2157
            }
        }

Fabrice Bellard's avatar
Fabrice Bellard committed
2158 2159
        i++;
        p = inet_ntoa(c1->from_addr.sin_addr);
2160 2161
        clean_html(c1->clean_url, sizeof(c1->clean_url), c1->url);
        avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td>%s"
2162
                        "<td>",
2163
                    i, c1->stream ? c1->stream->filename : "",
2164 2165 2166
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
                    p,
                    c1->clean_url,
2167
                    c1->protocol, http_state[c1->state]);
2168
        fmt_bytecount(pb, bitrate);
2169
        avio_printf(pb, "<td>");
2170
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2171
        avio_printf(pb, "<td>");
2172
        fmt_bytecount(pb, c1->data_count);
2173
        avio_printf(pb, "\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2174 2175
        c1 = c1->next;
    }
2176
    avio_printf(pb, "</table>\n");
2177

2178 2179 2180 2181
    if (!config.bitexact) {
        /* date */
        ti = time(NULL);
        p = ctime(&ti);
2182
        avio_printf(pb, "<hr>Generated at %s", p);
2183
    }
2184
    avio_printf(pb, "</body>\n</html>\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
2185

2186
    len = avio_close_dyn_buf(pb, &c->pb_buffer);
2187 2188
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
Fabrice Bellard's avatar
Fabrice Bellard committed
2189 2190 2191 2192 2193 2194
}

static int open_input_stream(HTTPContext *c, const char *info)
{
    char buf[128];
    char input_filename[1024];
2195
    AVFormatContext *s = NULL;
2196
    int buf_size, i, ret;
2197
    int64_t stream_pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
2198 2199 2200 2201

    /* find file name */
    if (c->stream->feed) {
        strcpy(input_filename, c->stream->feed->feed_filename);
2202
        buf_size = FFM_PACKET_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
2203
        /* compute position (absolute time) */
2204
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2205 2206
            if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
                http_log("Invalid date specification '%s' for stream\n", buf);
2207
                return ret;
2208
            }
2209
        } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2210
            int prebuffer = strtol(buf, 0, 10);
2211
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2212
        } else
2213
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
Fabrice Bellard's avatar
Fabrice Bellard committed
2214 2215
    } else {
        strcpy(input_filename, c->stream->feed_filename);
2216
        buf_size = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2217
        /* compute position (relative time) */
2218
        if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2219 2220
            if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
                http_log("Invalid date specification '%s' for stream\n", buf);
2221
                return ret;
2222
            }
2223
        } else
Fabrice Bellard's avatar
Fabrice Bellard committed
2224 2225
            stream_pos = 0;
    }
2226 2227 2228 2229
    if (!input_filename[0]) {
        http_log("No filename was specified for stream\n");
        return AVERROR(EINVAL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2230 2231

    /* open stream */
2232 2233 2234
    ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
                              &c->stream->in_opts);
    if (ret < 0) {
2235 2236
        http_log("Could not open input '%s': %s\n",
                 input_filename, av_err2str(ret));
2237
        return ret;
2238
    }
2239 2240

    /* set buffer size */
2241 2242 2243 2244 2245 2246 2247
    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;
        }
    }
2248

2249
    s->flags |= AVFMT_FLAG_GENPTS;
Fabrice Bellard's avatar
Fabrice Bellard committed
2250
    c->fmt_in = s;
2251 2252 2253
    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);
2254
        avformat_close_input(&s);
2255
        return ret;
2256
    }
2257

2258 2259
    /* choose stream as clock source (we favor the video stream if
     * present) for packet sending */
2260 2261
    c->pts_stream_index = 0;
    for(i=0;i<c->stream->nb_streams;i++) {
2262
        if (c->pts_stream_index == 0 &&
2263
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2264 2265 2266
            c->pts_stream_index = i;
        }
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2267

2268
    if (c->fmt_in->iformat->read_seek)
2269
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2270 2271 2272
    /* 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
2273 2274 2275
    return 0;
}

2276 2277
/* return the server clock (in us) */
static int64_t get_server_clock(HTTPContext *c)
2278
{
2279
    /* compute current pts value from system time */
2280
    return (cur_time - c->start_time) * 1000;
2281 2282
}

2283
/* return the estimated time (in us) at which the current packet must be sent */
2284
static int64_t get_packet_send_clock(HTTPContext *c)
2285
{
2286
    int bytes_left, bytes_sent, frame_bytes;
2287

2288
    frame_bytes = c->cur_frame_bytes;
2289
    if (frame_bytes <= 0)
2290
        return c->cur_pts;
2291 2292 2293 2294

    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;
2295 2296 2297 2298 2299 2300 2301 2302
}


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

2303
    av_freep(&c->pb_buffer);
2304 2305
    switch(c->state) {
    case HTTPSTATE_SEND_DATA_HEADER:
2306
        ctx = avformat_alloc_context();
2307 2308
        if (!ctx)
            return AVERROR(ENOMEM);
2309 2310
        c->pfmt_ctx = ctx;
        av_dict_copy(&(c->pfmt_ctx->metadata), c->stream->metadata, 0);
2311

2312
        for(i=0;i<c->stream->nb_streams;i++) {
2313 2314 2315 2316
            LayeredAVStream *src;
            AVStream *st = avformat_new_stream(c->pfmt_ctx, NULL);
            if (!st)
                return AVERROR(ENOMEM);
2317

2318 2319
            /* if file or feed, then just take streams from FFServerStream
             * struct */
2320
            if (!c->stream->feed ||
2321
                c->stream->feed == c->stream)
2322
                src = c->stream->streams[i];
2323
            else
2324 2325
                src = c->stream->feed->streams[c->stream->feed_streams[i]];

2326 2327
            unlayer_stream(c->pfmt_ctx->streams[i], src); //TODO we no longer copy st->internal, does this matter?
            av_assert0(!c->pfmt_ctx->streams[i]->priv_data);
2328 2329 2330

            if (src->codec->flags & AV_CODEC_FLAG_BITEXACT)
                c->pfmt_ctx->flags |= AVFMT_FLAG_BITEXACT;
2331
        }
2332
        /* set output format parameters */
2333
        c->pfmt_ctx->oformat = c->stream->fmt;
2334
        av_assert0(c->pfmt_ctx->nb_streams == c->stream->nb_streams);
2335

2336 2337 2338
        c->got_key_frame = 0;

        /* prepare header and save header data in a stream */
2339
        if (avio_open_dyn_buf(&c->pfmt_ctx->pb) < 0) {
2340 2341 2342
            /* XXX: potential leak */
            return -1;
        }
2343
        c->pfmt_ctx->pb->seekable = 0;
2344

2345
        /*
2346
         * HACK to avoid MPEG-PS muxer to spit many underflow errors
2347
         * Default value from FFmpeg
2348
         * Try to set it using configuration option
2349
         */
2350
        c->pfmt_ctx->max_delay = (int)(0.7*AV_TIME_BASE);
2351

2352
        if ((ret = avformat_write_header(c->pfmt_ctx, NULL)) < 0) {
2353 2354 2355
            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
2356
        }
2357
        av_dict_free(&c->pfmt_ctx->metadata);
2358

2359
        len = avio_close_dyn_buf(c->pfmt_ctx->pb, &c->pb_buffer);
2360 2361 2362 2363
        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
2364 2365 2366 2367
        c->last_packet_sent = 0;
        break;
    case HTTPSTATE_SEND_DATA:
        /* find a new packet */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
        /* 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:
2381 2382 2383
            ret = av_read_frame(c->fmt_in, &pkt);
            if (ret < 0) {
                if (c->stream->feed) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2384
                    /* if coming from feed, it means we reached the end of the
2385
                     * ffm file, so must wait for more data */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2386 2387
                    c->state = HTTPSTATE_WAIT_FEED;
                    return 1; /* state changed */
2388 2389
                }
                if (ret == AVERROR(EAGAIN)) {
2390 2391
                    /* input not ready, come back later */
                    return 0;
2392 2393 2394 2395 2396 2397
                }
                if (c->stream->loop) {
                    avformat_close_input(&c->fmt_in);
                    if (open_input_stream(c, "") < 0)
                        goto no_loop;
                    goto redo;
2398
                } else {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2399
                    no_loop:
2400
                        /* must send trailer now because EOF or error */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2401 2402 2403
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
                }
            } else {
2404
                int source_index = pkt.stream_index;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2405
                /* update first pts if needed */
2406
                if (c->first_pts == AV_NOPTS_VALUE && pkt.dts != AV_NOPTS_VALUE) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2407 2408 2409 2410 2411 2412 2413 2414
                    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;
2415
                        for(i=0;i<c->stream->nb_streams;i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2416
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2417
                                if (pkt.flags & AV_PKT_FLAG_KEY)
Reinhard Tartler's avatar
Reinhard Tartler committed
2418
                                    c->switch_feed_streams[i] = -1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2419 2420
                            if (c->switch_feed_streams[i] >= 0)
                                c->switch_pending = 1;
2421
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2422 2423
                    }
                    for(i=0;i<c->stream->nb_streams;i++) {
2424
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2425
                            AVStream *st = c->fmt_in->streams[source_index];
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2426
                            pkt.stream_index = i;
2427
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2428
                                (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
2429
                                 c->stream->nb_streams == 1))
2430 2431
                                c->got_key_frame = 1;
                            if (!c->stream->send_on_key || c->got_key_frame)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2432 2433 2434 2435
                                goto send_it;
                        }
                    }
                } else {
2436 2437 2438
                    AVStream *ist, *ost;
                send_it:
                    ist = c->fmt_in->streams[source_index];
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2439
                    /* specific handling for RTP: we use several
2440 2441
                     * output streams (one for each RTP connection).
                     * XXX: need more abstract handling */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2442 2443
                    if (c->is_packetized) {
                        /* compute send time and duration */
2444 2445 2446 2447
                        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
2448
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2449 2450 2451 2452
                        /* find RTP context */
                        c->packet_stream_index = pkt.stream_index;
                        ctx = c->rtp_ctx[c->packet_stream_index];
                        if(!ctx) {
2453
                            av_packet_unref(&pkt);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2454
                            break;
2455
                        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2456 2457 2458
                        /* only one stream per RTP connection */
                        pkt.stream_index = 0;
                    } else {
2459
                        ctx = c->pfmt_ctx;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2460 2461 2462 2463 2464
                        /* Fudge here */
                    }

                    if (c->is_packetized) {
                        int max_packet_size;
2465
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2466 2467
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
                        else
2468
                            max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2469 2470
                        ret = ffio_open_dyn_packet_buf(&ctx->pb,
                                                       max_packet_size);
2471
                    } else
2472
                        ret = avio_open_dyn_buf(&ctx->pb);
2473

Baptiste Coudurier's avatar
Baptiste Coudurier committed
2474 2475 2476 2477
                    if (ret < 0) {
                        /* XXX: potential leak */
                        return -1;
                    }
2478 2479
                    ost = ctx->streams[pkt.stream_index];

2480
                    ctx->pb->seekable = 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2481
                    if (pkt.dts != AV_NOPTS_VALUE)
2482 2483
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
                                               ost->time_base);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2484
                    if (pkt.pts != AV_NOPTS_VALUE)
2485 2486 2487 2488
                        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);
2489 2490 2491
                    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
2492
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2493
                    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2494

2495
                    av_freep(&c->pb_buffer);
2496
                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2497
                    ctx->pb = NULL;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2498 2499 2500 2501 2502
                    c->cur_frame_bytes = len;
                    c->buffer_ptr = c->pb_buffer;
                    c->buffer_end = c->pb_buffer + len;

                    if (len == 0) {
2503
                        av_packet_unref(&pkt);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2504
                        goto redo;
2505
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2506
                }
2507
                av_packet_unref(&pkt);
Fabrice Bellard's avatar
Fabrice Bellard committed
2508
            }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2509
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
2510 2511 2512 2513
        break;
    default:
    case HTTPSTATE_SEND_DATA_TRAILER:
        /* last packet test ? */
2514
        if (c->last_packet_sent || c->is_packetized)
Fabrice Bellard's avatar
Fabrice Bellard committed
2515
            return -1;
2516
        ctx = c->pfmt_ctx;
Fabrice Bellard's avatar
Fabrice Bellard committed
2517
        /* prepare header */
2518
        if (avio_open_dyn_buf(&ctx->pb) < 0) {
2519 2520 2521
            /* XXX: potential leak */
            return -1;
        }
2522
        c->pfmt_ctx->pb->seekable = 0;
2523
        av_write_trailer(ctx);
2524
        len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2525 2526 2527
        c->buffer_ptr = c->pb_buffer;
        c->buffer_end = c->pb_buffer + len;

Fabrice Bellard's avatar
Fabrice Bellard committed
2528 2529 2530 2531 2532 2533 2534
        c->last_packet_sent = 1;
        break;
    }
    return 0;
}

/* should convert the format at the same time */
2535
/* send data starting at c->buffer_ptr to the output connection
2536 2537
 * (either UDP or TCP)
 */
2538
static int http_send_data(HTTPContext *c)
Fabrice Bellard's avatar
Fabrice Bellard committed
2539
{
2540
    int len, ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
2541

2542 2543 2544 2545 2546
    for(;;) {
        if (c->buffer_ptr >= c->buffer_end) {
            ret = http_prepare_data(c);
            if (ret < 0)
                return -1;
2547
            else if (ret)
2548 2549
                /* state change requested */
                break;
2550
        } else {
2551 2552 2553 2554 2555 2556 2557
            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;
2558 2559
                    return 0;
                }
2560 2561 2562 2563 2564 2565
                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;
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
                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;

2576
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2577
                    /* RTP packets are sent inside the RTSP TCP connection */
2578
                    AVIOContext *pb;
2579 2580 2581
                    int interleaved_index, size;
                    uint8_t header[4];
                    HTTPContext *rtsp_c;
2582

2583 2584 2585 2586 2587
                    rtsp_c = c->rtsp_c;
                    /* if no RTSP connection left, error */
                    if (!rtsp_c)
                        return -1;
                    /* if already sending something, then wait. */
2588
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2589
                        break;
2590
                    if (avio_open_dyn_buf(&pb) < 0)
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600
                        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;
2601
                    avio_write(pb, header, 4);
2602 2603
                    /* write RTP packet data */
                    c->buffer_ptr += 4;
2604
                    avio_write(pb, c->buffer_ptr, len);
2605
                    size = avio_close_dyn_buf(pb, &c->packet_buffer);
2606 2607 2608
                    /* prepare asynchronous TCP sending */
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2609
                    c->buffer_ptr += len;
2610

2611
                    /* send everything we can NOW */
2612
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2613
                               rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2614
                    if (len > 0)
2615 2616 2617
                        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
2618 2619
                         * send it later, so a new state is needed to
                         * "lock" the RTSP TCP connection */
2620 2621
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
                        break;
2622
                    } else
2623 2624 2625 2626
                        /* all data has been sent */
                        av_freep(&c->packet_buffer);
                } else {
                    /* send RTP packet directly in UDP */
2627
                    c->buffer_ptr += 4;
2628 2629
                    ffurl_write(c->rtp_handles[c->packet_stream_index],
                                c->buffer_ptr, len);
2630
                    c->buffer_ptr += len;
2631 2632
                    /* here we continue as we can send several packets
                     * per 10 ms slot */
2633 2634 2635
                }
            } else {
                /* TCP data output */
2636 2637
                len = send(c->fd, c->buffer_ptr,
                           c->buffer_end - c->buffer_ptr, 0);
2638
                if (len < 0) {
2639 2640
                    if (ff_neterrno() != AVERROR(EAGAIN) &&
                        ff_neterrno() != AVERROR(EINTR))
2641 2642
                        /* error : close connection */
                        return -1;
2643
                    else
2644
                        return 0;
2645 2646
                }
                c->buffer_ptr += len;
2647

2648 2649 2650 2651 2652
                c->data_count += len;
                update_datarate(&c->datarate, c->data_count);
                if (c->stream)
                    c->stream->bytes_served += len;
                break;
2653
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2654
        }
2655
    } /* for(;;) */
Fabrice Bellard's avatar
Fabrice Bellard committed
2656 2657 2658 2659 2660 2661
    return 0;
}

static int http_start_receive_data(HTTPContext *c)
{
    int fd;
2662
    int ret;
2663
    int64_t ret64;
Fabrice Bellard's avatar
Fabrice Bellard committed
2664

2665
    if (c->stream->feed_opened) {
2666 2667
        http_log("Stream feed '%s' was not opened\n",
                 c->stream->feed_filename);
2668 2669
        return AVERROR(EINVAL);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2670

2671
    /* Don't permit writing to this one */
2672
    if (c->stream->readonly) {
2673 2674
        http_log("Cannot write to read-only file '%s'\n",
                 c->stream->feed_filename);
2675 2676
        return AVERROR(EINVAL);
    }
2677

Fabrice Bellard's avatar
Fabrice Bellard committed
2678 2679
    /* open feed */
    fd = open(c->stream->feed_filename, O_RDWR);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2680
    if (fd < 0) {
2681
        ret = AVERROR(errno);
2682
        http_log("Could not open feed file '%s': %s\n",
2683 2684
                 c->stream->feed_filename, strerror(errno));
        return ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
2685
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
2686
    c->feed_fd = fd;
2687

2688 2689 2690 2691
    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);
2692
        if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2693 2694 2695 2696
            ret = AVERROR(errno);
            http_log("Error truncating feed file '%s': %s\n",
                     c->stream->feed_filename, strerror(errno));
            return ret;
2697
        }
2698
    } else {
2699 2700
        ret64 = ffm_read_write_index(fd);
        if (ret64 < 0) {
2701 2702
            http_log("Error reading write index from feed file '%s': %s\n",
                     c->stream->feed_filename, strerror(errno));
2703
            return ret64;
2704
        }
2705
        c->stream->feed_write_index = ret64;
2706 2707
    }

2708 2709
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                        FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
2710 2711 2712 2713 2714 2715 2716
    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;
2717
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
Fabrice Bellard's avatar
Fabrice Bellard committed
2718 2719
    return 0;
}
2720

Fabrice Bellard's avatar
Fabrice Bellard committed
2721 2722 2723
static int http_receive_data(HTTPContext *c)
{
    HTTPContext *c1;
2724
    int len, loop_run = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
2725

2726 2727 2728 2729 2730 2731
    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) {
2732 2733
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
2734 2735
                /* error : close connection */
                goto fail;
2736
            return 0;
2737 2738 2739 2740 2741 2742
        } 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);
2743 2744
            if (c->chunk_size <= 0) { // end of stream or invalid chunk size
                c->chunk_size = 0;
2745
                goto fail;
2746
            }
2747 2748
            c->buffer_ptr = c->buffer;
            break;
2749
        } else if (++loop_run > 10)
2750 2751
            /* no chunk header, abort */
            goto fail;
2752
        else
2753 2754
            c->buffer_ptr++;
    }
2755

2756 2757 2758
    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);
2759
        if (len < 0) {
2760 2761
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
2762 2763
                /* error : close connection */
                goto fail;
2764
        } else if (len == 0)
2765 2766
            /* end of connection : close it */
            goto fail;
2767
        else {
2768
            av_assert0(len <= c->chunk_size);
2769
            c->chunk_size -= len;
2770 2771
            c->buffer_ptr += len;
            c->data_count += len;
2772
            update_datarate(&c->datarate, c->data_count);
2773 2774 2775
        }
    }

2776 2777 2778 2779 2780 2781 2782 2783
    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
2784
    if (c->buffer_ptr >= c->buffer_end) {
2785
        FFServerStream *feed = c->stream;
Fabrice Bellard's avatar
Fabrice Bellard committed
2786
        /* a packet has been received : write it in the store, except
2787
         * if header */
Fabrice Bellard's avatar
Fabrice Bellard committed
2788
        if (c->data_count > FFM_PACKET_SIZE) {
2789 2790 2791 2792 2793
            /* 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
2794 2795 2796 2797
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
                http_log("Error writing to feed file: %s\n", strerror(errno));
                goto fail;
            }
2798

Fabrice Bellard's avatar
Fabrice Bellard committed
2799 2800 2801 2802 2803 2804
            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 */
2805 2806
            if (c->stream->feed_max_size &&
                feed->feed_write_index >= c->stream->feed_max_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
2807 2808 2809
                feed->feed_write_index = FFM_PACKET_SIZE;

            /* write index */
2810
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2811 2812
                http_log("Error writing index to feed file: %s\n",
                         strerror(errno));
2813 2814
                goto fail;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
2815 2816

            /* wake up any waiting connections */
2817
            for(c1 = first_http_ctx; c1; c1 = c1->next) {
2818
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2819
                    c1->stream->feed == c->stream->feed)
Fabrice Bellard's avatar
Fabrice Bellard committed
2820 2821
                    c1->state = HTTPSTATE_SEND_DATA;
            }
2822 2823
        } else {
            /* We have a header in our hands that contains useful data */
2824
            AVFormatContext *s = avformat_alloc_context();
2825
            AVIOContext *pb;
2826
            AVInputFormat *fmt_in;
2827 2828
            int i;

2829 2830 2831
            if (!s)
                goto fail;

2832 2833 2834 2835 2836
            /* use feed output format name to find corresponding input format */
            fmt_in = av_find_input_format(feed->fmt->name);
            if (!fmt_in)
                goto fail;

2837 2838
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
                                    0, NULL, NULL, NULL, NULL);
2839 2840 2841
            if (!pb)
                goto fail;

2842
            pb->seekable = 0;
2843

2844 2845
            s->pb = pb;
            if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2846
                av_freep(&pb);
2847 2848
                goto fail;
            }
2849 2850

            /* Now we have the actual streams */
2851
            if (s->nb_streams != feed->nb_streams) {
2852
                avformat_close_input(&s);
2853
                av_freep(&pb);
2854 2855
                http_log("Feed '%s' stream number does not match registered feed\n",
                         c->stream->feed_filename);
2856 2857
                goto fail;
            }
2858

2859
            for (i = 0; i < s->nb_streams; i++) {
2860
                LayeredAVStream *fst = feed->streams[i];
2861
                AVStream *st = s->streams[i];
2862 2863
                avcodec_parameters_to_context(fst->codec, st->codecpar);
                avcodec_parameters_from_context(fst->codecpar, fst->codec);
2864
            }
2865

2866
            avformat_close_input(&s);
2867
            av_freep(&pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
2868 2869 2870 2871 2872 2873 2874 2875
        }
        c->buffer_ptr = c->buffer;
    }

    return 0;
 fail:
    c->stream->feed_opened = 0;
    close(c->feed_fd);
2876
    /* wake up any waiting connections to stop waiting for feed */
2877
    for(c1 = first_http_ctx; c1; c1 = c1->next) {
2878 2879 2880 2881
        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
2882 2883 2884
    return -1;
}

2885 2886 2887 2888 2889 2890 2891
/********************************************************************/
/* RTSP handling */

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

2895 2896
    str = RTSP_STATUS_CODE2STRING(error_number);
    if (!str)
2897
        str = "Unknown Error";
2898

2899 2900
    avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
    avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2901 2902 2903

    /* output GMT time */
    ti = time(NULL);
2904 2905
    tm = gmtime(&ti);
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2906
    avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2907 2908 2909 2910 2911
}

static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
{
    rtsp_reply_header(c, error_number);
2912
    avio_printf(c->pb, "\r\n");
2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
}

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

2925 2926
    c->buffer_ptr[0] = '\0';
    p = c->buffer;
2927

2928 2929 2930 2931
    get_word(cmd, sizeof(cmd), &p);
    get_word(url, sizeof(url), &p);
    get_word(protocol, sizeof(protocol), &p);

2932 2933 2934
    av_strlcpy(c->method, cmd, sizeof(c->method));
    av_strlcpy(c->url, url, sizeof(c->url));
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2935

2936
    if (avio_open_dyn_buf(&c->pb) < 0) {
2937 2938 2939 2940 2941 2942
        /* XXX: cannot do more */
        c->pb = NULL; /* safety */
        return -1;
    }

    /* check version name */
2943
    if (strcmp(protocol, "RTSP/1.0")) {
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954
        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') {
2955
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968
        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';
2969
        ff_rtsp_parse_line(NULL, header, line, NULL, NULL);
2970 2971 2972 2973 2974 2975
        p = p1 + 1;
    }

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

2976
    if (!strcmp(cmd, "DESCRIBE"))
2977
        rtsp_cmd_describe(c, url);
2978
    else if (!strcmp(cmd, "OPTIONS"))
2979
        rtsp_cmd_options(c, url);
2980
    else if (!strcmp(cmd, "SETUP"))
2981
        rtsp_cmd_setup(c, url, header);
2982
    else if (!strcmp(cmd, "PLAY"))
2983
        rtsp_cmd_play(c, url, header);
2984
    else if (!strcmp(cmd, "PAUSE"))
2985
        rtsp_cmd_interrupt(c, url, header, 1);
2986
    else if (!strcmp(cmd, "TEARDOWN"))
2987
        rtsp_cmd_interrupt(c, url, header, 0);
2988
    else
2989
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2990

2991
 the_end:
2992
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2993
    c->pb = NULL; /* safety */
2994
    if (len < 0)
2995 2996
        /* XXX: cannot do more */
        return -1;
2997

2998 2999 3000 3001 3002 3003
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
    c->state = RTSPSTATE_SEND_REPLY;
    return 0;
}

3004
static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
3005
                                   struct in_addr my_ip)
3006
{
3007
    AVFormatContext *avc;
3008
    AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
3009
    AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
3010
    int i;
3011

3012 3013
    *pbuffer = NULL;

3014
    avc =  avformat_alloc_context();
3015
    if (!avc || !rtp_format)
3016
        return -1;
3017

3018
    avc->oformat = rtp_format;
3019
    av_dict_set(&avc->metadata, "title",
3020
                entry ? entry->value : "No Title", 0);
3021 3022 3023 3024
    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);
3025
    } else
3026
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
3027

3028
    for(i = 0; i < stream->nb_streams; i++) {
3029 3030 3031
        AVStream *st = avformat_new_stream(avc, NULL);
        if (!st)
            goto sdp_done;
3032
        avcodec_parameters_from_context(stream->streams[i]->codecpar, stream->streams[i]->codec);
3033
        unlayer_stream(st, stream->streams[i]);
3034
    }
3035 3036
#define PBUFFER_SIZE 2048
    *pbuffer = av_mallocz(PBUFFER_SIZE);
3037 3038
    if (!*pbuffer)
        goto sdp_done;
3039
    av_sdp_create(&avc, 1, *pbuffer, PBUFFER_SIZE);
3040 3041

 sdp_done:
3042
    av_freep(&avc->streams);
3043
    av_dict_free(&avc->metadata);
3044 3045
    av_free(avc);

3046
    return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
3047 3048
}

3049 3050
static void rtsp_cmd_options(HTTPContext *c, const char *url)
{
3051
    /* rtsp_reply_header(c, RTSP_STATUS_OK); */
3052 3053
    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);
3054 3055
    avio_printf(c->pb, "Public: %s\r\n",
                "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3056
    avio_printf(c->pb, "\r\n");
3057 3058
}

3059 3060
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
{
3061
    FFServerStream *stream;
3062 3063
    char path1[1024];
    const char *path;
3064
    uint8_t *content;
3065 3066
    int content_length;
    socklen_t len;
3067
    struct sockaddr_in my_addr;
3068

3069
    /* find which URL is asked */
3070
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3071 3072 3073 3074
    path = path1;
    if (*path == '/')
        path++;

3075
    for(stream = config.first_stream; stream; stream = stream->next) {
3076 3077
        if (!stream->is_feed &&
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3078 3079 3080 3081 3082
            !strcmp(path, stream->filename)) {
            goto found;
        }
    }
    /* no stream found */
3083
    rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
3084 3085 3086
    return;

 found:
3087
    /* prepare the media description in SDP format */
3088 3089 3090 3091

    /* get the host IP */
    len = sizeof(my_addr);
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3092 3093
    content_length = prepare_sdp_description(stream, &content,
                                             my_addr.sin_addr);
3094 3095 3096 3097 3098
    if (content_length < 0) {
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
        return;
    }
    rtsp_reply_header(c, RTSP_STATUS_OK);
3099 3100 3101 3102
    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");
3103
    avio_write(c->pb, content, content_length);
3104
    av_free(content);
3105 3106 3107 3108 3109 3110 3111 3112 3113
}

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

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

3114
    for(c = first_http_ctx; c; c = c->next) {
3115 3116 3117 3118 3119 3120
        if (!strcmp(c->session_id, session_id))
            return c;
    }
    return NULL;
}

3121
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3122 3123 3124 3125 3126 3127
{
    RTSPTransportField *th;
    int i;

    for(i=0;i<h->nb_transports;i++) {
        th = &h->transports[i];
3128
        if (th->lower_transport == lower_transport)
3129 3130 3131 3132 3133
            return th;
    }
    return NULL;
}

3134
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3135
                           RTSPMessageHeader *h)
3136
{
3137
    FFServerStream *stream;
3138
    int stream_index, rtp_port, rtcp_port;
3139 3140 3141 3142 3143 3144 3145
    char buf[1024];
    char path1[1024];
    const char *path;
    HTTPContext *rtp_c;
    RTSPTransportField *th;
    struct sockaddr_in dest_addr;
    RTSPActionServerSetup setup;
3146

3147
    /* find which URL is asked */
3148
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3149 3150 3151 3152 3153
    path = path1;
    if (*path == '/')
        path++;

    /* now check each stream */
3154
    for(stream = config.first_stream; stream; stream = stream->next) {
3155 3156 3157 3158
        if (stream->is_feed || !stream->fmt ||
            strcmp(stream->fmt->name, "rtp")) {
            continue;
        }
3159 3160 3161 3162 3163
        /* 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;
3164
            }
3165 3166 3167
            stream_index = 0;
            goto found;
        }
3168

3169 3170 3171 3172 3173 3174 3175
        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;
        }
3176 3177 3178 3179 3180 3181 3182
    }
    /* no stream found */
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
    return;
 found:

    /* generate session id if needed */
3183 3184 3185
    if (h->session_id[0] == '\0') {
        unsigned random0 = av_lfg_get(&random_state);
        unsigned random1 = av_lfg_get(&random_state);
3186
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3187 3188
                 random0, random1);
    }
3189

3190
    /* find RTP session, and create it if none found */
3191 3192
    rtp_c = find_rtp_session(h->session_id);
    if (!rtp_c) {
3193
        /* always prefer UDP */
3194
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3195
        if (!th) {
3196
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3197 3198 3199 3200 3201 3202 3203
            if (!th) {
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
                return;
            }
        }

        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3204
                                   th->lower_transport);
3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215
        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;
        }
    }
3216

3217
    /* test if stream is OK (test needed because several SETUP needs
3218
     * to be done for a given file) */
3219 3220 3221 3222
    if (rtp_c->stream != stream) {
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
        return;
    }
3223

3224 3225 3226 3227 3228 3229 3230 3231
    /* 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);
3232
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3233 3234 3235 3236 3237 3238 3239 3240 3241
                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);
3242

3243
    /* setup stream */
3244
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3245 3246 3247 3248 3249 3250 3251
        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 */
3252
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3253 3254

    switch(rtp_c->rtp_protocol) {
3255
    case RTSP_LOWER_TRANSPORT_UDP:
3256 3257
        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]);
3258
        avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3259
                    "client_port=%d-%d;server_port=%d-%d",
3260 3261
                    th->client_port_min, th->client_port_max,
                    rtp_port, rtcp_port);
3262
        break;
3263
    case RTSP_LOWER_TRANSPORT_TCP:
3264
        avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3265 3266 3267 3268 3269
                    stream_index * 2, stream_index * 2 + 1);
        break;
    default:
        break;
    }
3270
    if (setup.transport_option[0] != '\0')
3271 3272
        avio_printf(c->pb, ";%s", setup.transport_option);
    avio_printf(c->pb, "\r\n");
3273

3274

3275
    avio_printf(c->pb, "\r\n");
3276 3277 3278
}


3279 3280 3281 3282
/**
 * find an RTP connection by using the session ID. Check consistency
 * with filename
 */
3283
static HTTPContext *find_rtp_session_with_url(const char *url,
3284 3285 3286 3287 3288
                                              const char *session_id)
{
    HTTPContext *rtp_c;
    char path1[1024];
    const char *path;
3289
    char buf[1024];
3290
    int s, len;
3291 3292 3293 3294 3295

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

3296
    /* find which URL is asked */
3297
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3298 3299 3300
    path = path1;
    if (*path == '/')
        path++;
3301 3302 3303 3304
    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);
3305 3306 3307
      if(!strncmp(path, buf, sizeof(buf)))
        /* XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE
         * if nb_streams>1? */
3308 3309
        return rtp_c;
    }
3310 3311 3312 3313
    len = strlen(path);
    if (len > 0 && path[len - 1] == '/' &&
        !strncmp(path, rtp_c->stream->filename, len - 1))
        return rtp_c;
3314
    return NULL;
3315 3316
}

3317
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3318 3319 3320 3321 3322 3323 3324 3325
{
    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;
    }
3326

3327 3328 3329 3330 3331 3332 3333 3334
    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;
3335

3336 3337 3338
    /* now everything is OK, so we can send the connection parameters */
    rtsp_reply_header(c, RTSP_STATUS_OK);
    /* session ID */
3339 3340
    avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
    avio_printf(c->pb, "\r\n");
3341 3342
}

3343 3344
static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
                               RTSPMessageHeader *h, int pause_only)
3345 3346 3347 3348 3349 3350 3351 3352
{
    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;
    }
3353

3354 3355 3356 3357 3358 3359 3360 3361
    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;
3362
    }
3363

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

3370 3371
    if (!pause_only)
        close_connection(rtp_c);
3372 3373 3374 3375 3376
}

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

3377
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3378 3379
                                       FFServerStream *stream,
                                       const char *session_id,
3380
                                       enum RTSPLowerTransport rtp_protocol)
3381 3382
{
    HTTPContext *c = NULL;
3383
    const char *proto_str;
3384

3385
    /* XXX: should output a warning page when coming
3386
     * close to the connection limit */
3387
    if (nb_connections >= config.nb_max_connections)
3388
        goto fail;
3389

3390 3391 3392 3393
    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
3394

3395 3396
    c->fd = -1;
    c->poll_entry = NULL;
3397
    c->from_addr = *from_addr;
3398 3399 3400 3401 3402 3403
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;
    nb_connections++;
    c->stream = stream;
3404
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3405 3406
    c->state = HTTPSTATE_READY;
    c->is_packetized = 1;
3407 3408
    c->rtp_protocol = rtp_protocol;

3409
    /* protocol is shown in statistics */
3410
    switch(c->rtp_protocol) {
3411
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3412 3413
        proto_str = "MCAST";
        break;
3414
    case RTSP_LOWER_TRANSPORT_UDP:
3415 3416
        proto_str = "UDP";
        break;
3417
    case RTSP_LOWER_TRANSPORT_TCP:
3418 3419 3420 3421 3422 3423
        proto_str = "TCP";
        break;
    default:
        proto_str = "???";
        break;
    }
3424 3425
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3426

3427 3428
    current_bandwidth += stream->bandwidth;

3429 3430 3431
    c->next = first_http_ctx;
    first_http_ctx = c;
    return c;
3432

3433 3434
 fail:
    if (c) {
3435
        av_freep(&c->buffer);
3436 3437 3438 3439 3440
        av_free(c);
    }
    return NULL;
}

3441 3442 3443 3444 3445
/**
 * 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.
 */
3446
static int rtp_new_av_stream(HTTPContext *c,
3447 3448
                             int stream_index, struct sockaddr_in *dest_addr,
                             HTTPContext *rtsp_c)
3449 3450 3451 3452
{
    AVFormatContext *ctx;
    AVStream *st;
    char *ipaddr;
3453
    URLContext *h = NULL;
3454
    uint8_t *dummy_buf;
3455
    int max_packet_size;
3456
    void *st_internal;
3457

3458
    /* now we can open the relevant output stream */
3459
    ctx = avformat_alloc_context();
3460 3461
    if (!ctx)
        return -1;
3462
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3463

3464
    st = avformat_new_stream(ctx, NULL);
3465 3466
    if (!st)
        goto fail;
3467 3468

    st_internal = st->internal;
3469

3470
    if (!c->stream->feed ||
3471
        c->stream->feed == c->stream)
3472
        unlayer_stream(st, c->stream->streams[stream_index]);
3473
    else
3474 3475 3476 3477
        unlayer_stream(st,
               c->stream->feed->streams[c->stream->feed_streams[stream_index]]);
    av_assert0(st->priv_data == NULL);
    av_assert0(st->internal == st_internal);
3478

3479 3480 3481 3482
    /* build destination RTP address */
    ipaddr = inet_ntoa(dest_addr->sin_addr);

    switch(c->rtp_protocol) {
3483 3484
    case RTSP_LOWER_TRANSPORT_UDP:
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3485
        /* RTP/UDP case */
3486

3487 3488 3489 3490 3491 3492 3493
        /* 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),
3494
                     "rtp://%s:%d?multicast=1&ttl=%d",
3495 3496 3497 3498 3499
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
        } else {
            snprintf(ctx->filename, sizeof(ctx->filename),
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
        }
3500

3501
        if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3502 3503
            goto fail;
        c->rtp_handles[stream_index] = h;
3504
        max_packet_size = h->max_packet_size;
3505
        break;
3506
    case RTSP_LOWER_TRANSPORT_TCP:
3507 3508 3509 3510 3511
        /* RTP/TCP case */
        c->rtsp_c = rtsp_c;
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
        break;
    default:
3512 3513 3514
        goto fail;
    }

3515
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3516
             ipaddr, ntohs(dest_addr->sin_port),
3517
             c->stream->filename, stream_index, c->protocol);
3518

3519 3520
    /* normally, no packets should be output here, but the packet size may
     * be checked */
3521
    if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0)
3522 3523
        /* XXX: close stream */
        goto fail;
3524

3525
    if (avformat_write_header(ctx, NULL) < 0) {
3526 3527
    fail:
        if (h)
3528
            ffurl_close(h);
3529
        av_free(st);
3530 3531 3532
        av_free(ctx);
        return -1;
    }
3533
    avio_close_dyn_buf(ctx->pb, &dummy_buf);
3534
    ctx->pb = NULL;
3535
    av_free(dummy_buf);
3536

3537 3538 3539 3540 3541 3542 3543
    c->rtp_ctx[stream_index] = ctx;
    return 0;
}

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

3544
/* FIXME: This code should use avformat_new_stream() */
3545
static LayeredAVStream *add_av_stream1(FFServerStream *stream,
3546
                                AVCodecContext *codec, int copy)
3547
{
3548
    LayeredAVStream *fst;
3549

3550 3551 3552
    if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
        return NULL;

3553
    fst = av_mallocz(sizeof(*fst));
3554 3555
    if (!fst)
        return NULL;
3556
    if (copy) {
3557
        fst->codec = avcodec_alloc_context3(codec->codec);
3558 3559 3560 3561
        if (!fst->codec) {
            av_free(fst);
            return NULL;
        }
3562
        avcodec_copy_context(fst->codec, codec);
3563
    } else
3564
        /* live streams must use the actual feed's codec since it may be
3565
         * updated later to carry extradata needed by them.
3566 3567
         */
        fst->codec = codec;
3568

3569
    //NOTE we previously allocated internal & internal->avctx, these seemed uneeded though
3570
    fst->codecpar = avcodec_parameters_alloc();
3571
    fst->index = stream->nb_streams;
3572
    fst->time_base = codec->time_base;
3573
    fst->pts_wrap_bits = 33;
3574
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3575 3576 3577 3578
    stream->streams[stream->nb_streams++] = fst;
    return fst;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
3579
/* return the stream number in the feed */
3580
static int add_av_stream(FFServerStream *feed, LayeredAVStream *st)
Fabrice Bellard's avatar
Fabrice Bellard committed
3581
{
3582
    LayeredAVStream *fst;
Fabrice Bellard's avatar
Fabrice Bellard committed
3583 3584 3585
    AVCodecContext *av, *av1;
    int i;

3586
    av = st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
3587
    for(i=0;i<feed->nb_streams;i++) {
3588
        av1 = feed->streams[i]->codec;
3589 3590
        if (av1->codec_id == av->codec_id &&
            av1->codec_type == av->codec_type &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3591 3592 3593
            av1->bit_rate == av->bit_rate) {

            switch(av->codec_type) {
3594
            case AVMEDIA_TYPE_AUDIO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3595 3596
                if (av1->channels == av->channels &&
                    av1->sample_rate == av->sample_rate)
3597
                    return i;
Fabrice Bellard's avatar
Fabrice Bellard committed
3598
                break;
3599
            case AVMEDIA_TYPE_VIDEO:
Fabrice Bellard's avatar
Fabrice Bellard committed
3600 3601
                if (av1->width == av->width &&
                    av1->height == av->height &&
3602 3603
                    av1->time_base.den == av->time_base.den &&
                    av1->time_base.num == av->time_base.num &&
Fabrice Bellard's avatar
Fabrice Bellard committed
3604
                    av1->gop_size == av->gop_size)
3605
                    return i;
Fabrice Bellard's avatar
Fabrice Bellard committed
3606
                break;
3607
            default:
3608
                abort();
Fabrice Bellard's avatar
Fabrice Bellard committed
3609 3610 3611
            }
        }
    }
3612

3613
    fst = add_av_stream1(feed, av, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
3614 3615
    if (!fst)
        return -1;
3616 3617 3618
    if (st->recommended_encoder_configuration)
        fst->recommended_encoder_configuration =
            av_strdup(st->recommended_encoder_configuration);
Fabrice Bellard's avatar
Fabrice Bellard committed
3619 3620 3621
    return feed->nb_streams - 1;
}

3622
static void remove_stream(FFServerStream *stream)
3623
{
3624 3625
    FFServerStream **ps;
    ps = &config.first_stream;
3626
    while (*ps) {
3627
        if (*ps == stream)
3628
            *ps = (*ps)->next;
3629
        else
3630 3631 3632 3633 3634
            ps = &(*ps)->next;
    }
}

/* compute the needed AVStream for each file */
3635
static void build_file_streams(void)
3636
{
3637 3638
    FFServerStream *stream;
    AVFormatContext *infile;
3639
    int i, ret;
3640 3641

    /* gather all streams */
3642 3643
    for(stream = config.first_stream; stream; stream = stream->next) {
        infile = NULL;
3644

3645 3646 3647 3648 3649 3650
        if (stream->stream_type != STREAM_TYPE_LIVE || stream->feed)
            continue;

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

3652

3653 3654 3655 3656
        /* 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);
3657

3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680
        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);
3681
                avformat_close_input(&infile);
3682
                goto fail;
3683
            }
3684 3685 3686 3687 3688

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

            avformat_close_input(&infile);
3689 3690 3691 3692
        }
    }
}

3693
static inline
3694
int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream)
3695 3696 3697
{
    int matches = 1;

3698 3699
/* FIXME: Missed check on AVCodecContext.flags */
#define CHECK_CODEC(x)  (ccf->codecpar->x != ccs->codecpar->x)
3700 3701 3702
    if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
        http_log("Codecs do not match for stream %d\n", stream);
        matches = 0;
3703
    } else if (CHECK_CODEC(bit_rate)) {
3704 3705
        http_log("Codec bitrates do not match for stream %d\n", stream);
        matches = 0;
3706 3707 3708
    } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        if (av_cmp_q(ccf->time_base, ccs->time_base) ||
            CHECK_CODEC(width) || CHECK_CODEC(height)) {
3709 3710 3711
            http_log("Codec width, height or framerate do not match for stream %d\n", stream);
            matches = 0;
        }
3712
    } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726
        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
3727
/* compute the needed AVStream for each feed */
3728
static int build_feed_streams(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
3729
{
3730
    FFServerStream *stream, *feed;
3731
    int i, fd;
Fabrice Bellard's avatar
Fabrice Bellard committed
3732

3733
    /* gather all streams */
3734
    for(stream = config.first_stream; stream; stream = stream->next) {
3735
        feed = stream->feed;
3736 3737 3738 3739 3740 3741
        if (!feed)
            continue;

        if (stream->is_feed) {
            for(i=0;i<stream->nb_streams;i++)
                stream->feed_streams[i] = i;
3742
            continue;
Fabrice Bellard's avatar
Fabrice Bellard committed
3743
        }
3744 3745 3746
        /* 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
3747 3748 3749
    }

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

3752
        if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3753
            AVFormatContext *s = NULL;
3754 3755
            int matches = 0;

3756
            /* See if it matches */
3757

3758 3759 3760 3761 3762 3763
            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;
            }
3764

3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781
            /* 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++) {
3782 3783
                AVStream *ss;
                LayeredAVStream *sf;
3784 3785 3786

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

3788 3789 3790 3791 3792 3793 3794
                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;
                }

3795
                matches = check_codec_match (sf, ss, i);
3796 3797 3798 3799 3800 3801
                if (!matches)
                    break;
            }

drop:
            if (s)
3802
                avformat_close_input(&s);
3803

3804 3805
            if (!matches) {
                if (feed->readonly) {
3806 3807
                    http_log("Unable to delete read-only feed file '%s'\n",
                             feed->feed_filename);
3808
                    goto bail;
3809
                }
3810
                unlink(feed->feed_filename);
3811
            }
3812
        }
3813

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

3817 3818
            if (!s) {
                http_log("Failed to allocate context\n");
3819
                goto bail;
3820 3821
            }

3822
            if (feed->readonly) {
3823 3824 3825 3826
                http_log("Unable to create feed file '%s' as it is "
                            "marked readonly\n",
                         feed->feed_filename);
                avformat_free_context(s);
3827
                goto bail;
3828 3829
            }

Fabrice Bellard's avatar
Fabrice Bellard committed
3830
            /* only write the header of the ffm file */
3831
            if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3832 3833
                http_log("Could not open output feed file '%s'\n",
                         feed->feed_filename);
3834
                avformat_free_context(s);
3835
                goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
3836
            }
3837
            s->oformat = feed->fmt;
3838 3839 3840 3841 3842 3843 3844 3845
            for (i = 0; i<feed->nb_streams; i++) {
                AVStream *st = avformat_new_stream(s, NULL); // FIXME free this
                if (!st) {
                    http_log("Failed to allocate stream\n");
                    goto bail;
                }
                unlayer_stream(st, feed->streams[i]);
            }
3846
            if (avformat_write_header(s, NULL) < 0) {
3847
                http_log("Container doesn't support the required parameters\n");
3848
                avio_closep(&s->pb);
3849 3850
                s->streams = NULL;
                s->nb_streams = 0;
3851
                avformat_free_context(s);
3852
                goto bail;
3853
            }
3854
            /* XXX: need better API */
3855
            av_freep(&s->priv_data);
3856
            avio_closep(&s->pb);
3857 3858 3859
            s->streams = NULL;
            s->nb_streams = 0;
            avformat_free_context(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
3860
        }
3861

Fabrice Bellard's avatar
Fabrice Bellard committed
3862 3863 3864
        /* get feed size and write index */
        fd = open(feed->feed_filename, O_RDONLY);
        if (fd < 0) {
3865
            http_log("Could not open output feed file '%s'\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
3866
                    feed->feed_filename);
3867
            goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
3868 3869
        }

3870 3871
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                       FFM_PACKET_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
3872 3873
        feed->feed_size = lseek(fd, 0, SEEK_END);
        /* ensure that we do not wrap before the end of file */
3874
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
Fabrice Bellard's avatar
Fabrice Bellard committed
3875 3876 3877 3878
            feed->feed_max_size = feed->feed_size;

        close(fd);
    }
3879 3880 3881 3882
    return 0;

bail:
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
3883 3884
}

3885 3886 3887
/* compute the bandwidth used by each stream */
static void compute_bandwidth(void)
{
3888 3889
    unsigned bandwidth;
    int i;
3890
    FFServerStream *stream;
3891

3892
    for(stream = config.first_stream; stream; stream = stream->next) {
3893 3894
        bandwidth = 0;
        for(i=0;i<stream->nb_streams;i++) {
3895
            LayeredAVStream *st = stream->streams[i];
3896
            switch(st->codec->codec_type) {
3897 3898
            case AVMEDIA_TYPE_AUDIO:
            case AVMEDIA_TYPE_VIDEO:
3899
                bandwidth += st->codec->bit_rate;
3900 3901 3902 3903 3904 3905 3906 3907 3908
                break;
            default:
                break;
            }
        }
        stream->bandwidth = (bandwidth + 999) / 1000;
    }
}

3909 3910 3911
static void handle_child_exit(int sig)
{
    pid_t pid;
3912 3913
    int status;
    time_t uptime;
3914 3915

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

3918
        for (feed = config.first_feed; feed; feed = feed->next) {
3919 3920
            if (feed->pid != pid)
                continue;
3921

3922 3923 3924
            uptime = time(0) - feed->pid_start;
            feed->pid = 0;
            fprintf(stderr,
3925 3926
                    "%s: Pid %"PRId64" exited with status %d after %"PRId64" "
                        "seconds\n",
3927
                    feed->filename, (int64_t) pid, status, (int64_t)uptime);
3928

3929 3930 3931
            if (uptime < 30)
                /* Turn off any more restarts */
                ffserver_free_child_args(&feed->child_argv);
3932 3933 3934 3935 3936 3937
        }
    }

    need_to_start_children = 1;
}

3938
static void opt_debug(void)
3939
{
3940 3941
    config.debug = 1;
    snprintf(config.logfilename, sizeof(config.logfilename), "-");
3942 3943
}

3944
void show_help_default(const char *opt, const char *arg)
3945
{
3946
    printf("usage: ffserver [options]\n"
3947 3948
           "Hyper fast multi format Audio/Video streaming server\n");
    printf("\n");
3949
    show_help_options(options, "Main options:", 0, 0, 0);
3950 3951 3952
}

static const OptionDef options[] = {
3953
    CMDUTILS_COMMON_OPTIONS
3954 3955
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3956
    { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3957 3958 3959
    { NULL },
};

Fabrice Bellard's avatar
Fabrice Bellard committed
3960 3961
int main(int argc, char **argv)
{
3962
    struct sigaction sigact = { { 0 } };
3963 3964 3965
    int cfg_parsed;
    int ret = EXIT_FAILURE;

3966
    init_dynload();
Fabrice Bellard's avatar
Fabrice Bellard committed
3967

3968
    config.filename = av_strdup("/etc/ffserver.conf");
3969

3970
    parse_loglevel(argc, argv, options);
3971
    av_register_all();
3972
    avformat_network_init();
Fabrice Bellard's avatar
Fabrice Bellard committed
3973

3974
    show_banner(argc, argv, options);
3975

3976
    my_program_name = argv[0];
3977

3978
    parse_options(NULL, argc, argv, options, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
3979

3980
    unsetenv("http_proxy");             /* Kill the http_proxy */
3981

3982
    av_lfg_init(&random_state, av_get_random_seed());
3983

3984 3985 3986 3987
    sigact.sa_handler = handle_child_exit;
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    sigaction(SIGCHLD, &sigact, 0);

3988
    if ((cfg_parsed = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3989
        fprintf(stderr, "Error reading configuration file '%s': %s\n",
3990 3991
                config.filename, av_err2str(cfg_parsed));
        goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
3992 3993
    }

3994
    /* open log file if needed */
3995 3996
    if (config.logfilename[0] != '\0') {
        if (!strcmp(config.logfilename, "-"))
3997
            logfile = stdout;
3998
        else
3999
            logfile = fopen(config.logfilename, "a");
4000 4001 4002
        av_log_set_callback(http_av_log);
    }

4003 4004
    build_file_streams();

4005 4006 4007 4008
    if (build_feed_streams() < 0) {
        http_log("Could not setup feed streams\n");
        goto bail;
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
4009

4010 4011
    compute_bandwidth();

Fabrice Bellard's avatar
Fabrice Bellard committed
4012 4013 4014
    /* signal init */
    signal(SIGPIPE, SIG_IGN);

4015
    if (http_server() < 0) {
4016
        http_log("Could not start server\n");
4017
        goto bail;
Fabrice Bellard's avatar
Fabrice Bellard committed
4018 4019
    }

4020 4021 4022 4023 4024 4025
    ret=EXIT_SUCCESS;

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