ffserver.c 125.5 KB
Newer Older
F
merge  
Fabrice Bellard 已提交
1
/*
2
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
F
merge  
Fabrice Bellard 已提交
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.
F
merge  
Fabrice Bellard 已提交
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
F
merge  
Fabrice Bellard 已提交
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.
F
merge  
Fabrice Bellard 已提交
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
F
merge  
Fabrice Bellard 已提交
19
 */
20

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

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

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

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

71
#include "cmdutils.h"
72
#include "ffserver_config.h"
F
merge  
Fabrice Bellard 已提交
73

74 75
#define PATH_LENGTH 1024

D
Diego Biurrun 已提交
76
const char program_name[] = "ffserver";
77
const int program_birth_year = 2000;
78

79 80
static const OptionDef options[];

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

    RTSPSTATE_WAIT_REQUEST,
    RTSPSTATE_SEND_REPLY,
F
Fabrice Bellard 已提交
93
    RTSPSTATE_SEND_PACKET,
F
merge  
Fabrice Bellard 已提交
94 95
};

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

F
merge  
Fabrice Bellard 已提交
100 101 102 103 104
    "SEND_DATA_HEADER",
    "SEND_DATA",
    "SEND_DATA_TRAILER",
    "RECEIVE_DATA",
    "WAIT_FEED",
105 106 107 108
    "READY",

    "RTSP_WAIT_REQUEST",
    "RTSP_SEND_REPLY",
F
Fabrice Bellard 已提交
109
    "RTSP_SEND_PACKET",
F
merge  
Fabrice Bellard 已提交
110 111
};

P
Philip Gladstone 已提交
112
#define IOBUFFER_INIT_SIZE 8192
F
merge  
Fabrice Bellard 已提交
113 114

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

F
merge  
Fabrice Bellard 已提交
118 119
#define SYNC_TIMEOUT (10 * 1000)

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

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

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

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

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

F
Fabrice Bellard 已提交
187
    /* RTP/UDP specific */
188
    URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
F
Fabrice Bellard 已提交
189 190 191 192

    /* RTP/TCP specific */
    struct HTTPContext *rtsp_c;
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
F
merge  
Fabrice Bellard 已提交
193 194 195 196
} HTTPContext;

typedef struct FeedData {
    long long data_count;
D
Diego Biurrun 已提交
197
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
F
merge  
Fabrice Bellard 已提交
198 199
} FeedData;

200
static HTTPContext *first_http_ctx;
201 202 203 204 205

static FFServerConfig config = {
    .nb_max_http_connections = 2000,
    .nb_max_connections = 5,
    .max_bandwidth = 1000,
206
    .use_defaults = 1,
207
};
F
merge  
Fabrice Bellard 已提交
208

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

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

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

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

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

P
Philip Gladstone 已提交
251 252
static const char *my_program_name;

253
static int no_launch;
254
static int need_to_start_children;
255

256
/* maximum number of simultaneous HTTP connections */
257
static unsigned int nb_connections;
F
merge  
Fabrice Bellard 已提交
258

259
static uint64_t current_bandwidth;
260

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

264
static AVLFG random_state;
265

F
merge  
Fabrice Bellard 已提交
266 267
static FILE *logfile = NULL;

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

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

    if (!src)
        return 0;

    start = src;

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

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

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

    return final_size;
341 342
}

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

347 348
    if (lseek(fd, 8, SEEK_SET) < 0)
        return AVERROR(EIO);
349 350 351 352 353 354 355 356 357 358 359 360
    if (read(fd, buf, 8) != 8)
        return AVERROR(EIO);
    return AV_RB64(buf);
}

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

    for(i=0;i<8;i++)
        buf[i] = (pos >> (56 - i * 8)) & 0xff;
361
    if (lseek(fd, 8, SEEK_SET) < 0)
362
        goto bail_eio;
363
    if (write(fd, buf, 8) != 8)
364 365
        goto bail_eio;

366
    return 8;
367 368 369

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

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

380
static char *ctime1(char *buf2, size_t buf_size)
B
Baptiste Coudurier 已提交
381 382 383 384 385 386
{
    time_t ti;
    char *p;

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

B
Baptiste Coudurier 已提交
398
static void http_vlog(const char *fmt, va_list vargs)
F
merge  
Fabrice Bellard 已提交
399
{
B
Baptiste Coudurier 已提交
400
    static int print_prefix = 1;
401
    char buf[32];
402 403 404 405

    if (!logfile)
        return;

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

415 416 417 418
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
static void http_log(const char *fmt, ...)
B
Baptiste Coudurier 已提交
419 420 421 422 423 424 425 426 427 428 429
{
    va_list vargs;
    va_start(vargs, fmt);
    http_vlog(fmt, vargs);
    va_end(vargs);
}

static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
{
    static int print_prefix = 1;
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
430
    if (level > av_log_get_level())
B
Baptiste Coudurier 已提交
431 432
        return;
    if (print_prefix && avc)
433
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
B
Baptiste Coudurier 已提交
434 435
    print_prefix = strstr(fmt, "\n") != NULL;
    http_vlog(fmt, vargs);
F
merge  
Fabrice Bellard 已提交
436 437
}

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

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

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

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

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

470

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

478 479 480
    if (no_launch)
        return;

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

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

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

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

P
Philip Gladstone 已提交
508
    for (; feed; feed = feed->next) {
509 510 511 512

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

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

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

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

525
        /* In child */
526

527 528
        http_log("Launch command line: ");
        http_log("%s ", pathname);
P
Philip Gladstone 已提交
529

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

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

537 538 539 540 541 542 543 544
        if (!config.debug) {
            if (!freopen("/dev/null", "r", stdin))
                http_log("failed to redirect STDIN to /dev/null\n;");
            if (!freopen("/dev/null", "w", stdout))
                http_log("failed to redirect STDOUT to /dev/null\n;");
            if (!freopen("/dev/null", "w", stderr))
                http_log("failed to redirect STDERR to /dev/null\n;");
        }
P
Philip Gladstone 已提交
545

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

554 555
/* open a listening socket */
static int socket_open_listen(struct sockaddr_in *my_addr)
F
merge  
Fabrice Bellard 已提交
556
{
557
    int server_fd, tmp;
F
merge  
Fabrice Bellard 已提交
558 559 560 561 562 563

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

F
merge  
Fabrice Bellard 已提交
565
    tmp = 1;
566 567
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
        av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
F
merge  
Fabrice Bellard 已提交
568

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

F
merge  
Fabrice Bellard 已提交
578 579
    if (listen (server_fd, 5) < 0) {
        perror ("listen");
580
        goto fail;
F
merge  
Fabrice Bellard 已提交
581
    }
582 583 584

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

    return server_fd;
587 588 589 590

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

669 670
    if (config.http_addr.sin_port) {
        server_fd = socket_open_listen(&config.http_addr);
671 672
        if (server_fd < 0)
            goto quit;
B
Baptiste Coudurier 已提交
673
    }
F
merge  
Fabrice Bellard 已提交
674

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

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

688
    http_log("FFserver started.\n");
F
merge  
Fabrice Bellard 已提交
689

690
    start_children(config.first_feed);
P
Philip Gladstone 已提交
691

692 693
    start_multicast();

F
merge  
Fabrice Bellard 已提交
694 695
    for(;;) {
        poll_entry = poll_table;
B
Baptiste Coudurier 已提交
696
        if (server_fd) {
B
Baptiste Coudurier 已提交
697 698 699
            poll_entry->fd = server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
B
Baptiste Coudurier 已提交
700 701
        }
        if (rtsp_server_fd) {
B
Baptiste Coudurier 已提交
702 703 704
            poll_entry->fd = rtsp_server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
B
Baptiste Coudurier 已提交
705
        }
706

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

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

767
        cur_time = av_gettime() / 1000;
F
merge  
Fabrice Bellard 已提交
768

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

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

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

quit:
    av_free(poll_table);
    return -1;
F
merge  
Fabrice Bellard 已提交
801 802
}

803 804
/* start waiting for a new HTTP/RTSP request */
static void start_wait_request(HTTPContext *c, int is_rtsp)
F
merge  
Fabrice Bellard 已提交
805
{
806 807 808
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */

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

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


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

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

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

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

863 864 865 866 867 868 869
    c->fd = fd;
    c->poll_entry = NULL;
    c->from_addr = from_addr;
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;
870 871 872

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

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

    return;

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

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

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

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

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

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

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

939 940
    ctx = &c->fmt_ctx;

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

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

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

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

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

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

F
merge  
Fabrice Bellard 已提交
976 977
    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
978
    case RTSPSTATE_WAIT_REQUEST:
F
merge  
Fabrice Bellard 已提交
979 980 981 982 983 984 985 986 987 988
        /* timeout ? */
        if ((c->timeout - cur_time) < 0)
            return -1;
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        /* read the data */
989
    read_loop:
990 991 992
        if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
            return -1;

F
merge  
Fabrice Bellard 已提交
993
        if (len < 0) {
994 995
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
F
merge  
Fabrice Bellard 已提交
996
                return -1;
997 998
            break;
        }
999 1000 1001 1002 1003 1004
        /* search for end of request. */
        c->buffer_ptr += len;
        ptr = c->buffer_ptr;
        if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
            (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
            /* request found : parse it and reply */
1005
            if (c->state == HTTPSTATE_WAIT_REQUEST)
1006
                ret = http_parse_request(c);
1007
            else
1008
                ret = rtsp_parse_request(c);
1009

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

F
merge  
Fabrice Bellard 已提交
1017 1018 1019 1020 1021 1022
        break;

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

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

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

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

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

    case RTSPSTATE_SEND_REPLY:
1092 1093
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            goto close_connection;
1094 1095 1096
        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1097
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1098
        if (len < 0) {
1099 1100
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
1101
                goto close_connection;
1102
            }
1103 1104
            break;
        }
1105 1106 1107 1108 1109 1110 1111
        c->buffer_ptr += len;
        c->data_count += len;
        if (c->buffer_ptr >= c->buffer_end) {
            /* all the buffer was sent : wait for a new request */
            av_freep(&c->pb_buffer);
            start_wait_request(c, 1);
        }
1112
        break;
F
Fabrice Bellard 已提交
1113 1114 1115 1116 1117 1118 1119 1120
    case RTSPSTATE_SEND_PACKET:
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
            av_freep(&c->packet_buffer);
            return -1;
        }
        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
1121 1122
        len = send(c->fd, c->packet_buffer_ptr,
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
F
Fabrice Bellard 已提交
1123
        if (len < 0) {
1124 1125
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
F
Fabrice Bellard 已提交
1126 1127 1128 1129
                /* error : close connection */
                av_freep(&c->packet_buffer);
                return -1;
            }
1130 1131
            break;
        }
1132 1133 1134 1135 1136 1137
        c->packet_buffer_ptr += len;
        if (c->packet_buffer_ptr >= c->packet_buffer_end) {
            /* all the buffer was sent : wait for a new request */
            av_freep(&c->packet_buffer);
            c->state = RTSPSTATE_WAIT_REQUEST;
        }
F
Fabrice Bellard 已提交
1138
        break;
1139 1140 1141
    case HTTPSTATE_READY:
        /* nothing to do */
        break;
F
merge  
Fabrice Bellard 已提交
1142 1143 1144 1145
    default:
        return -1;
    }
    return 0;
1146 1147 1148 1149

close_connection:
    av_freep(&c->pb_buffer);
    return -1;
F
merge  
Fabrice Bellard 已提交
1150 1151
}

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

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

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

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

                q += 20;

P
Philip Gladstone 已提交
1169
                memset(rates, 0xff, ratelen);
1170 1171 1172 1173 1174

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

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

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

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

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

        p++;
    }

    return 0;
}

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

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

        if (feed_codec->codec_id != codec->codec_id ||
            feed_codec->sample_rate != codec->sample_rate ||
            feed_codec->width != codec->width ||
1212
            feed_codec->height != codec->height)
P
Philip Gladstone 已提交
1213 1214 1215 1216
            continue;

        /* Potential stream */

1217
        /* We want the fastest stream less than bit_rate, or the slowest
P
Philip Gladstone 已提交
1218 1219 1220 1221
         * faster than bit_rate
         */

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

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

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

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

        switch(rates[i]) {
            case 0:
P
Philip Gladstone 已提交
1252
                c->switch_feed_streams[i] = req->feed_streams[i];
1253 1254
                break;
            case 1:
P
Philip Gladstone 已提交
1255
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1256 1257
                break;
            case 2:
P
Philip Gladstone 已提交
1258 1259 1260 1261 1262 1263 1264
                /* Wants off or slow */
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
#ifdef WANTS_OFF
                /* This doesn't work well when it turns off the only stream! */
                c->switch_feed_streams[i] = -2;
                c->feed_streams[i] = -2;
#endif
1265 1266 1267
                break;
        }

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

P
Philip Gladstone 已提交
1274 1275
    return action_required;
}
1276

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

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

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

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

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

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

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


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

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

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

1355
    for (acl = in_acl; acl; acl = acl->next) {
1356
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1357 1358 1359 1360 1361 1362 1363 1364
            return (acl->action == IP_ALLOW) ? 1 : 0;
        last_action = acl->action;
    }

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

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

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

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

    return ret;
}

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

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

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

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

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

F
merge  
Fabrice Bellard 已提交
1440
    if (!strcmp(cmd, "GET"))
1441
        c->post = 0;
F
merge  
Fabrice Bellard 已提交
1442
    else if (!strcmp(cmd, "POST"))
1443
        c->post = 1;
F
merge  
Fabrice Bellard 已提交
1444 1445 1446
    else
        return -1;

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

1450
    get_word(protocol, sizeof(protocol), (const char **)&p);
F
merge  
Fabrice Bellard 已提交
1451 1452
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
        return -1;
1453

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

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

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

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

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

        p++;
    }

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

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

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

P
Philip Gladstone 已提交
1519 1520 1521 1522 1523 1524 1525
    c->stream = stream;
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));

    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
        c->http_error = 301;
        q = c->buffer;
1526
        snprintf(q, c->buffer_size,
1527 1528 1529 1530
                      "HTTP/1.0 301 Moved\r\n"
                      "Location: %s\r\n"
                      "Content-type: text/html\r\n"
                      "\r\n"
1531
                      "<!DOCTYPE html>\n"
1532 1533
                      "<html><head><title>Moved</title></head><body>\r\n"
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1534 1535
                      "</body></html>\r\n",
                 stream->feed_filename, stream->feed_filename);
1536
        q += strlen(q);
P
Philip Gladstone 已提交
1537 1538 1539 1540 1541 1542 1543
        /* prepare output buffer */
        c->buffer_ptr = c->buffer;
        c->buffer_end = q;
        c->state = HTTPSTATE_SEND_HEADER;
        return 0;
    }

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

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

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

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

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

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

            p++;
        }

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

1607
            while (av_isspace(*hostinfo))
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
                hostinfo++;

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

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

                    c->http_error = 200;
                    q = c->buffer;
1621 1622
                    switch(redir_type) {
                    case REDIR_ASX:
1623
                        snprintf(q, c->buffer_size,
1624 1625 1626 1627 1628 1629 1630
                                      "HTTP/1.0 200 ASX Follows\r\n"
                                      "Content-type: video/x-ms-asf\r\n"
                                      "\r\n"
                                      "<ASX Version=\"3\">\r\n"
                                      //"<!-- Autogenerated by ffserver -->\r\n"
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
                                      "</ASX>\r\n", hostbuf, filename, info);
1631
                        q += strlen(q);
1632 1633
                        break;
                    case REDIR_RAM:
1634
                        snprintf(q, c->buffer_size,
1635 1636 1637 1638 1639
                                      "HTTP/1.0 200 RAM Follows\r\n"
                                      "Content-type: audio/x-pn-realaudio\r\n"
                                      "\r\n"
                                      "# Autogenerated by ffserver\r\n"
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1640
                        q += strlen(q);
1641 1642
                        break;
                    case REDIR_ASF:
1643
                        snprintf(q, c->buffer_size,
1644 1645 1646 1647 1648
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
                                      "Content-type: video/x-ms-asf\r\n"
                                      "\r\n"
                                      "[Reference]\r\n"
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1649
                        q += strlen(q);
1650 1651 1652 1653 1654
                        break;
                    case REDIR_RTSP:
                        {
                            char hostname[256], *p;
                            /* extract only hostname */
1655
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1656 1657 1658
                            p = strrchr(hostname, ':');
                            if (p)
                                *p = '\0';
1659
                            snprintf(q, c->buffer_size,
1660
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1661
                                          /* XXX: incorrect MIME type ? */
1662 1663
                                          "Content-type: application/x-rtsp\r\n"
                                          "\r\n"
1664
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1665
                            q += strlen(q);
1666 1667 1668 1669
                        }
                        break;
                    case REDIR_SDP:
                        {
1670
                            uint8_t *sdp_data;
1671 1672
                            int sdp_data_size;
                            socklen_t len;
1673 1674
                            struct sockaddr_in my_addr;

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

                            len = sizeof(my_addr);
1682 1683 1684 1685

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

1687
                            /* XXX: should use a dynamic buffer */
1688 1689
                            sdp_data_size = prepare_sdp_description(stream,
                                                                    &sdp_data,
1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
                                                                    my_addr.sin_addr);
                            if (sdp_data_size > 0) {
                                memcpy(q, sdp_data, sdp_data_size);
                                q += sdp_data_size;
                                *q = '\0';
                                av_free(sdp_data);
                            }
                        }
                        break;
                    default:
1700
                        abort();
1701
                        break;
1702
                    }
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712

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

1713
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1714
        goto send_error;
F
merge  
Fabrice Bellard 已提交
1715 1716
    }

1717
    stream->conns_served++;
1718

F
merge  
Fabrice Bellard 已提交
1719 1720
    /* XXX: add there authenticate and IP match */

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

1729
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1730
                if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1731 1732 1733
                    logline = p;
                    break;
                }
1734
                if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1735
                    client_id = strtol(p + 18, 0, 10);
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
                p = strchr(p, '\n');
                if (!p)
                    break;

                p++;
            }

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

                logline += 17;

                if (eol) {
                    if (eol[-1] == '\r')
                        eol--;
F
Falk Hüffner 已提交
1751
                    http_log("%.*s\n", (int) (eol - logline), logline);
1752 1753 1754
                    c->suppress_log = 1;
                }
            }
1755

1756
#ifdef DEBUG
P
Philip Gladstone 已提交
1757
            http_log("\nGot request:\n%s\n", c->buffer);
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
#endif

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

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

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

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

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

F
merge  
Fabrice Bellard 已提交
1791
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1792
        goto send_status;
F
merge  
Fabrice Bellard 已提交
1793 1794 1795

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

1800
    /* prepare HTTP header */
1801 1802
    c->buffer[0] = 0;
    av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
F
merge  
Fabrice Bellard 已提交
1803 1804
    mime_type = c->stream->fmt->mime_type;
    if (!mime_type)
A
Alex Beregszaszi 已提交
1805
        mime_type = "application/x-octet-stream";
1806
    av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
F
merge  
Fabrice Bellard 已提交
1807 1808

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

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

1814
        av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
F
merge  
Fabrice Bellard 已提交
1815
    }
1816 1817 1818
    av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
    av_strlcatf(c->buffer, c->buffer_size, "\r\n");
    q = c->buffer + strlen(c->buffer);
1819

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

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

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

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

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

    stream_no = stream->nb_streams;

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

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

        parameters[0] = 0;

        switch(st->codec->codec_type) {
        case AVMEDIA_TYPE_AUDIO:
            type = "audio";
            snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
                     st->codec->channels, st->codec->sample_rate);
            break;
        case AVMEDIA_TYPE_VIDEO:
            type = "video";
            snprintf(parameters, sizeof(parameters),
                     "%dx%d, q=%d-%d, fps=%d", st->codec->width,
                     st->codec->height, st->codec->qmin, st->codec->qmax,
                     st->codec->time_base.den / st->codec->time_base.num);
            break;
        default:
            abort();
        }

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

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

1916
static void compute_status(HTTPContext *c)
F
merge  
Fabrice Bellard 已提交
1917 1918
{
    HTTPContext *c1;
1919
    FFServerStream *stream;
1920
    char *p;
F
merge  
Fabrice Bellard 已提交
1921
    time_t ti;
1922
    int i, len;
1923
    AVIOContext *pb;
P
Philip Gladstone 已提交
1924

1925
    if (avio_open_dyn_buf(&pb) < 0) {
1926
        /* XXX: return an error ? */
P
Philip Gladstone 已提交
1927
        c->buffer_ptr = c->buffer;
1928 1929
        c->buffer_end = c->buffer;
        return;
P
Philip Gladstone 已提交
1930
    }
F
merge  
Fabrice Bellard 已提交
1931

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

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

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

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

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

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

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

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

            avio_printf(pb, "<td align=center> %s <td align=right> %d "
                            "<td align=right> %d <td> %s %s <td align=right> "
                            "%d <td> %s %s",
                        stream->fmt->name, stream->bandwidth,
                        video_bit_rate / 1000, video_codec_name,
                        video_codec_name_extra, audio_bit_rate / 1000,
                        audio_codec_name, audio_codec_name_extra);

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

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

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

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

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

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

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

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

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

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

F
merge  
Fabrice Bellard 已提交
2091
    /* connection status */
2092
    avio_printf(pb, "<h2>Connection Status</h2>\n");
F
merge  
Fabrice Bellard 已提交
2093

2094
    avio_printf(pb, "Number of connections: %d / %d<br>\n",
2095
                nb_connections, config.nb_max_connections);
F
merge  
Fabrice Bellard 已提交
2096

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

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

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

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

F
merge  
Fabrice Bellard 已提交
2136 2137 2138
    /* date */
    ti = time(NULL);
    p = ctime(&ti);
2139 2140
    avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
    avio_printf(pb, "</body>\n</html>\n");
F
merge  
Fabrice Bellard 已提交
2141

2142
    len = avio_close_dyn_buf(pb, &c->pb_buffer);
2143 2144
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
F
merge  
Fabrice Bellard 已提交
2145 2146 2147 2148 2149 2150
}

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

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

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

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

2205
    s->flags |= AVFMT_FLAG_GENPTS;
F
merge  
Fabrice Bellard 已提交
2206
    c->fmt_in = s;
2207 2208 2209
    if (strcmp(s->iformat->name, "ffm") &&
        (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
        http_log("Could not find stream info for input '%s'\n", input_filename);
2210
        avformat_close_input(&s);
2211
        return ret;
2212
    }
2213

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

2224
    if (c->fmt_in->iformat->read_seek)
2225
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2226 2227 2228
    /* set the start time (needed for maxtime and RTP packet timing) */
    c->start_time = cur_time;
    c->first_pts = AV_NOPTS_VALUE;
F
merge  
Fabrice Bellard 已提交
2229 2230 2231
    return 0;
}

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

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

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

    bytes_left = c->buffer_end - c->buffer_ptr;
    bytes_sent = frame_bytes - bytes_left;
    return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2251 2252 2253 2254 2255 2256 2257 2258
}


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

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

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

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

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

2294 2295 2296
        c->got_key_frame = 0;

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

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

2310 2311 2312 2313
        if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
            http_log("Error writing output header for stream '%s': %s\n",
                     c->stream->filename, av_err2str(ret));
            return ret;
B
Baptiste Coudurier 已提交
2314
        }
2315
        av_dict_free(&c->fmt_ctx.metadata);
2316

2317
        len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2318 2319 2320 2321
        c->buffer_ptr = c->pb_buffer;
        c->buffer_end = c->pb_buffer + len;

        c->state = HTTPSTATE_SEND_DATA;
F
merge  
Fabrice Bellard 已提交
2322 2323 2324 2325
        c->last_packet_sent = 0;
        break;
    case HTTPSTATE_SEND_DATA:
        /* find a new packet */
B
Baptiste Coudurier 已提交
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
        /* read a packet from the input stream */
        if (c->stream->feed)
            ffm_set_write_index(c->fmt_in,
                                c->stream->feed->feed_write_index,
                                c->stream->feed->feed_size);

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

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

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

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

L
Lukasz Marek 已提交
2456
                    av_freep(&c->pb_buffer);
2457
                    len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2458
                    ctx->pb = NULL;
B
Baptiste Coudurier 已提交
2459 2460 2461 2462 2463 2464
                    c->cur_frame_bytes = len;
                    c->buffer_ptr = c->pb_buffer;
                    c->buffer_end = c->pb_buffer + len;

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

F
merge  
Fabrice Bellard 已提交
2490 2491 2492 2493 2494 2495 2496
        c->last_packet_sent = 1;
        break;
    }
    return 0;
}

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

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

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

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

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

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

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

static int http_start_receive_data(HTTPContext *c)
{
    int fd;
2624
    int ret;
2625
    int64_t ret64;
F
merge  
Fabrice Bellard 已提交
2626

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

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

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

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

2670 2671
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                        FFM_PACKET_SIZE);
F
merge  
Fabrice Bellard 已提交
2672 2673 2674 2675 2676 2677 2678
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    /* init buffer input */
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
    c->stream->feed_opened = 1;
M
Måns Rullgård 已提交
2679
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
F
merge  
Fabrice Bellard 已提交
2680 2681
    return 0;
}
2682

F
merge  
Fabrice Bellard 已提交
2683 2684 2685
static int http_receive_data(HTTPContext *c)
{
    HTTPContext *c1;
2686
    int len, loop_run = 0;
F
merge  
Fabrice Bellard 已提交
2687

2688 2689 2690 2691 2692 2693
    while (c->chunked_encoding && !c->chunk_size &&
           c->buffer_end > c->buffer_ptr) {
        /* read chunk header, if present */
        len = recv(c->fd, c->buffer_ptr, 1, 0);

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

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

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

F
merge  
Fabrice Bellard 已提交
2743
    if (c->buffer_ptr >= c->buffer_end) {
2744
        FFServerStream *feed = c->stream;
F
merge  
Fabrice Bellard 已提交
2745
        /* a packet has been received : write it in the store, except
2746
         * if header */
F
merge  
Fabrice Bellard 已提交
2747
        if (c->data_count > FFM_PACKET_SIZE) {
2748 2749 2750 2751 2752
            /* XXX: use llseek or url_seek
             * XXX: Should probably fail? */
            if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
                http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);

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

F
merge  
Fabrice Bellard 已提交
2758 2759 2760 2761 2762 2763
            feed->feed_write_index += FFM_PACKET_SIZE;
            /* update file size */
            if (feed->feed_write_index > c->stream->feed_size)
                feed->feed_size = feed->feed_write_index;

            /* handle wrap around if max file size reached */
2764 2765
            if (c->stream->feed_max_size &&
                feed->feed_write_index >= c->stream->feed_max_size)
F
merge  
Fabrice Bellard 已提交
2766 2767 2768
                feed->feed_write_index = FFM_PACKET_SIZE;

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

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

2788 2789 2790
            if (!s)
                goto fail;

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

A
Anton Khirnov 已提交
2796 2797
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
                                    0, NULL, NULL, NULL, NULL);
2798 2799 2800
            if (!pb)
                goto fail;

2801
            pb->seekable = 0;
2802

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

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

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

2824
            avformat_close_input(&s);
2825
            av_freep(&pb);
F
merge  
Fabrice Bellard 已提交
2826 2827 2828 2829 2830 2831 2832 2833
        }
        c->buffer_ptr = c->buffer;
    }

    return 0;
 fail:
    c->stream->feed_opened = 0;
    close(c->feed_fd);
2834
    /* wake up any waiting connections to stop waiting for feed */
2835
    for(c1 = first_http_ctx; c1; c1 = c1->next) {
2836 2837 2838 2839
        if (c1->state == HTTPSTATE_WAIT_FEED &&
            c1->stream->feed == c->stream->feed)
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
    }
F
merge  
Fabrice Bellard 已提交
2840 2841 2842
    return -1;
}

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

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

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

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

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

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

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

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

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

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

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

    /* check version name */
2901
    if (strcmp(protocol, "RTSP/1.0")) {
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
        goto the_end;
    }

    /* parse each header line */
    /* skip to next line */
    while (*p != '\n' && *p != '\0')
        p++;
    if (*p == '\n')
        p++;
    while (*p != '\0') {
2913
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926
        if (!p1)
            break;
        p2 = p1;
        if (p2 > p && p2[-1] == '\r')
            p2--;
        /* skip empty line */
        if (p2 == p)
            break;
        len = p2 - p;
        if (len > sizeof(line) - 1)
            len = sizeof(line) - 1;
        memcpy(line, p, len);
        line[len] = '\0';
2927
        ff_rtsp_parse_line(NULL, header, line, NULL, NULL);
2928 2929 2930 2931 2932 2933
        p = p1 + 1;
    }

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

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

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

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

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

2971 2972
    *pbuffer = NULL;

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

M
Michael Niedermayer 已提交
2977
    avc->oformat = rtp_format;
2978
    av_dict_set(&avc->metadata, "title",
2979
                entry ? entry->value : "No Title", 0);
L
Luca Abeni 已提交
2980 2981 2982 2983 2984
    avc->nb_streams = stream->nb_streams;
    if (stream->is_multicast) {
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
                 inet_ntoa(stream->multicast_ip),
                 stream->multicast_port, stream->multicast_ttl);
2985
    } else
2986
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2987

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

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

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

 sdp_done:
3006
    av_freep(&avc->streams);
3007
    av_dict_free(&avc->metadata);
L
Luca Abeni 已提交
3008
    av_free(avc);
3009
    av_free(avs);
L
Luca Abeni 已提交
3010

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

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

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

3034
    /* find which URL is asked */
M
Måns Rullgård 已提交
3035
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3036 3037 3038 3039
    path = path1;
    if (*path == '/')
        path++;

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

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

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

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

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

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

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

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

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

3112
    /* find which URL is asked */
M
Måns Rullgård 已提交
3113
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3114 3115 3116 3117 3118
    path = path1;
    if (*path == '/')
        path++;

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

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

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

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

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

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

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

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

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

3239

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


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

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

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

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

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

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

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

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

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

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

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

3342
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3343 3344
                                       FFServerStream *stream,
                                       const char *session_id,
3345
                                       enum RTSPLowerTransport rtp_protocol)
3346 3347
{
    HTTPContext *c = NULL;
F
Fabrice Bellard 已提交
3348
    const char *proto_str;
3349

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

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

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

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

3392 3393
    current_bandwidth += stream->bandwidth;

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

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

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

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

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

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

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

F
Fabrice Bellard 已提交
3447 3448 3449 3450
    /* build destination RTP address */
    ipaddr = inet_ntoa(dest_addr->sin_addr);

    switch(c->rtp_protocol) {
3451 3452
    case RTSP_LOWER_TRANSPORT_UDP:
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
F
Fabrice Bellard 已提交
3453
        /* RTP/UDP case */
3454

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

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

3483
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3484
             ipaddr, ntohs(dest_addr->sin_port),
F
Fabrice Bellard 已提交
3485
             c->stream->filename, stream_index, c->protocol);
3486

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

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

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

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

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

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

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

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

F
merge  
Fabrice Bellard 已提交
3546
/* return the stream number in the feed */
3547
static int add_av_stream(FFServerStream *feed, AVStream *st)
F
merge  
Fabrice Bellard 已提交
3548 3549 3550 3551 3552
{
    AVStream *fst;
    AVCodecContext *av, *av1;
    int i;

3553
    av = st->codec;
F
merge  
Fabrice Bellard 已提交
3554
    for(i=0;i<feed->nb_streams;i++) {
3555
        av1 = feed->streams[i]->codec;
3556 3557
        if (av1->codec_id == av->codec_id &&
            av1->codec_type == av->codec_type &&
F
merge  
Fabrice Bellard 已提交
3558 3559 3560
            av1->bit_rate == av->bit_rate) {

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

H
Howard Chu 已提交
3580
    fst = add_av_stream1(feed, av, 0);
F
merge  
Fabrice Bellard 已提交
3581 3582
    if (!fst)
        return -1;
3583 3584 3585
    if (av_stream_get_recommended_encoder_configuration(st))
        av_stream_set_recommended_encoder_configuration(fst,
            av_strdup(av_stream_get_recommended_encoder_configuration(st)));
F
merge  
Fabrice Bellard 已提交
3586 3587 3588
    return feed->nb_streams - 1;
}

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

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

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

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

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

3652
/* compute the needed AVStream for each file */
3653
static void build_file_streams(void)
3654
{
3655 3656
    FFServerStream *stream;
    AVFormatContext *infile;
B
Baptiste Coudurier 已提交
3657
    int i, ret;
3658 3659

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

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

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

3670

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

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

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

            avformat_close_input(&infile);
3708 3709 3710 3711
        }
    }
}

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

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

    return matches;
}

F
merge  
Fabrice Bellard 已提交
3747
/* compute the needed AVStream for each feed */
3748
static int build_feed_streams(void)
F
merge  
Fabrice Bellard 已提交
3749
{
3750
    FFServerStream *stream, *feed;
3751
    int i, fd;
F
merge  
Fabrice Bellard 已提交
3752

P
Philip Gladstone 已提交
3753
    /* gather all streams */
3754
    for(stream = config.first_stream; stream; stream = stream->next) {
P
Philip Gladstone 已提交
3755
        feed = stream->feed;
3756 3757 3758 3759 3760 3761
        if (!feed)
            continue;

        if (stream->is_feed) {
            for(i=0;i<stream->nb_streams;i++)
                stream->feed_streams[i] = i;
3762
            continue;
F
merge  
Fabrice Bellard 已提交
3763
        }
3764 3765 3766
        /* 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]);
F
merge  
Fabrice Bellard 已提交
3767 3768 3769
    }

    /* create feed files if needed */
3770
    for(feed = config.first_feed; feed; feed = feed->next_feed) {
F
merge  
Fabrice Bellard 已提交
3771

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

3776
            /* See if it matches */
3777

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

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

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

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

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

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

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

drop:
            if (s)
3821
                avformat_close_input(&s);
3822

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

3833
        if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3834
            AVFormatContext *s = avformat_alloc_context();
F
merge  
Fabrice Bellard 已提交
3835

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

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

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

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

3881 3882
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd),
                                       FFM_PACKET_SIZE);
F
merge  
Fabrice Bellard 已提交
3883 3884
        feed->feed_size = lseek(fd, 0, SEEK_END);
        /* ensure that we do not wrap before the end of file */
A
Alex Beregszaszi 已提交
3885
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
F
merge  
Fabrice Bellard 已提交
3886 3887 3888 3889
            feed->feed_max_size = feed->feed_size;

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

bail:
    return -1;
F
merge  
Fabrice Bellard 已提交
3894 3895
}

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

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

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

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

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

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

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

    need_to_start_children = 1;
}

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

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

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

F
merge  
Fabrice Bellard 已提交
3971 3972
int main(int argc, char **argv)
{
3973
    struct sigaction sigact = { { 0 } };
3974 3975 3976
    int cfg_parsed;
    int ret = EXIT_FAILURE;

F
merge  
Fabrice Bellard 已提交
3977

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

3980
    parse_loglevel(argc, argv, options);
3981
    av_register_all();
3982
    avformat_network_init();
F
merge  
Fabrice Bellard 已提交
3983

3984
    show_banner(argc, argv, options);
3985

P
Philip Gladstone 已提交
3986
    my_program_name = argv[0];
3987

3988
    parse_options(NULL, argc, argv, options, NULL);
F
merge  
Fabrice Bellard 已提交
3989

3990
    unsetenv("http_proxy");             /* Kill the http_proxy */
P
Philip Gladstone 已提交
3991

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

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

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

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

4013 4014
    build_file_streams();

4015 4016 4017 4018
    if (build_feed_streams() < 0) {
        http_log("Could not setup feed streams\n");
        goto bail;
    }
F
merge  
Fabrice Bellard 已提交
4019

4020 4021
    compute_bandwidth();

F
merge  
Fabrice Bellard 已提交
4022 4023 4024
    /* signal init */
    signal(SIGPIPE, SIG_IGN);

4025
    if (http_server() < 0) {
4026
        http_log("Could not start server\n");
4027
        goto bail;
F
merge  
Fabrice Bellard 已提交
4028 4029
    }

4030 4031 4032 4033 4034 4035
    ret=EXIT_SUCCESS;

bail:
    av_freep (&config.filename);
    avformat_network_deinit();
    return ret;
F
merge  
Fabrice Bellard 已提交
4036
}