Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 3b963552

History | View | Annotate | Download (153 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

    
24
#include "config.h"
25
#if !HAVE_CLOSESOCKET
26
#define closesocket close
27
#endif
28
#include <string.h>
29
#include <strings.h>
30
#include <stdlib.h>
31
#include "libavformat/avformat.h"
32
#include "libavformat/network.h"
33
#include "libavformat/os_support.h"
34
#include "libavformat/rtpdec.h"
35
#include "libavformat/rtsp.h"
36
#include "libavutil/avstring.h"
37
#include "libavutil/lfg.h"
38
#include "libavutil/random_seed.h"
39
#include "libavcodec/opt.h"
40
#include <stdarg.h>
41
#include <unistd.h>
42
#include <fcntl.h>
43
#include <sys/ioctl.h>
44
#if HAVE_POLL_H
45
#include <poll.h>
46
#endif
47
#include <errno.h>
48
#include <sys/time.h>
49
#include <time.h>
50
#include <sys/wait.h>
51
#include <signal.h>
52
#if HAVE_DLFCN_H
53
#include <dlfcn.h>
54
#endif
55

    
56
#include "cmdutils.h"
57

    
58
const char program_name[] = "FFserver";
59
const int program_birth_year = 2000;
60

    
61
static const OptionDef options[];
62

    
63
enum HTTPState {
64
    HTTPSTATE_WAIT_REQUEST,
65
    HTTPSTATE_SEND_HEADER,
66
    HTTPSTATE_SEND_DATA_HEADER,
67
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
68
    HTTPSTATE_SEND_DATA_TRAILER,
69
    HTTPSTATE_RECEIVE_DATA,
70
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
71
    HTTPSTATE_READY,
72

    
73
    RTSPSTATE_WAIT_REQUEST,
74
    RTSPSTATE_SEND_REPLY,
75
    RTSPSTATE_SEND_PACKET,
76
};
77

    
78
static const char *http_state[] = {
79
    "HTTP_WAIT_REQUEST",
80
    "HTTP_SEND_HEADER",
81

    
82
    "SEND_DATA_HEADER",
83
    "SEND_DATA",
84
    "SEND_DATA_TRAILER",
85
    "RECEIVE_DATA",
86
    "WAIT_FEED",
87
    "READY",
88

    
89
    "RTSP_WAIT_REQUEST",
90
    "RTSP_SEND_REPLY",
91
    "RTSP_SEND_PACKET",
92
};
93

    
94
#define IOBUFFER_INIT_SIZE 8192
95

    
96
/* timeouts are in ms */
97
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
98
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
99

    
100
#define SYNC_TIMEOUT (10 * 1000)
101

    
102
typedef struct RTSPActionServerSetup {
103
    uint32_t ipaddr;
104
    char transport_option[512];
105
} RTSPActionServerSetup;
106

    
107
typedef struct {
108
    int64_t count1, count2;
109
    int64_t time1, time2;
110
} DataRateData;
111

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

    
159
    /* RTSP state specific */
160
    uint8_t *pb_buffer; /* XXX: use that in all the code */
161
    ByteIOContext *pb;
162
    int seq; /* RTSP sequence number */
163

    
164
    /* RTP state specific */
165
    enum RTSPLowerTransport rtp_protocol;
166
    char session_id[32]; /* session id */
167
    AVFormatContext *rtp_ctx[MAX_STREAMS];
168

    
169
    /* RTP/UDP specific */
170
    URLContext *rtp_handles[MAX_STREAMS];
171

    
172
    /* RTP/TCP specific */
173
    struct HTTPContext *rtsp_c;
174
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
175
} HTTPContext;
176

    
177
/* each generated stream is described here */
178
enum StreamType {
179
    STREAM_TYPE_LIVE,
180
    STREAM_TYPE_STATUS,
181
    STREAM_TYPE_REDIRECT,
182
};
183

    
184
enum IPAddressAction {
185
    IP_ALLOW = 1,
186
    IP_DENY,
187
};
188

    
189
typedef struct IPAddressACL {
190
    struct IPAddressACL *next;
191
    enum IPAddressAction action;
192
    /* These are in host order */
193
    struct in_addr first;
194
    struct in_addr last;
195
} IPAddressACL;
196

    
197
/* description of each stream of the ffserver.conf file */
198
typedef struct FFStream {
199
    enum StreamType stream_type;
200
    char filename[1024];     /* stream filename */
201
    struct FFStream *feed;   /* feed we are using (can be null if
202
                                coming from file) */
203
    AVFormatParameters *ap_in; /* input parameters */
204
    AVInputFormat *ifmt;       /* if non NULL, force input format */
205
    AVOutputFormat *fmt;
206
    IPAddressACL *acl;
207
    char dynamic_acl[1024];
208
    int nb_streams;
209
    int prebuffer;      /* Number of millseconds early to start */
210
    int64_t max_time;      /* Number of milliseconds to run */
211
    int send_on_key;
212
    AVStream *streams[MAX_STREAMS];
213
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
214
    char feed_filename[1024]; /* file name of the feed storage, or
215
                                 input file name for a stream */
216
    char author[512];
217
    char title[512];
218
    char copyright[512];
219
    char comment[512];
220
    pid_t pid;  /* Of ffmpeg process */
221
    time_t pid_start;  /* Of ffmpeg process */
222
    char **child_argv;
223
    struct FFStream *next;
224
    unsigned bandwidth; /* bandwidth, in kbits/s */
225
    /* RTSP options */
226
    char *rtsp_option;
227
    /* multicast specific */
228
    int is_multicast;
229
    struct in_addr multicast_ip;
230
    int multicast_port; /* first port used for multicast */
231
    int multicast_ttl;
232
    int loop; /* if true, send the stream in loops (only meaningful if file) */
233

    
234
    /* feed specific */
235
    int feed_opened;     /* true if someone is writing to the feed */
236
    int is_feed;         /* true if it is a feed */
237
    int readonly;        /* True if writing is prohibited to the file */
238
    int truncate;        /* True if feeder connection truncate the feed file */
239
    int conns_served;
240
    int64_t bytes_served;
241
    int64_t feed_max_size;      /* maximum storage size, zero means unlimited */
242
    int64_t feed_write_index;   /* current write position in feed (it wraps around) */
243
    int64_t feed_size;          /* current size of feed */
244
    struct FFStream *next_feed;
245
} FFStream;
246

    
247
typedef struct FeedData {
248
    long long data_count;
249
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
250
} FeedData;
251

    
252
static struct sockaddr_in my_http_addr;
253
static struct sockaddr_in my_rtsp_addr;
254

    
255
static char logfilename[1024];
256
static HTTPContext *first_http_ctx;
257
static FFStream *first_feed;   /* contains only feeds */
258
static FFStream *first_stream; /* contains all streams, including feeds */
259

    
260
static void new_connection(int server_fd, int is_rtsp);
261
static void close_connection(HTTPContext *c);
262

    
263
/* HTTP handling */
264
static int handle_connection(HTTPContext *c);
265
static int http_parse_request(HTTPContext *c);
266
static int http_send_data(HTTPContext *c);
267
static void compute_status(HTTPContext *c);
268
static int open_input_stream(HTTPContext *c, const char *info);
269
static int http_start_receive_data(HTTPContext *c);
270
static int http_receive_data(HTTPContext *c);
271

    
272
/* RTSP handling */
273
static int rtsp_parse_request(HTTPContext *c);
274
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
275
static void rtsp_cmd_options(HTTPContext *c, const char *url);
276
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
277
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
278
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
279
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
280

    
281
/* SDP handling */
282
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
283
                                   struct in_addr my_ip);
284

    
285
/* RTP handling */
286
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
287
                                       FFStream *stream, const char *session_id,
288
                                       enum RTSPLowerTransport rtp_protocol);
289
static int rtp_new_av_stream(HTTPContext *c,
290
                             int stream_index, struct sockaddr_in *dest_addr,
291
                             HTTPContext *rtsp_c);
292

    
293
static const char *my_program_name;
294
static const char *my_program_dir;
295

    
296
static const char *config_filename = "/etc/ffserver.conf";
297

    
298
static int ffserver_debug;
299
static int ffserver_daemon;
300
static int no_launch;
301
static int need_to_start_children;
302

    
303
/* maximum number of simultaneous HTTP connections */
304
static unsigned int nb_max_http_connections = 2000;
305
static unsigned int nb_max_connections = 5;
306
static unsigned int nb_connections;
307

    
308
static uint64_t max_bandwidth = 1000;
309
static uint64_t current_bandwidth;
310

    
311
static int64_t cur_time;           // Making this global saves on passing it around everywhere
312

    
313
static AVLFG random_state;
314

    
315
static FILE *logfile = NULL;
316

    
317
/* FIXME: make ffserver work with IPv6 */
318
/* resolve host with also IP address parsing */
319
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
320
{
321

    
322
    if (!ff_inet_aton(hostname, sin_addr)) {
323
#if HAVE_GETADDRINFO
324
        struct addrinfo *ai, *cur;
325
        struct addrinfo hints;
326
        memset(&hints, 0, sizeof(hints));
327
        hints.ai_family = AF_INET;
328
        if (getaddrinfo(hostname, NULL, &hints, &ai))
329
            return -1;
330
        /* getaddrinfo returns a linked list of addrinfo structs.
331
         * Even if we set ai_family = AF_INET above, make sure
332
         * that the returned one actually is of the correct type. */
333
        for (cur = ai; cur; cur = cur->ai_next) {
334
            if (cur->ai_family == AF_INET) {
335
                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
336
                freeaddrinfo(ai);
337
                return 0;
338
            }
339
        }
340
        freeaddrinfo(ai);
341
        return -1;
342
#else
343
        struct hostent *hp;
344
        hp = gethostbyname(hostname);
345
        if (!hp)
346
            return -1;
347
        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
348
#endif
349
    }
350
    return 0;
351
}
352

    
353
static char *ctime1(char *buf2)
354
{
355
    time_t ti;
356
    char *p;
357

    
358
    ti = time(NULL);
359
    p = ctime(&ti);
360
    strcpy(buf2, p);
361
    p = buf2 + strlen(p) - 1;
362
    if (*p == '\n')
363
        *p = '\0';
364
    return buf2;
365
}
366

    
367
static void http_vlog(const char *fmt, va_list vargs)
368
{
369
    static int print_prefix = 1;
370
    if (logfile) {
371
        if (print_prefix) {
372
            char buf[32];
373
            ctime1(buf);
374
            fprintf(logfile, "%s ", buf);
375
        }
376
        print_prefix = strstr(fmt, "\n") != NULL;
377
        vfprintf(logfile, fmt, vargs);
378
        fflush(logfile);
379
    }
380
}
381

    
382
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
383
{
384
    va_list vargs;
385
    va_start(vargs, fmt);
386
    http_vlog(fmt, vargs);
387
    va_end(vargs);
388
}
389

    
390
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
391
{
392
    static int print_prefix = 1;
393
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
394
    if (level > av_log_get_level())
395
        return;
396
    if (print_prefix && avc)
397
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
398
    print_prefix = strstr(fmt, "\n") != NULL;
399
    http_vlog(fmt, vargs);
400
}
401

    
402
static void log_connection(HTTPContext *c)
403
{
404
    if (c->suppress_log)
405
        return;
406

    
407
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
408
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
409
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
410
}
411

    
412
static void update_datarate(DataRateData *drd, int64_t count)
413
{
414
    if (!drd->time1 && !drd->count1) {
415
        drd->time1 = drd->time2 = cur_time;
416
        drd->count1 = drd->count2 = count;
417
    } else if (cur_time - drd->time2 > 5000) {
418
        drd->time1 = drd->time2;
419
        drd->count1 = drd->count2;
420
        drd->time2 = cur_time;
421
        drd->count2 = count;
422
    }
423
}
424

    
425
/* In bytes per second */
426
static int compute_datarate(DataRateData *drd, int64_t count)
427
{
428
    if (cur_time == drd->time1)
429
        return 0;
430

    
431
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
432
}
433

    
434

    
435
static void start_children(FFStream *feed)
436
{
437
    if (no_launch)
438
        return;
439

    
440
    for (; feed; feed = feed->next) {
441
        if (feed->child_argv && !feed->pid) {
442
            feed->pid_start = time(0);
443

    
444
            feed->pid = fork();
445

    
446
            if (feed->pid < 0) {
447
                http_log("Unable to create children\n");
448
                exit(1);
449
            }
450
            if (!feed->pid) {
451
                /* In child */
452
                char pathname[1024];
453
                char *slash;
454
                int i;
455

    
456
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
457

    
458
                slash = strrchr(pathname, '/');
459
                if (!slash)
460
                    slash = pathname;
461
                else
462
                    slash++;
463
                strcpy(slash, "ffmpeg");
464

    
465
                http_log("Launch commandline: ");
466
                http_log("%s ", pathname);
467
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
468
                    http_log("%s ", feed->child_argv[i]);
469
                http_log("\n");
470

    
471
                for (i = 3; i < 256; i++)
472
                    close(i);
473

    
474
                if (!ffserver_debug) {
475
                    i = open("/dev/null", O_RDWR);
476
                    if (i != -1) {
477
                        dup2(i, 0);
478
                        dup2(i, 1);
479
                        dup2(i, 2);
480
                        close(i);
481
                    }
482
                }
483

    
484
                /* This is needed to make relative pathnames work */
485
                chdir(my_program_dir);
486

    
487
                signal(SIGPIPE, SIG_DFL);
488

    
489
                execvp(pathname, feed->child_argv);
490

    
491
                _exit(1);
492
            }
493
        }
494
    }
495
}
496

    
497
/* open a listening socket */
498
static int socket_open_listen(struct sockaddr_in *my_addr)
499
{
500
    int server_fd, tmp;
501

    
502
    server_fd = socket(AF_INET,SOCK_STREAM,0);
503
    if (server_fd < 0) {
504
        perror ("socket");
505
        return -1;
506
    }
507

    
508
    tmp = 1;
509
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
510

    
511
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
512
        char bindmsg[32];
513
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
514
        perror (bindmsg);
515
        closesocket(server_fd);
516
        return -1;
517
    }
518

    
519
    if (listen (server_fd, 5) < 0) {
520
        perror ("listen");
521
        closesocket(server_fd);
522
        return -1;
523
    }
524
    ff_socket_nonblock(server_fd, 1);
525

    
526
    return server_fd;
527
}
528

    
529
/* start all multicast streams */
530
static void start_multicast(void)
531
{
532
    FFStream *stream;
533
    char session_id[32];
534
    HTTPContext *rtp_c;
535
    struct sockaddr_in dest_addr;
536
    int default_port, stream_index;
537

    
538
    default_port = 6000;
539
    for(stream = first_stream; stream != NULL; stream = stream->next) {
540
        if (stream->is_multicast) {
541
            /* open the RTP connection */
542
            snprintf(session_id, sizeof(session_id), "%08x%08x",
543
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
544

    
545
            /* choose a port if none given */
546
            if (stream->multicast_port == 0) {
547
                stream->multicast_port = default_port;
548
                default_port += 100;
549
            }
550

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

    
555
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
556
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
557
            if (!rtp_c)
558
                continue;
559

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

    
566
            /* open each RTP stream */
567
            for(stream_index = 0; stream_index < stream->nb_streams;
568
                stream_index++) {
569
                dest_addr.sin_port = htons(stream->multicast_port +
570
                                           2 * stream_index);
571
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
572
                    http_log("Could not open output stream '%s/streamid=%d'\n",
573
                             stream->filename, stream_index);
574
                    exit(1);
575
                }
576
            }
577

    
578
            /* change state to send data */
579
            rtp_c->state = HTTPSTATE_SEND_DATA;
580
        }
581
    }
582
}
583

    
584
/* main loop of the http server */
585
static int http_server(void)
586
{
587
    int server_fd = 0, rtsp_server_fd = 0;
588
    int ret, delay, delay1;
589
    struct pollfd *poll_table, *poll_entry;
590
    HTTPContext *c, *c_next;
591

    
592
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
593
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
594
        return -1;
595
    }
596

    
597
    if (my_http_addr.sin_port) {
598
        server_fd = socket_open_listen(&my_http_addr);
599
        if (server_fd < 0)
600
            return -1;
601
    }
602

    
603
    if (my_rtsp_addr.sin_port) {
604
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
605
        if (rtsp_server_fd < 0)
606
            return -1;
607
    }
608

    
609
    if (!rtsp_server_fd && !server_fd) {
610
        http_log("HTTP and RTSP disabled.\n");
611
        return -1;
612
    }
613

    
614
    http_log("FFserver started.\n");
615

    
616
    start_children(first_feed);
617

    
618
    start_multicast();
619

    
620
    for(;;) {
621
        poll_entry = poll_table;
622
        if (server_fd) {
623
            poll_entry->fd = server_fd;
624
            poll_entry->events = POLLIN;
625
            poll_entry++;
626
        }
627
        if (rtsp_server_fd) {
628
            poll_entry->fd = rtsp_server_fd;
629
            poll_entry->events = POLLIN;
630
            poll_entry++;
631
        }
632

    
633
        /* wait for events on each HTTP handle */
634
        c = first_http_ctx;
635
        delay = 1000;
636
        while (c != NULL) {
637
            int fd;
638
            fd = c->fd;
639
            switch(c->state) {
640
            case HTTPSTATE_SEND_HEADER:
641
            case RTSPSTATE_SEND_REPLY:
642
            case RTSPSTATE_SEND_PACKET:
643
                c->poll_entry = poll_entry;
644
                poll_entry->fd = fd;
645
                poll_entry->events = POLLOUT;
646
                poll_entry++;
647
                break;
648
            case HTTPSTATE_SEND_DATA_HEADER:
649
            case HTTPSTATE_SEND_DATA:
650
            case HTTPSTATE_SEND_DATA_TRAILER:
651
                if (!c->is_packetized) {
652
                    /* for TCP, we output as much as we can (may need to put a limit) */
653
                    c->poll_entry = poll_entry;
654
                    poll_entry->fd = fd;
655
                    poll_entry->events = POLLOUT;
656
                    poll_entry++;
657
                } else {
658
                    /* when ffserver is doing the timing, we work by
659
                       looking at which packet need to be sent every
660
                       10 ms */
661
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
662
                    if (delay1 < delay)
663
                        delay = delay1;
664
                }
665
                break;
666
            case HTTPSTATE_WAIT_REQUEST:
667
            case HTTPSTATE_RECEIVE_DATA:
668
            case HTTPSTATE_WAIT_FEED:
669
            case RTSPSTATE_WAIT_REQUEST:
670
                /* need to catch errors */
671
                c->poll_entry = poll_entry;
672
                poll_entry->fd = fd;
673
                poll_entry->events = POLLIN;/* Maybe this will work */
674
                poll_entry++;
675
                break;
676
            default:
677
                c->poll_entry = NULL;
678
                break;
679
            }
680
            c = c->next;
681
        }
682

    
683
        /* wait for an event on one connection. We poll at least every
684
           second to handle timeouts */
685
        do {
686
            ret = poll(poll_table, poll_entry - poll_table, delay);
687
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
688
                ff_neterrno() != FF_NETERROR(EINTR))
689
                return -1;
690
        } while (ret < 0);
691

    
692
        cur_time = av_gettime() / 1000;
693

    
694
        if (need_to_start_children) {
695
            need_to_start_children = 0;
696
            start_children(first_feed);
697
        }
698

    
699
        /* now handle the events */
700
        for(c = first_http_ctx; c != NULL; c = c_next) {
701
            c_next = c->next;
702
            if (handle_connection(c) < 0) {
703
                /* close and free the connection */
704
                log_connection(c);
705
                close_connection(c);
706
            }
707
        }
708

    
709
        poll_entry = poll_table;
710
        if (server_fd) {
711
            /* new HTTP connection request ? */
712
            if (poll_entry->revents & POLLIN)
713
                new_connection(server_fd, 0);
714
            poll_entry++;
715
        }
716
        if (rtsp_server_fd) {
717
            /* new RTSP connection request ? */
718
            if (poll_entry->revents & POLLIN)
719
                new_connection(rtsp_server_fd, 1);
720
        }
721
    }
722
}
723

    
724
/* start waiting for a new HTTP/RTSP request */
725
static void start_wait_request(HTTPContext *c, int is_rtsp)
726
{
727
    c->buffer_ptr = c->buffer;
728
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
729

    
730
    if (is_rtsp) {
731
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
732
        c->state = RTSPSTATE_WAIT_REQUEST;
733
    } else {
734
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
735
        c->state = HTTPSTATE_WAIT_REQUEST;
736
    }
737
}
738

    
739
static void http_send_too_busy_reply(int fd)
740
{
741
    char buffer[300];
742
    int len = snprintf(buffer, sizeof(buffer),
743
                       "HTTP/1.0 200 Server too busy\r\n"
744
                       "Content-type: text/html\r\n"
745
                       "\r\n"
746
                       "<html><head><title>Too busy</title></head><body>\r\n"
747
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
748
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
749
                       "</body></html>\r\n",
750
                       nb_connections, nb_max_connections);
751
    send(fd, buffer, len, 0);
752
}
753

    
754

    
755
static void new_connection(int server_fd, int is_rtsp)
756
{
757
    struct sockaddr_in from_addr;
758
    int fd, len;
759
    HTTPContext *c = NULL;
760

    
761
    len = sizeof(from_addr);
762
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
763
                &len);
764
    if (fd < 0) {
765
        http_log("error during accept %s\n", strerror(errno));
766
        return;
767
    }
768
    ff_socket_nonblock(fd, 1);
769

    
770
    if (nb_connections >= nb_max_connections) {
771
        http_send_too_busy_reply(fd);
772
        goto fail;
773
    }
774

    
775
    /* add a new connection */
776
    c = av_mallocz(sizeof(HTTPContext));
777
    if (!c)
778
        goto fail;
779

    
780
    c->fd = fd;
781
    c->poll_entry = NULL;
782
    c->from_addr = from_addr;
783
    c->buffer_size = IOBUFFER_INIT_SIZE;
784
    c->buffer = av_malloc(c->buffer_size);
785
    if (!c->buffer)
786
        goto fail;
787

    
788
    c->next = first_http_ctx;
789
    first_http_ctx = c;
790
    nb_connections++;
791

    
792
    start_wait_request(c, is_rtsp);
793

    
794
    return;
795

    
796
 fail:
797
    if (c) {
798
        av_free(c->buffer);
799
        av_free(c);
800
    }
801
    closesocket(fd);
802
}
803

    
804
static void close_connection(HTTPContext *c)
805
{
806
    HTTPContext **cp, *c1;
807
    int i, nb_streams;
808
    AVFormatContext *ctx;
809
    URLContext *h;
810
    AVStream *st;
811

    
812
    /* remove connection from list */
813
    cp = &first_http_ctx;
814
    while ((*cp) != NULL) {
815
        c1 = *cp;
816
        if (c1 == c)
817
            *cp = c->next;
818
        else
819
            cp = &c1->next;
820
    }
821

    
822
    /* remove references, if any (XXX: do it faster) */
823
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
824
        if (c1->rtsp_c == c)
825
            c1->rtsp_c = NULL;
826
    }
827

    
828
    /* remove connection associated resources */
829
    if (c->fd >= 0)
830
        closesocket(c->fd);
831
    if (c->fmt_in) {
832
        /* close each frame parser */
833
        for(i=0;i<c->fmt_in->nb_streams;i++) {
834
            st = c->fmt_in->streams[i];
835
            if (st->codec->codec)
836
                avcodec_close(st->codec);
837
        }
838
        av_close_input_file(c->fmt_in);
839
    }
840

    
841
    /* free RTP output streams if any */
842
    nb_streams = 0;
843
    if (c->stream)
844
        nb_streams = c->stream->nb_streams;
845

    
846
    for(i=0;i<nb_streams;i++) {
847
        ctx = c->rtp_ctx[i];
848
        if (ctx) {
849
            av_write_trailer(ctx);
850
            av_metadata_free(&ctx->metadata);
851
            av_free(ctx->streams[0]);
852
            av_free(ctx);
853
        }
854
        h = c->rtp_handles[i];
855
        if (h)
856
            url_close(h);
857
    }
858

    
859
    ctx = &c->fmt_ctx;
860

    
861
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
862
        if (ctx->oformat) {
863
            /* prepare header */
864
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
865
                av_write_trailer(ctx);
866
                av_freep(&c->pb_buffer);
867
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
868
            }
869
        }
870
    }
871

    
872
    for(i=0; i<ctx->nb_streams; i++)
873
        av_free(ctx->streams[i]);
874

    
875
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
876
        current_bandwidth -= c->stream->bandwidth;
877

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

    
884
    av_freep(&c->pb_buffer);
885
    av_freep(&c->packet_buffer);
886
    av_free(c->buffer);
887
    av_free(c);
888
    nb_connections--;
889
}
890

    
891
static int handle_connection(HTTPContext *c)
892
{
893
    int len, ret;
894

    
895
    switch(c->state) {
896
    case HTTPSTATE_WAIT_REQUEST:
897
    case RTSPSTATE_WAIT_REQUEST:
898
        /* timeout ? */
899
        if ((c->timeout - cur_time) < 0)
900
            return -1;
901
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
902
            return -1;
903

    
904
        /* no need to read if no events */
905
        if (!(c->poll_entry->revents & POLLIN))
906
            return 0;
907
        /* read the data */
908
    read_loop:
909
        len = recv(c->fd, c->buffer_ptr, 1, 0);
910
        if (len < 0) {
911
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
912
                ff_neterrno() != FF_NETERROR(EINTR))
913
                return -1;
914
        } else if (len == 0) {
915
            return -1;
916
        } else {
917
            /* search for end of request. */
918
            uint8_t *ptr;
919
            c->buffer_ptr += len;
920
            ptr = c->buffer_ptr;
921
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
922
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
923
                /* request found : parse it and reply */
924
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
925
                    ret = http_parse_request(c);
926
                } else {
927
                    ret = rtsp_parse_request(c);
928
                }
929
                if (ret < 0)
930
                    return -1;
931
            } else if (ptr >= c->buffer_end) {
932
                /* request too long: cannot do anything */
933
                return -1;
934
            } else goto read_loop;
935
        }
936
        break;
937

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

    
942
        /* no need to write if no events */
943
        if (!(c->poll_entry->revents & POLLOUT))
944
            return 0;
945
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
946
        if (len < 0) {
947
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
948
                ff_neterrno() != FF_NETERROR(EINTR)) {
949
                /* error : close connection */
950
                av_freep(&c->pb_buffer);
951
                return -1;
952
            }
953
        } else {
954
            c->buffer_ptr += len;
955
            if (c->stream)
956
                c->stream->bytes_served += len;
957
            c->data_count += len;
958
            if (c->buffer_ptr >= c->buffer_end) {
959
                av_freep(&c->pb_buffer);
960
                /* if error, exit */
961
                if (c->http_error)
962
                    return -1;
963
                /* all the buffer was sent : synchronize to the incoming stream */
964
                c->state = HTTPSTATE_SEND_DATA_HEADER;
965
                c->buffer_ptr = c->buffer_end = c->buffer;
966
            }
967
        }
968
        break;
969

    
970
    case HTTPSTATE_SEND_DATA:
971
    case HTTPSTATE_SEND_DATA_HEADER:
972
    case HTTPSTATE_SEND_DATA_TRAILER:
973
        /* for packetized output, we consider we can always write (the
974
           input streams sets the speed). It may be better to verify
975
           that we do not rely too much on the kernel queues */
976
        if (!c->is_packetized) {
977
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
978
                return -1;
979

    
980
            /* no need to read if no events */
981
            if (!(c->poll_entry->revents & POLLOUT))
982
                return 0;
983
        }
984
        if (http_send_data(c) < 0)
985
            return -1;
986
        /* close connection if trailer sent */
987
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
988
            return -1;
989
        break;
990
    case HTTPSTATE_RECEIVE_DATA:
991
        /* no need to read if no events */
992
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
993
            return -1;
994
        if (!(c->poll_entry->revents & POLLIN))
995
            return 0;
996
        if (http_receive_data(c) < 0)
997
            return -1;
998
        break;
999
    case HTTPSTATE_WAIT_FEED:
1000
        /* no need to read if no events */
1001
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1002
            return -1;
1003

    
1004
        /* nothing to do, we'll be waken up by incoming feed packets */
1005
        break;
1006

    
1007
    case RTSPSTATE_SEND_REPLY:
1008
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1009
            av_freep(&c->pb_buffer);
1010
            return -1;
1011
        }
1012
        /* no need to write if no events */
1013
        if (!(c->poll_entry->revents & POLLOUT))
1014
            return 0;
1015
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1016
        if (len < 0) {
1017
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1018
                ff_neterrno() != FF_NETERROR(EINTR)) {
1019
                /* error : close connection */
1020
                av_freep(&c->pb_buffer);
1021
                return -1;
1022
            }
1023
        } else {
1024
            c->buffer_ptr += len;
1025
            c->data_count += len;
1026
            if (c->buffer_ptr >= c->buffer_end) {
1027
                /* all the buffer was sent : wait for a new request */
1028
                av_freep(&c->pb_buffer);
1029
                start_wait_request(c, 1);
1030
            }
1031
        }
1032
        break;
1033
    case RTSPSTATE_SEND_PACKET:
1034
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1035
            av_freep(&c->packet_buffer);
1036
            return -1;
1037
        }
1038
        /* no need to write if no events */
1039
        if (!(c->poll_entry->revents & POLLOUT))
1040
            return 0;
1041
        len = send(c->fd, c->packet_buffer_ptr,
1042
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1043
        if (len < 0) {
1044
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1045
                ff_neterrno() != FF_NETERROR(EINTR)) {
1046
                /* error : close connection */
1047
                av_freep(&c->packet_buffer);
1048
                return -1;
1049
            }
1050
        } else {
1051
            c->packet_buffer_ptr += len;
1052
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1053
                /* all the buffer was sent : wait for a new request */
1054
                av_freep(&c->packet_buffer);
1055
                c->state = RTSPSTATE_WAIT_REQUEST;
1056
            }
1057
        }
1058
        break;
1059
    case HTTPSTATE_READY:
1060
        /* nothing to do */
1061
        break;
1062
    default:
1063
        return -1;
1064
    }
1065
    return 0;
1066
}
1067

    
1068
static int extract_rates(char *rates, int ratelen, const char *request)
1069
{
1070
    const char *p;
1071

    
1072
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1073
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1074
            const char *q = p + 7;
1075

    
1076
            while (*q && *q != '\n' && isspace(*q))
1077
                q++;
1078

    
1079
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1080
                int stream_no;
1081
                int rate_no;
1082

    
1083
                q += 20;
1084

    
1085
                memset(rates, 0xff, ratelen);
1086

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

    
1091
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1092
                        break;
1093

    
1094
                    stream_no--;
1095
                    if (stream_no < ratelen && stream_no >= 0)
1096
                        rates[stream_no] = rate_no;
1097

    
1098
                    while (*q && *q != '\n' && !isspace(*q))
1099
                        q++;
1100
                }
1101

    
1102
                return 1;
1103
            }
1104
        }
1105
        p = strchr(p, '\n');
1106
        if (!p)
1107
            break;
1108

    
1109
        p++;
1110
    }
1111

    
1112
    return 0;
1113
}
1114

    
1115
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1116
{
1117
    int i;
1118
    int best_bitrate = 100000000;
1119
    int best = -1;
1120

    
1121
    for (i = 0; i < feed->nb_streams; i++) {
1122
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1123

    
1124
        if (feed_codec->codec_id != codec->codec_id ||
1125
            feed_codec->sample_rate != codec->sample_rate ||
1126
            feed_codec->width != codec->width ||
1127
            feed_codec->height != codec->height)
1128
            continue;
1129

    
1130
        /* Potential stream */
1131

    
1132
        /* We want the fastest stream less than bit_rate, or the slowest
1133
         * faster than bit_rate
1134
         */
1135

    
1136
        if (feed_codec->bit_rate <= bit_rate) {
1137
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1138
                best_bitrate = feed_codec->bit_rate;
1139
                best = i;
1140
            }
1141
        } else {
1142
            if (feed_codec->bit_rate < best_bitrate) {
1143
                best_bitrate = feed_codec->bit_rate;
1144
                best = i;
1145
            }
1146
        }
1147
    }
1148

    
1149
    return best;
1150
}
1151

    
1152
static int modify_current_stream(HTTPContext *c, char *rates)
1153
{
1154
    int i;
1155
    FFStream *req = c->stream;
1156
    int action_required = 0;
1157

    
1158
    /* Not much we can do for a feed */
1159
    if (!req->feed)
1160
        return 0;
1161

    
1162
    for (i = 0; i < req->nb_streams; i++) {
1163
        AVCodecContext *codec = req->streams[i]->codec;
1164

    
1165
        switch(rates[i]) {
1166
            case 0:
1167
                c->switch_feed_streams[i] = req->feed_streams[i];
1168
                break;
1169
            case 1:
1170
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1171
                break;
1172
            case 2:
1173
                /* Wants off or slow */
1174
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1175
#ifdef WANTS_OFF
1176
                /* This doesn't work well when it turns off the only stream! */
1177
                c->switch_feed_streams[i] = -2;
1178
                c->feed_streams[i] = -2;
1179
#endif
1180
                break;
1181
        }
1182

    
1183
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1184
            action_required = 1;
1185
    }
1186

    
1187
    return action_required;
1188
}
1189

    
1190

    
1191
static void do_switch_stream(HTTPContext *c, int i)
1192
{
1193
    if (c->switch_feed_streams[i] >= 0) {
1194
#ifdef PHILIP
1195
        c->feed_streams[i] = c->switch_feed_streams[i];
1196
#endif
1197

    
1198
        /* Now update the stream */
1199
    }
1200
    c->switch_feed_streams[i] = -1;
1201
}
1202

    
1203
/* XXX: factorize in utils.c ? */
1204
/* XXX: take care with different space meaning */
1205
static void skip_spaces(const char **pp)
1206
{
1207
    const char *p;
1208
    p = *pp;
1209
    while (*p == ' ' || *p == '\t')
1210
        p++;
1211
    *pp = p;
1212
}
1213

    
1214
static void get_word(char *buf, int buf_size, const char **pp)
1215
{
1216
    const char *p;
1217
    char *q;
1218

    
1219
    p = *pp;
1220
    skip_spaces(&p);
1221
    q = buf;
1222
    while (!isspace(*p) && *p != '\0') {
1223
        if ((q - buf) < buf_size - 1)
1224
            *q++ = *p;
1225
        p++;
1226
    }
1227
    if (buf_size > 0)
1228
        *q = '\0';
1229
    *pp = p;
1230
}
1231

    
1232
static void get_arg(char *buf, int buf_size, const char **pp)
1233
{
1234
    const char *p;
1235
    char *q;
1236
    int quote;
1237

    
1238
    p = *pp;
1239
    while (isspace(*p)) p++;
1240
    q = buf;
1241
    quote = 0;
1242
    if (*p == '\"' || *p == '\'')
1243
        quote = *p++;
1244
    for(;;) {
1245
        if (quote) {
1246
            if (*p == quote)
1247
                break;
1248
        } else {
1249
            if (isspace(*p))
1250
                break;
1251
        }
1252
        if (*p == '\0')
1253
            break;
1254
        if ((q - buf) < buf_size - 1)
1255
            *q++ = *p;
1256
        p++;
1257
    }
1258
    *q = '\0';
1259
    if (quote && *p == quote)
1260
        p++;
1261
    *pp = p;
1262
}
1263

    
1264
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1265
                         const char *p, const char *filename, int line_num)
1266
{
1267
    char arg[1024];
1268
    IPAddressACL acl;
1269
    int errors = 0;
1270

    
1271
    get_arg(arg, sizeof(arg), &p);
1272
    if (strcasecmp(arg, "allow") == 0)
1273
        acl.action = IP_ALLOW;
1274
    else if (strcasecmp(arg, "deny") == 0)
1275
        acl.action = IP_DENY;
1276
    else {
1277
        fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1278
                filename, line_num, arg);
1279
        errors++;
1280
    }
1281

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

    
1284
    if (resolve_host(&acl.first, arg) != 0) {
1285
        fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1286
                filename, line_num, arg);
1287
        errors++;
1288
    } else
1289
        acl.last = acl.first;
1290

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

    
1293
    if (arg[0]) {
1294
        if (resolve_host(&acl.last, arg) != 0) {
1295
            fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1296
                    filename, line_num, arg);
1297
            errors++;
1298
        }
1299
    }
1300

    
1301
    if (!errors) {
1302
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1303
        IPAddressACL **naclp = 0;
1304

    
1305
        acl.next = 0;
1306
        *nacl = acl;
1307

    
1308
        if (stream)
1309
            naclp = &stream->acl;
1310
        else if (feed)
1311
            naclp = &feed->acl;
1312
        else if (ext_acl)
1313
            naclp = &ext_acl;
1314
        else {
1315
            fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1316
                    filename, line_num);
1317
            errors++;
1318
        }
1319

    
1320
        if (naclp) {
1321
            while (*naclp)
1322
                naclp = &(*naclp)->next;
1323

    
1324
            *naclp = nacl;
1325
        }
1326
    }
1327
}
1328

    
1329

    
1330
static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1331
{
1332
    FILE* f;
1333
    char line[1024];
1334
    char  cmd[1024];
1335
    IPAddressACL *acl = NULL;
1336
    int line_num = 0;
1337
    const char *p;
1338

    
1339
    f = fopen(stream->dynamic_acl, "r");
1340
    if (!f) {
1341
        perror(stream->dynamic_acl);
1342
        return NULL;
1343
    }
1344

    
1345
    acl = av_mallocz(sizeof(IPAddressACL));
1346

    
1347
    /* Build ACL */
1348
    for(;;) {
1349
        if (fgets(line, sizeof(line), f) == NULL)
1350
            break;
1351
        line_num++;
1352
        p = line;
1353
        while (isspace(*p))
1354
            p++;
1355
        if (*p == '\0' || *p == '#')
1356
            continue;
1357
        get_arg(cmd, sizeof(cmd), &p);
1358

    
1359
        if (!strcasecmp(cmd, "ACL"))
1360
            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1361
    }
1362
    fclose(f);
1363
    return acl;
1364
}
1365

    
1366

    
1367
static void free_acl_list(IPAddressACL *in_acl)
1368
{
1369
    IPAddressACL *pacl,*pacl2;
1370

    
1371
    pacl = in_acl;
1372
    while(pacl) {
1373
        pacl2 = pacl;
1374
        pacl = pacl->next;
1375
        av_freep(pacl2);
1376
    }
1377
}
1378

    
1379
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1380
{
1381
    enum IPAddressAction last_action = IP_DENY;
1382
    IPAddressACL *acl;
1383
    struct in_addr *src = &c->from_addr.sin_addr;
1384
    unsigned long src_addr = src->s_addr;
1385

    
1386
    for (acl = in_acl; acl; acl = acl->next) {
1387
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1388
            return (acl->action == IP_ALLOW) ? 1 : 0;
1389
        last_action = acl->action;
1390
    }
1391

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

    
1396
static int validate_acl(FFStream *stream, HTTPContext *c)
1397
{
1398
    int ret = 0;
1399
    IPAddressACL *acl;
1400

    
1401

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

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

    
1408
        ret = validate_acl_list(acl, c);
1409

    
1410
        free_acl_list(acl);
1411
    }
1412

    
1413
    return ret;
1414
}
1415

    
1416
/* compute the real filename of a file by matching it without its
1417
   extensions to all the stream filenames */
1418
static void compute_real_filename(char *filename, int max_size)
1419
{
1420
    char file1[1024];
1421
    char file2[1024];
1422
    char *p;
1423
    FFStream *stream;
1424

    
1425
    /* compute filename by matching without the file extensions */
1426
    av_strlcpy(file1, filename, sizeof(file1));
1427
    p = strrchr(file1, '.');
1428
    if (p)
1429
        *p = '\0';
1430
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1431
        av_strlcpy(file2, stream->filename, sizeof(file2));
1432
        p = strrchr(file2, '.');
1433
        if (p)
1434
            *p = '\0';
1435
        if (!strcmp(file1, file2)) {
1436
            av_strlcpy(filename, stream->filename, max_size);
1437
            break;
1438
        }
1439
    }
1440
}
1441

    
1442
enum RedirType {
1443
    REDIR_NONE,
1444
    REDIR_ASX,
1445
    REDIR_RAM,
1446
    REDIR_ASF,
1447
    REDIR_RTSP,
1448
    REDIR_SDP,
1449
};
1450

    
1451
/* parse http request and prepare header */
1452
static int http_parse_request(HTTPContext *c)
1453
{
1454
    char *p;
1455
    enum RedirType redir_type;
1456
    char cmd[32];
1457
    char info[1024], filename[1024];
1458
    char url[1024], *q;
1459
    char protocol[32];
1460
    char msg[1024];
1461
    const char *mime_type;
1462
    FFStream *stream;
1463
    int i;
1464
    char ratebuf[32];
1465
    char *useragent = 0;
1466

    
1467
    p = c->buffer;
1468
    get_word(cmd, sizeof(cmd), (const char **)&p);
1469
    av_strlcpy(c->method, cmd, sizeof(c->method));
1470

    
1471
    if (!strcmp(cmd, "GET"))
1472
        c->post = 0;
1473
    else if (!strcmp(cmd, "POST"))
1474
        c->post = 1;
1475
    else
1476
        return -1;
1477

    
1478
    get_word(url, sizeof(url), (const char **)&p);
1479
    av_strlcpy(c->url, url, sizeof(c->url));
1480

    
1481
    get_word(protocol, sizeof(protocol), (const char **)&p);
1482
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1483
        return -1;
1484

    
1485
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1486

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

    
1490
    /* find the filename and the optional info string in the request */
1491
    p = strchr(url, '?');
1492
    if (p) {
1493
        av_strlcpy(info, p, sizeof(info));
1494
        *p = '\0';
1495
    } else
1496
        info[0] = '\0';
1497

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

    
1500
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1501
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1502
            useragent = p + 11;
1503
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1504
                useragent++;
1505
            break;
1506
        }
1507
        p = strchr(p, '\n');
1508
        if (!p)
1509
            break;
1510

    
1511
        p++;
1512
    }
1513

    
1514
    redir_type = REDIR_NONE;
1515
    if (av_match_ext(filename, "asx")) {
1516
        redir_type = REDIR_ASX;
1517
        filename[strlen(filename)-1] = 'f';
1518
    } else if (av_match_ext(filename, "asf") &&
1519
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1520
        /* if this isn't WMP or lookalike, return the redirector file */
1521
        redir_type = REDIR_ASF;
1522
    } else if (av_match_ext(filename, "rpm,ram")) {
1523
        redir_type = REDIR_RAM;
1524
        strcpy(filename + strlen(filename)-2, "m");
1525
    } else if (av_match_ext(filename, "rtsp")) {
1526
        redir_type = REDIR_RTSP;
1527
        compute_real_filename(filename, sizeof(filename) - 1);
1528
    } else if (av_match_ext(filename, "sdp")) {
1529
        redir_type = REDIR_SDP;
1530
        compute_real_filename(filename, sizeof(filename) - 1);
1531
    }
1532

    
1533
    // "redirect" / request to index.html
1534
    if (!strlen(filename))
1535
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1536

    
1537
    stream = first_stream;
1538
    while (stream != NULL) {
1539
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1540
            break;
1541
        stream = stream->next;
1542
    }
1543
    if (stream == NULL) {
1544
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1545
        http_log("File '%s' not found\n", url);
1546
        goto send_error;
1547
    }
1548

    
1549
    c->stream = stream;
1550
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1551
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1552

    
1553
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1554
        c->http_error = 301;
1555
        q = c->buffer;
1556
        q += snprintf(q, c->buffer_size,
1557
                      "HTTP/1.0 301 Moved\r\n"
1558
                      "Location: %s\r\n"
1559
                      "Content-type: text/html\r\n"
1560
                      "\r\n"
1561
                      "<html><head><title>Moved</title></head><body>\r\n"
1562
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1563
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1564
        /* prepare output buffer */
1565
        c->buffer_ptr = c->buffer;
1566
        c->buffer_end = q;
1567
        c->state = HTTPSTATE_SEND_HEADER;
1568
        return 0;
1569
    }
1570

    
1571
    /* If this is WMP, get the rate information */
1572
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1573
        if (modify_current_stream(c, ratebuf)) {
1574
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1575
                if (c->switch_feed_streams[i] >= 0)
1576
                    do_switch_stream(c, i);
1577
            }
1578
        }
1579
    }
1580

    
1581
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1582
        current_bandwidth += stream->bandwidth;
1583

    
1584
    /* If already streaming this feed, do not let start another feeder. */
1585
    if (stream->feed_opened) {
1586
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1587
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1588
        goto send_error;
1589
    }
1590

    
1591
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1592
        c->http_error = 200;
1593
        q = c->buffer;
1594
        q += snprintf(q, c->buffer_size,
1595
                      "HTTP/1.0 200 Server too busy\r\n"
1596
                      "Content-type: text/html\r\n"
1597
                      "\r\n"
1598
                      "<html><head><title>Too busy</title></head><body>\r\n"
1599
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1600
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1601
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1602
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1603
        /* prepare output buffer */
1604
        c->buffer_ptr = c->buffer;
1605
        c->buffer_end = q;
1606
        c->state = HTTPSTATE_SEND_HEADER;
1607
        return 0;
1608
    }
1609

    
1610
    if (redir_type != REDIR_NONE) {
1611
        char *hostinfo = 0;
1612

    
1613
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1614
            if (strncasecmp(p, "Host:", 5) == 0) {
1615
                hostinfo = p + 5;
1616
                break;
1617
            }
1618
            p = strchr(p, '\n');
1619
            if (!p)
1620
                break;
1621

    
1622
            p++;
1623
        }
1624

    
1625
        if (hostinfo) {
1626
            char *eoh;
1627
            char hostbuf[260];
1628

    
1629
            while (isspace(*hostinfo))
1630
                hostinfo++;
1631

    
1632
            eoh = strchr(hostinfo, '\n');
1633
            if (eoh) {
1634
                if (eoh[-1] == '\r')
1635
                    eoh--;
1636

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

    
1641
                    c->http_error = 200;
1642
                    q = c->buffer;
1643
                    switch(redir_type) {
1644
                    case REDIR_ASX:
1645
                        q += snprintf(q, c->buffer_size,
1646
                                      "HTTP/1.0 200 ASX Follows\r\n"
1647
                                      "Content-type: video/x-ms-asf\r\n"
1648
                                      "\r\n"
1649
                                      "<ASX Version=\"3\">\r\n"
1650
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1651
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1652
                                      "</ASX>\r\n", hostbuf, filename, info);
1653
                        break;
1654
                    case REDIR_RAM:
1655
                        q += snprintf(q, c->buffer_size,
1656
                                      "HTTP/1.0 200 RAM Follows\r\n"
1657
                                      "Content-type: audio/x-pn-realaudio\r\n"
1658
                                      "\r\n"
1659
                                      "# Autogenerated by ffserver\r\n"
1660
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1661
                        break;
1662
                    case REDIR_ASF:
1663
                        q += snprintf(q, c->buffer_size,
1664
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1665
                                      "Content-type: video/x-ms-asf\r\n"
1666
                                      "\r\n"
1667
                                      "[Reference]\r\n"
1668
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1669
                        break;
1670
                    case REDIR_RTSP:
1671
                        {
1672
                            char hostname[256], *p;
1673
                            /* extract only hostname */
1674
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1675
                            p = strrchr(hostname, ':');
1676
                            if (p)
1677
                                *p = '\0';
1678
                            q += snprintf(q, c->buffer_size,
1679
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1680
                                          /* XXX: incorrect mime type ? */
1681
                                          "Content-type: application/x-rtsp\r\n"
1682
                                          "\r\n"
1683
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1684
                        }
1685
                        break;
1686
                    case REDIR_SDP:
1687
                        {
1688
                            uint8_t *sdp_data;
1689
                            int sdp_data_size, len;
1690
                            struct sockaddr_in my_addr;
1691

    
1692
                            q += snprintf(q, c->buffer_size,
1693
                                          "HTTP/1.0 200 OK\r\n"
1694
                                          "Content-type: application/sdp\r\n"
1695
                                          "\r\n");
1696

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

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

    
1717
                    /* prepare output buffer */
1718
                    c->buffer_ptr = c->buffer;
1719
                    c->buffer_end = q;
1720
                    c->state = HTTPSTATE_SEND_HEADER;
1721
                    return 0;
1722
                }
1723
            }
1724
        }
1725

    
1726
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1727
        goto send_error;
1728
    }
1729

    
1730
    stream->conns_served++;
1731

    
1732
    /* XXX: add there authenticate and IP match */
1733

    
1734
    if (c->post) {
1735
        /* if post, it means a feed is being sent */
1736
        if (!stream->is_feed) {
1737
            /* However it might be a status report from WMP! Let us log the
1738
             * data as it might come in handy one day. */
1739
            char *logline = 0;
1740
            int client_id = 0;
1741

    
1742
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1743
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1744
                    logline = p;
1745
                    break;
1746
                }
1747
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1748
                    client_id = strtol(p + 18, 0, 10);
1749
                p = strchr(p, '\n');
1750
                if (!p)
1751
                    break;
1752

    
1753
                p++;
1754
            }
1755

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

    
1759
                logline += 17;
1760

    
1761
                if (eol) {
1762
                    if (eol[-1] == '\r')
1763
                        eol--;
1764
                    http_log("%.*s\n", (int) (eol - logline), logline);
1765
                    c->suppress_log = 1;
1766
                }
1767
            }
1768

    
1769
#ifdef DEBUG_WMP
1770
            http_log("\nGot request:\n%s\n", c->buffer);
1771
#endif
1772

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

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

    
1782
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1783
                    wmpc->switch_pending = 1;
1784
            }
1785

    
1786
            snprintf(msg, sizeof(msg), "POST command not handled");
1787
            c->stream = 0;
1788
            goto send_error;
1789
        }
1790
        if (http_start_receive_data(c) < 0) {
1791
            snprintf(msg, sizeof(msg), "could not open feed");
1792
            goto send_error;
1793
        }
1794
        c->http_error = 0;
1795
        c->state = HTTPSTATE_RECEIVE_DATA;
1796
        return 0;
1797
    }
1798

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

    
1804
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1805
        goto send_status;
1806

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

    
1813
    /* prepare http header */
1814
    q = c->buffer;
1815
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1816
    mime_type = c->stream->fmt->mime_type;
1817
    if (!mime_type)
1818
        mime_type = "application/x-octet-stream";
1819
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1820

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

    
1825
        c->wmp_client_id = av_lfg_get(&random_state);
1826

    
1827
        q += snprintf(q, q - (char *) 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);
1828
    }
1829
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1830
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1831

    
1832
    /* prepare output buffer */
1833
    c->http_error = 0;
1834
    c->buffer_ptr = c->buffer;
1835
    c->buffer_end = q;
1836
    c->state = HTTPSTATE_SEND_HEADER;
1837
    return 0;
1838
 send_error:
1839
    c->http_error = 404;
1840
    q = c->buffer;
1841
    q += snprintf(q, c->buffer_size,
1842
                  "HTTP/1.0 404 Not Found\r\n"
1843
                  "Content-type: text/html\r\n"
1844
                  "\r\n"
1845
                  "<html>\n"
1846
                  "<head><title>404 Not Found</title></head>\n"
1847
                  "<body>%s</body>\n"
1848
                  "</html>\n", msg);
1849
    /* prepare output buffer */
1850
    c->buffer_ptr = c->buffer;
1851
    c->buffer_end = q;
1852
    c->state = HTTPSTATE_SEND_HEADER;
1853
    return 0;
1854
 send_status:
1855
    compute_status(c);
1856
    c->http_error = 200; /* horrible : we use this value to avoid
1857
                            going to the send data state */
1858
    c->state = HTTPSTATE_SEND_HEADER;
1859
    return 0;
1860
}
1861

    
1862
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1863
{
1864
    static const char *suffix = " kMGTP";
1865
    const char *s;
1866

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

    
1869
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1870
}
1871

    
1872
static void compute_status(HTTPContext *c)
1873
{
1874
    HTTPContext *c1;
1875
    FFStream *stream;
1876
    char *p;
1877
    time_t ti;
1878
    int i, len;
1879
    ByteIOContext *pb;
1880

    
1881
    if (url_open_dyn_buf(&pb) < 0) {
1882
        /* XXX: return an error ? */
1883
        c->buffer_ptr = c->buffer;
1884
        c->buffer_end = c->buffer;
1885
        return;
1886
    }
1887

    
1888
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1889
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1890
    url_fprintf(pb, "Pragma: no-cache\r\n");
1891
    url_fprintf(pb, "\r\n");
1892

    
1893
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1894
    if (c->stream->feed_filename[0])
1895
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1896
    url_fprintf(pb, "</head>\n<body>");
1897
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1898
    /* format status */
1899
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1900
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1901
    url_fprintf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
1902
    stream = first_stream;
1903
    while (stream != NULL) {
1904
        char sfilename[1024];
1905
        char *eosf;
1906

    
1907
        if (stream->feed != stream) {
1908
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1909
            eosf = sfilename + strlen(sfilename);
1910
            if (eosf - sfilename >= 4) {
1911
                if (strcmp(eosf - 4, ".asf") == 0)
1912
                    strcpy(eosf - 4, ".asx");
1913
                else if (strcmp(eosf - 3, ".rm") == 0)
1914
                    strcpy(eosf - 3, ".ram");
1915
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1916
                    /* generate a sample RTSP director if
1917
                       unicast. Generate an SDP redirector if
1918
                       multicast */
1919
                    eosf = strrchr(sfilename, '.');
1920
                    if (!eosf)
1921
                        eosf = sfilename + strlen(sfilename);
1922
                    if (stream->is_multicast)
1923
                        strcpy(eosf, ".sdp");
1924
                    else
1925
                        strcpy(eosf, ".rtsp");
1926
                }
1927
            }
1928

    
1929
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1930
                         sfilename, stream->filename);
1931
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1932
                        stream->conns_served);
1933
            fmt_bytecount(pb, stream->bytes_served);
1934
            switch(stream->stream_type) {
1935
            case STREAM_TYPE_LIVE: {
1936
                    int audio_bit_rate = 0;
1937
                    int video_bit_rate = 0;
1938
                    const char *audio_codec_name = "";
1939
                    const char *video_codec_name = "";
1940
                    const char *audio_codec_name_extra = "";
1941
                    const char *video_codec_name_extra = "";
1942

    
1943
                    for(i=0;i<stream->nb_streams;i++) {
1944
                        AVStream *st = stream->streams[i];
1945
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1946
                        switch(st->codec->codec_type) {
1947
                        case AVMEDIA_TYPE_AUDIO:
1948
                            audio_bit_rate += st->codec->bit_rate;
1949
                            if (codec) {
1950
                                if (*audio_codec_name)
1951
                                    audio_codec_name_extra = "...";
1952
                                audio_codec_name = codec->name;
1953
                            }
1954
                            break;
1955
                        case AVMEDIA_TYPE_VIDEO:
1956
                            video_bit_rate += st->codec->bit_rate;
1957
                            if (codec) {
1958
                                if (*video_codec_name)
1959
                                    video_codec_name_extra = "...";
1960
                                video_codec_name = codec->name;
1961
                            }
1962
                            break;
1963
                        case AVMEDIA_TYPE_DATA:
1964
                            video_bit_rate += st->codec->bit_rate;
1965
                            break;
1966
                        default:
1967
                            abort();
1968
                        }
1969
                    }
1970
                    url_fprintf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
1971
                                 stream->fmt->name,
1972
                                 stream->bandwidth,
1973
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1974
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1975
                    if (stream->feed)
1976
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1977
                    else
1978
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1979
                    url_fprintf(pb, "\n");
1980
                }
1981
                break;
1982
            default:
1983
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1984
                break;
1985
            }
1986
        }
1987
        stream = stream->next;
1988
    }
1989
    url_fprintf(pb, "</table>\n");
1990

    
1991
    stream = first_stream;
1992
    while (stream != NULL) {
1993
        if (stream->feed == stream) {
1994
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1995
            if (stream->pid) {
1996
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1997

    
1998
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1999
                {
2000
                    FILE *pid_stat;
2001
                    char ps_cmd[64];
2002

    
2003
                    /* This is somewhat linux specific I guess */
2004
                    snprintf(ps_cmd, sizeof(ps_cmd),
2005
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2006
                             stream->pid);
2007

    
2008
                    pid_stat = popen(ps_cmd, "r");
2009
                    if (pid_stat) {
2010
                        char cpuperc[10];
2011
                        char cpuused[64];
2012

    
2013
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
2014
                                   cpuused) == 2) {
2015
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2016
                                         cpuperc, cpuused);
2017
                        }
2018
                        fclose(pid_stat);
2019
                    }
2020
                }
2021
#endif
2022

    
2023
                url_fprintf(pb, "<p>");
2024
            }
2025
            url_fprintf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
2026

    
2027
            for (i = 0; i < stream->nb_streams; i++) {
2028
                AVStream *st = stream->streams[i];
2029
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2030
                const char *type = "unknown";
2031
                char parameters[64];
2032

    
2033
                parameters[0] = 0;
2034

    
2035
                switch(st->codec->codec_type) {
2036
                case AVMEDIA_TYPE_AUDIO:
2037
                    type = "audio";
2038
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2039
                    break;
2040
                case AVMEDIA_TYPE_VIDEO:
2041
                    type = "video";
2042
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2043
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2044
                    break;
2045
                default:
2046
                    abort();
2047
                }
2048
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2049
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2050
            }
2051
            url_fprintf(pb, "</table>\n");
2052

    
2053
        }
2054
        stream = stream->next;
2055
    }
2056

    
2057
    /* connection status */
2058
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
2059

    
2060
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
2061
                 nb_connections, nb_max_connections);
2062

    
2063
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2064
                 current_bandwidth, max_bandwidth);
2065

    
2066
    url_fprintf(pb, "<table>\n");
2067
    url_fprintf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
2068
    c1 = first_http_ctx;
2069
    i = 0;
2070
    while (c1 != NULL) {
2071
        int bitrate;
2072
        int j;
2073

    
2074
        bitrate = 0;
2075
        if (c1->stream) {
2076
            for (j = 0; j < c1->stream->nb_streams; j++) {
2077
                if (!c1->stream->feed)
2078
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2079
                else if (c1->feed_streams[j] >= 0)
2080
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2081
            }
2082
        }
2083

    
2084
        i++;
2085
        p = inet_ntoa(c1->from_addr.sin_addr);
2086
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2087
                    i,
2088
                    c1->stream ? c1->stream->filename : "",
2089
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2090
                    p,
2091
                    c1->protocol,
2092
                    http_state[c1->state]);
2093
        fmt_bytecount(pb, bitrate);
2094
        url_fprintf(pb, "<td align=right>");
2095
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2096
        url_fprintf(pb, "<td align=right>");
2097
        fmt_bytecount(pb, c1->data_count);
2098
        url_fprintf(pb, "\n");
2099
        c1 = c1->next;
2100
    }
2101
    url_fprintf(pb, "</table>\n");
2102

    
2103
    /* date */
2104
    ti = time(NULL);
2105
    p = ctime(&ti);
2106
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
2107
    url_fprintf(pb, "</body>\n</html>\n");
2108

    
2109
    len = url_close_dyn_buf(pb, &c->pb_buffer);
2110
    c->buffer_ptr = c->pb_buffer;
2111
    c->buffer_end = c->pb_buffer + len;
2112
}
2113

    
2114
/* check if the parser needs to be opened for stream i */
2115
static void open_parser(AVFormatContext *s, int i)
2116
{
2117
    AVStream *st = s->streams[i];
2118
    AVCodec *codec;
2119

    
2120
    if (!st->codec->codec) {
2121
        codec = avcodec_find_decoder(st->codec->codec_id);
2122
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2123
            st->codec->parse_only = 1;
2124
            if (avcodec_open(st->codec, codec) < 0)
2125
                st->codec->parse_only = 0;
2126
        }
2127
    }
2128
}
2129

    
2130
static int open_input_stream(HTTPContext *c, const char *info)
2131
{
2132
    char buf[128];
2133
    char input_filename[1024];
2134
    AVFormatContext *s;
2135
    int buf_size, i, ret;
2136
    int64_t stream_pos;
2137

    
2138
    /* find file name */
2139
    if (c->stream->feed) {
2140
        strcpy(input_filename, c->stream->feed->feed_filename);
2141
        buf_size = FFM_PACKET_SIZE;
2142
        /* compute position (absolute time) */
2143
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
2144
            stream_pos = parse_date(buf, 0);
2145
            if (stream_pos == INT64_MIN)
2146
                return -1;
2147
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
2148
            int prebuffer = strtol(buf, 0, 10);
2149
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2150
        } else
2151
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2152
    } else {
2153
        strcpy(input_filename, c->stream->feed_filename);
2154
        buf_size = 0;
2155
        /* compute position (relative time) */
2156
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
2157
            stream_pos = parse_date(buf, 1);
2158
            if (stream_pos == INT64_MIN)
2159
                return -1;
2160
        } else
2161
            stream_pos = 0;
2162
    }
2163
    if (input_filename[0] == '\0')
2164
        return -1;
2165

    
2166
    /* open stream */
2167
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2168
                                  buf_size, c->stream->ap_in)) < 0) {
2169
        http_log("could not open %s: %d\n", input_filename, ret);
2170
        return -1;
2171
    }
2172
    s->flags |= AVFMT_FLAG_GENPTS;
2173
    c->fmt_in = s;
2174
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2175
        http_log("Could not find stream info '%s'\n", input_filename);
2176
        av_close_input_file(s);
2177
        return -1;
2178
    }
2179

    
2180
    /* open each parser */
2181
    for(i=0;i<s->nb_streams;i++)
2182
        open_parser(s, i);
2183

    
2184
    /* choose stream as clock source (we favorize video stream if
2185
       present) for packet sending */
2186
    c->pts_stream_index = 0;
2187
    for(i=0;i<c->stream->nb_streams;i++) {
2188
        if (c->pts_stream_index == 0 &&
2189
            c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2190
            c->pts_stream_index = i;
2191
        }
2192
    }
2193

    
2194
#if 1
2195
    if (c->fmt_in->iformat->read_seek)
2196
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2197
#endif
2198
    /* set the start time (needed for maxtime and RTP packet timing) */
2199
    c->start_time = cur_time;
2200
    c->first_pts = AV_NOPTS_VALUE;
2201
    return 0;
2202
}
2203

    
2204
/* return the server clock (in us) */
2205
static int64_t get_server_clock(HTTPContext *c)
2206
{
2207
    /* compute current pts value from system time */
2208
    return (cur_time - c->start_time) * 1000;
2209
}
2210

    
2211
/* return the estimated time at which the current packet must be sent
2212
   (in us) */
2213
static int64_t get_packet_send_clock(HTTPContext *c)
2214
{
2215
    int bytes_left, bytes_sent, frame_bytes;
2216

    
2217
    frame_bytes = c->cur_frame_bytes;
2218
    if (frame_bytes <= 0)
2219
        return c->cur_pts;
2220
    else {
2221
        bytes_left = c->buffer_end - c->buffer_ptr;
2222
        bytes_sent = frame_bytes - bytes_left;
2223
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2224
    }
2225
}
2226

    
2227

    
2228
static int http_prepare_data(HTTPContext *c)
2229
{
2230
    int i, len, ret;
2231
    AVFormatContext *ctx;
2232

    
2233
    av_freep(&c->pb_buffer);
2234
    switch(c->state) {
2235
    case HTTPSTATE_SEND_DATA_HEADER:
2236
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2237
        av_metadata_set2(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2238
        av_metadata_set2(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2239
        av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2240
        av_metadata_set2(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
2241

    
2242
        for(i=0;i<c->stream->nb_streams;i++) {
2243
            AVStream *st;
2244
            AVStream *src;
2245
            st = av_mallocz(sizeof(AVStream));
2246
            c->fmt_ctx.streams[i] = st;
2247
            /* if file or feed, then just take streams from FFStream struct */
2248
            if (!c->stream->feed ||
2249
                c->stream->feed == c->stream)
2250
                src = c->stream->streams[i];
2251
            else
2252
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2253

    
2254
            *st = *src;
2255
            st->priv_data = 0;
2256
            st->codec->frame_number = 0; /* XXX: should be done in
2257
                                           AVStream, not in codec */
2258
        }
2259
        /* set output format parameters */
2260
        c->fmt_ctx.oformat = c->stream->fmt;
2261
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2262

    
2263
        c->got_key_frame = 0;
2264

    
2265
        /* prepare header and save header data in a stream */
2266
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2267
            /* XXX: potential leak */
2268
            return -1;
2269
        }
2270
        c->fmt_ctx.pb->is_streamed = 1;
2271

    
2272
        /*
2273
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2274
         * Default value from FFmpeg
2275
         * Try to set it use configuration option
2276
         */
2277
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2278
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2279

    
2280
        av_set_parameters(&c->fmt_ctx, NULL);
2281
        if (av_write_header(&c->fmt_ctx) < 0) {
2282
            http_log("Error writing output header\n");
2283
            return -1;
2284
        }
2285
        av_metadata_free(&c->fmt_ctx.metadata);
2286

    
2287
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2288
        c->buffer_ptr = c->pb_buffer;
2289
        c->buffer_end = c->pb_buffer + len;
2290

    
2291
        c->state = HTTPSTATE_SEND_DATA;
2292
        c->last_packet_sent = 0;
2293
        break;
2294
    case HTTPSTATE_SEND_DATA:
2295
        /* find a new packet */
2296
        /* read a packet from the input stream */
2297
        if (c->stream->feed)
2298
            ffm_set_write_index(c->fmt_in,
2299
                                c->stream->feed->feed_write_index,
2300
                                c->stream->feed->feed_size);
2301

    
2302
        if (c->stream->max_time &&
2303
            c->stream->max_time + c->start_time - cur_time < 0)
2304
            /* We have timed out */
2305
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2306
        else {
2307
            AVPacket pkt;
2308
        redo:
2309
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2310
                if (c->stream->feed && c->stream->feed->feed_opened) {
2311
                    /* if coming from feed, it means we reached the end of the
2312
                       ffm file, so must wait for more data */
2313
                    c->state = HTTPSTATE_WAIT_FEED;
2314
                    return 1; /* state changed */
2315
                } else {
2316
                    if (c->stream->loop) {
2317
                        av_close_input_file(c->fmt_in);
2318
                        c->fmt_in = NULL;
2319
                        if (open_input_stream(c, "") < 0)
2320
                            goto no_loop;
2321
                        goto redo;
2322
                    } else {
2323
                    no_loop:
2324
                        /* must send trailer now because eof or error */
2325
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2326
                    }
2327
                }
2328
            } else {
2329
                int source_index = pkt.stream_index;
2330
                /* update first pts if needed */
2331
                if (c->first_pts == AV_NOPTS_VALUE) {
2332
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2333
                    c->start_time = cur_time;
2334
                }
2335
                /* send it to the appropriate stream */
2336
                if (c->stream->feed) {
2337
                    /* if coming from a feed, select the right stream */
2338
                    if (c->switch_pending) {
2339
                        c->switch_pending = 0;
2340
                        for(i=0;i<c->stream->nb_streams;i++) {
2341
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2342
                                if (pkt.flags & AV_PKT_FLAG_KEY)
2343
                                    do_switch_stream(c, i);
2344
                            if (c->switch_feed_streams[i] >= 0)
2345
                                c->switch_pending = 1;
2346
                        }
2347
                    }
2348
                    for(i=0;i<c->stream->nb_streams;i++) {
2349
                        if (c->stream->feed_streams[i] == pkt.stream_index) {
2350
                            AVStream *st = c->fmt_in->streams[source_index];
2351
                            pkt.stream_index = i;
2352
                            if (pkt.flags & AV_PKT_FLAG_KEY &&
2353
                                (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2354
                                 c->stream->nb_streams == 1))
2355
                                c->got_key_frame = 1;
2356
                            if (!c->stream->send_on_key || c->got_key_frame)
2357
                                goto send_it;
2358
                        }
2359
                    }
2360
                } else {
2361
                    AVCodecContext *codec;
2362
                    AVStream *ist, *ost;
2363
                send_it:
2364
                    ist = c->fmt_in->streams[source_index];
2365
                    /* specific handling for RTP: we use several
2366
                       output stream (one for each RTP
2367
                       connection). XXX: need more abstract handling */
2368
                    if (c->is_packetized) {
2369
                        /* compute send time and duration */
2370
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2371
                        if (ist->start_time != AV_NOPTS_VALUE)
2372
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2373
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2374
                        /* find RTP context */
2375
                        c->packet_stream_index = pkt.stream_index;
2376
                        ctx = c->rtp_ctx[c->packet_stream_index];
2377
                        if(!ctx) {
2378
                            av_free_packet(&pkt);
2379
                            break;
2380
                        }
2381
                        codec = ctx->streams[0]->codec;
2382
                        /* only one stream per RTP connection */
2383
                        pkt.stream_index = 0;
2384
                    } else {
2385
                        ctx = &c->fmt_ctx;
2386
                        /* Fudge here */
2387
                        codec = ctx->streams[pkt.stream_index]->codec;
2388
                    }
2389

    
2390
                    if (c->is_packetized) {
2391
                        int max_packet_size;
2392
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2393
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2394
                        else
2395
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2396
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2397
                    } else {
2398
                        ret = url_open_dyn_buf(&ctx->pb);
2399
                    }
2400
                    if (ret < 0) {
2401
                        /* XXX: potential leak */
2402
                        return -1;
2403
                    }
2404
                    ost = ctx->streams[pkt.stream_index];
2405

    
2406
                    ctx->pb->is_streamed = 1;
2407
                    if (pkt.dts != AV_NOPTS_VALUE)
2408
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2409
                    if (pkt.pts != AV_NOPTS_VALUE)
2410
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2411
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2412
                    if (av_write_frame(ctx, &pkt) < 0) {
2413
                        http_log("Error writing frame to output\n");
2414
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2415
                    }
2416

    
2417
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2418
                    c->cur_frame_bytes = len;
2419
                    c->buffer_ptr = c->pb_buffer;
2420
                    c->buffer_end = c->pb_buffer + len;
2421

    
2422
                    codec->frame_number++;
2423
                    if (len == 0) {
2424
                        av_free_packet(&pkt);
2425
                        goto redo;
2426
                    }
2427
                }
2428
                av_free_packet(&pkt);
2429
            }
2430
        }
2431
        break;
2432
    default:
2433
    case HTTPSTATE_SEND_DATA_TRAILER:
2434
        /* last packet test ? */
2435
        if (c->last_packet_sent || c->is_packetized)
2436
            return -1;
2437
        ctx = &c->fmt_ctx;
2438
        /* prepare header */
2439
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2440
            /* XXX: potential leak */
2441
            return -1;
2442
        }
2443
        c->fmt_ctx.pb->is_streamed = 1;
2444
        av_write_trailer(ctx);
2445
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2446
        c->buffer_ptr = c->pb_buffer;
2447
        c->buffer_end = c->pb_buffer + len;
2448

    
2449
        c->last_packet_sent = 1;
2450
        break;
2451
    }
2452
    return 0;
2453
}
2454

    
2455
/* should convert the format at the same time */
2456
/* send data starting at c->buffer_ptr to the output connection
2457
   (either UDP or TCP connection) */
2458
static int http_send_data(HTTPContext *c)
2459
{
2460
    int len, ret;
2461

    
2462
    for(;;) {
2463
        if (c->buffer_ptr >= c->buffer_end) {
2464
            ret = http_prepare_data(c);
2465
            if (ret < 0)
2466
                return -1;
2467
            else if (ret != 0)
2468
                /* state change requested */
2469
                break;
2470
        } else {
2471
            if (c->is_packetized) {
2472
                /* RTP data output */
2473
                len = c->buffer_end - c->buffer_ptr;
2474
                if (len < 4) {
2475
                    /* fail safe - should never happen */
2476
                fail1:
2477
                    c->buffer_ptr = c->buffer_end;
2478
                    return 0;
2479
                }
2480
                len = (c->buffer_ptr[0] << 24) |
2481
                    (c->buffer_ptr[1] << 16) |
2482
                    (c->buffer_ptr[2] << 8) |
2483
                    (c->buffer_ptr[3]);
2484
                if (len > (c->buffer_end - c->buffer_ptr))
2485
                    goto fail1;
2486
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2487
                    /* nothing to send yet: we can wait */
2488
                    return 0;
2489
                }
2490

    
2491
                c->data_count += len;
2492
                update_datarate(&c->datarate, c->data_count);
2493
                if (c->stream)
2494
                    c->stream->bytes_served += len;
2495

    
2496
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2497
                    /* RTP packets are sent inside the RTSP TCP connection */
2498
                    ByteIOContext *pb;
2499
                    int interleaved_index, size;
2500
                    uint8_t header[4];
2501
                    HTTPContext *rtsp_c;
2502

    
2503
                    rtsp_c = c->rtsp_c;
2504
                    /* if no RTSP connection left, error */
2505
                    if (!rtsp_c)
2506
                        return -1;
2507
                    /* if already sending something, then wait. */
2508
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2509
                        break;
2510
                    if (url_open_dyn_buf(&pb) < 0)
2511
                        goto fail1;
2512
                    interleaved_index = c->packet_stream_index * 2;
2513
                    /* RTCP packets are sent at odd indexes */
2514
                    if (c->buffer_ptr[1] == 200)
2515
                        interleaved_index++;
2516
                    /* write RTSP TCP header */
2517
                    header[0] = '$';
2518
                    header[1] = interleaved_index;
2519
                    header[2] = len >> 8;
2520
                    header[3] = len;
2521
                    put_buffer(pb, header, 4);
2522
                    /* write RTP packet data */
2523
                    c->buffer_ptr += 4;
2524
                    put_buffer(pb, c->buffer_ptr, len);
2525
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2526
                    /* prepare asynchronous TCP sending */
2527
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2528
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2529
                    c->buffer_ptr += len;
2530

    
2531
                    /* send everything we can NOW */
2532
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2533
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2534
                    if (len > 0)
2535
                        rtsp_c->packet_buffer_ptr += len;
2536
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2537
                        /* if we could not send all the data, we will
2538
                           send it later, so a new state is needed to
2539
                           "lock" the RTSP TCP connection */
2540
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2541
                        break;
2542
                    } else
2543
                        /* all data has been sent */
2544
                        av_freep(&c->packet_buffer);
2545
                } else {
2546
                    /* send RTP packet directly in UDP */
2547
                    c->buffer_ptr += 4;
2548
                    url_write(c->rtp_handles[c->packet_stream_index],
2549
                              c->buffer_ptr, len);
2550
                    c->buffer_ptr += len;
2551
                    /* here we continue as we can send several packets per 10 ms slot */
2552
                }
2553
            } else {
2554
                /* TCP data output */
2555
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2556
                if (len < 0) {
2557
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2558
                        ff_neterrno() != FF_NETERROR(EINTR))
2559
                        /* error : close connection */
2560
                        return -1;
2561
                    else
2562
                        return 0;
2563
                } else
2564
                    c->buffer_ptr += len;
2565

    
2566
                c->data_count += len;
2567
                update_datarate(&c->datarate, c->data_count);
2568
                if (c->stream)
2569
                    c->stream->bytes_served += len;
2570
                break;
2571
            }
2572
        }
2573
    } /* for(;;) */
2574
    return 0;
2575
}
2576

    
2577
static int http_start_receive_data(HTTPContext *c)
2578
{
2579
    int fd;
2580

    
2581
    if (c->stream->feed_opened)
2582
        return -1;
2583

    
2584
    /* Don't permit writing to this one */
2585
    if (c->stream->readonly)
2586
        return -1;
2587

    
2588
    /* open feed */
2589
    fd = open(c->stream->feed_filename, O_RDWR);
2590
    if (fd < 0) {
2591
        http_log("Error opening feeder file: %s\n", strerror(errno));
2592
        return -1;
2593
    }
2594
    c->feed_fd = fd;
2595

    
2596
    if (c->stream->truncate) {
2597
        /* truncate feed file */
2598
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2599
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2600
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2601
    } else {
2602
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2603
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2604
            return -1;
2605
        }
2606
    }
2607

    
2608
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2609
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2610
    lseek(fd, 0, SEEK_SET);
2611

    
2612
    /* init buffer input */
2613
    c->buffer_ptr = c->buffer;
2614
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2615
    c->stream->feed_opened = 1;
2616
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2617
    return 0;
2618
}
2619

    
2620
static int http_receive_data(HTTPContext *c)
2621
{
2622
    HTTPContext *c1;
2623
    int len, loop_run = 0;
2624

    
2625
    while (c->chunked_encoding && !c->chunk_size &&
2626
           c->buffer_end > c->buffer_ptr) {
2627
        /* read chunk header, if present */
2628
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2629

    
2630
        if (len < 0) {
2631
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2632
                ff_neterrno() != FF_NETERROR(EINTR))
2633
                /* error : close connection */
2634
                goto fail;
2635
            return 0;
2636
        } else if (len == 0) {
2637
            /* end of connection : close it */
2638
            goto fail;
2639
        } else if (c->buffer_ptr - c->buffer >= 2 &&
2640
                   !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2641
            c->chunk_size = strtol(c->buffer, 0, 16);
2642
            if (c->chunk_size == 0) // end of stream
2643
                goto fail;
2644
            c->buffer_ptr = c->buffer;
2645
            break;
2646
        } else if (++loop_run > 10) {
2647
            /* no chunk header, abort */
2648
            goto fail;
2649
        } else {
2650
            c->buffer_ptr++;
2651
        }
2652
    }
2653

    
2654
    if (c->buffer_end > c->buffer_ptr) {
2655
        len = recv(c->fd, c->buffer_ptr,
2656
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2657
        if (len < 0) {
2658
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2659
                ff_neterrno() != FF_NETERROR(EINTR))
2660
                /* error : close connection */
2661
                goto fail;
2662
        } else if (len == 0)
2663
            /* end of connection : close it */
2664
            goto fail;
2665
        else {
2666
            c->chunk_size -= len;
2667
            c->buffer_ptr += len;
2668
            c->data_count += len;
2669
            update_datarate(&c->datarate, c->data_count);
2670
        }
2671
    }
2672

    
2673
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2674
        if (c->buffer[0] != 'f' ||
2675
            c->buffer[1] != 'm') {
2676
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2677
            goto fail;
2678
        }
2679
    }
2680

    
2681
    if (c->buffer_ptr >= c->buffer_end) {
2682
        FFStream *feed = c->stream;
2683
        /* a packet has been received : write it in the store, except
2684
           if header */
2685
        if (c->data_count > FFM_PACKET_SIZE) {
2686

    
2687
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2688
            /* XXX: use llseek or url_seek */
2689
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2690
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2691
                http_log("Error writing to feed file: %s\n", strerror(errno));
2692
                goto fail;
2693
            }
2694

    
2695
            feed->feed_write_index += FFM_PACKET_SIZE;
2696
            /* update file size */
2697
            if (feed->feed_write_index > c->stream->feed_size)
2698
                feed->feed_size = feed->feed_write_index;
2699

    
2700
            /* handle wrap around if max file size reached */
2701
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2702
                feed->feed_write_index = FFM_PACKET_SIZE;
2703

    
2704
            /* write index */
2705
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2706
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2707
                goto fail;
2708
            }
2709

    
2710
            /* wake up any waiting connections */
2711
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2712
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2713
                    c1->stream->feed == c->stream->feed)
2714
                    c1->state = HTTPSTATE_SEND_DATA;
2715
            }
2716
        } else {
2717
            /* We have a header in our hands that contains useful data */
2718
            AVFormatContext *s = NULL;
2719
            ByteIOContext *pb;
2720
            AVInputFormat *fmt_in;
2721
            int i;
2722

    
2723
            /* use feed output format name to find corresponding input format */
2724
            fmt_in = av_find_input_format(feed->fmt->name);
2725
            if (!fmt_in)
2726
                goto fail;
2727

    
2728
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2729
            pb->is_streamed = 1;
2730

    
2731
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2732
                av_free(pb);
2733
                goto fail;
2734
            }
2735

    
2736
            /* Now we have the actual streams */
2737
            if (s->nb_streams != feed->nb_streams) {
2738
                av_close_input_stream(s);
2739
                av_free(pb);
2740
                http_log("Feed '%s' stream number does not match registered feed\n",
2741
                         c->stream->feed_filename);
2742
                goto fail;
2743
            }
2744

    
2745
            for (i = 0; i < s->nb_streams; i++) {
2746
                AVStream *fst = feed->streams[i];
2747
                AVStream *st = s->streams[i];
2748
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2749
                if (fst->codec->extradata_size) {
2750
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2751
                    if (!fst->codec->extradata)
2752
                        goto fail;
2753
                    memcpy(fst->codec->extradata, st->codec->extradata,
2754
                           fst->codec->extradata_size);
2755
                }
2756
            }
2757

    
2758
            av_close_input_stream(s);
2759
            av_free(pb);
2760
        }
2761
        c->buffer_ptr = c->buffer;
2762
    }
2763

    
2764
    return 0;
2765
 fail:
2766
    c->stream->feed_opened = 0;
2767
    close(c->feed_fd);
2768
    /* wake up any waiting connections to stop waiting for feed */
2769
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2770
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2771
            c1->stream->feed == c->stream->feed)
2772
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2773
    }
2774
    return -1;
2775
}
2776

    
2777
/********************************************************************/
2778
/* RTSP handling */
2779

    
2780
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2781
{
2782
    const char *str;
2783
    time_t ti;
2784
    struct tm *tm;
2785
    char buf2[32];
2786

    
2787
    switch(error_number) {
2788
    case RTSP_STATUS_OK:
2789
        str = "OK";
2790
        break;
2791
    case RTSP_STATUS_METHOD:
2792
        str = "Method Not Allowed";
2793
        break;
2794
    case RTSP_STATUS_BANDWIDTH:
2795
        str = "Not Enough Bandwidth";
2796
        break;
2797
    case RTSP_STATUS_SESSION:
2798
        str = "Session Not Found";
2799
        break;
2800
    case RTSP_STATUS_STATE:
2801
        str = "Method Not Valid in This State";
2802
        break;
2803
    case RTSP_STATUS_AGGREGATE:
2804
        str = "Aggregate operation not allowed";
2805
        break;
2806
    case RTSP_STATUS_ONLY_AGGREGATE:
2807
        str = "Only aggregate operation allowed";
2808
        break;
2809
    case RTSP_STATUS_TRANSPORT:
2810
        str = "Unsupported transport";
2811
        break;
2812
    case RTSP_STATUS_INTERNAL:
2813
        str = "Internal Server Error";
2814
        break;
2815
    case RTSP_STATUS_SERVICE:
2816
        str = "Service Unavailable";
2817
        break;
2818
    case RTSP_STATUS_VERSION:
2819
        str = "RTSP Version not supported";
2820
        break;
2821
    default:
2822
        str = "Unknown Error";
2823
        break;
2824
    }
2825

    
2826
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2827
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2828

    
2829
    /* output GMT time */
2830
    ti = time(NULL);
2831
    tm = gmtime(&ti);
2832
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2833
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2834
}
2835

    
2836
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2837
{
2838
    rtsp_reply_header(c, error_number);
2839
    url_fprintf(c->pb, "\r\n");
2840
}
2841

    
2842
static int rtsp_parse_request(HTTPContext *c)
2843
{
2844
    const char *p, *p1, *p2;
2845
    char cmd[32];
2846
    char url[1024];
2847
    char protocol[32];
2848
    char line[1024];
2849
    int len;
2850
    RTSPMessageHeader header1, *header = &header1;
2851

    
2852
    c->buffer_ptr[0] = '\0';
2853
    p = c->buffer;
2854

    
2855
    get_word(cmd, sizeof(cmd), &p);
2856
    get_word(url, sizeof(url), &p);
2857
    get_word(protocol, sizeof(protocol), &p);
2858

    
2859
    av_strlcpy(c->method, cmd, sizeof(c->method));
2860
    av_strlcpy(c->url, url, sizeof(c->url));
2861
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2862

    
2863
    if (url_open_dyn_buf(&c->pb) < 0) {
2864
        /* XXX: cannot do more */
2865
        c->pb = NULL; /* safety */
2866
        return -1;
2867
    }
2868

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

    
2875
    /* parse each header line */
2876
    memset(header, 0, sizeof(*header));
2877
    /* skip to next line */
2878
    while (*p != '\n' && *p != '\0')
2879
        p++;
2880
    if (*p == '\n')
2881
        p++;
2882
    while (*p != '\0') {
2883
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2884
        if (!p1)
2885
            break;
2886
        p2 = p1;
2887
        if (p2 > p && p2[-1] == '\r')
2888
            p2--;
2889
        /* skip empty line */
2890
        if (p2 == p)
2891
            break;
2892
        len = p2 - p;
2893
        if (len > sizeof(line) - 1)
2894
            len = sizeof(line) - 1;
2895
        memcpy(line, p, len);
2896
        line[len] = '\0';
2897
        ff_rtsp_parse_line(header, line, NULL);
2898
        p = p1 + 1;
2899
    }
2900

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

    
2904
    if (!strcmp(cmd, "DESCRIBE"))
2905
        rtsp_cmd_describe(c, url);
2906
    else if (!strcmp(cmd, "OPTIONS"))
2907
        rtsp_cmd_options(c, url);
2908
    else if (!strcmp(cmd, "SETUP"))
2909
        rtsp_cmd_setup(c, url, header);
2910
    else if (!strcmp(cmd, "PLAY"))
2911
        rtsp_cmd_play(c, url, header);
2912
    else if (!strcmp(cmd, "PAUSE"))
2913
        rtsp_cmd_pause(c, url, header);
2914
    else if (!strcmp(cmd, "TEARDOWN"))
2915
        rtsp_cmd_teardown(c, url, header);
2916
    else
2917
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2918

    
2919
 the_end:
2920
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2921
    c->pb = NULL; /* safety */
2922
    if (len < 0) {
2923
        /* XXX: cannot do more */
2924
        return -1;
2925
    }
2926
    c->buffer_ptr = c->pb_buffer;
2927
    c->buffer_end = c->pb_buffer + len;
2928
    c->state = RTSPSTATE_SEND_REPLY;
2929
    return 0;
2930
}
2931

    
2932
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2933
                                   struct in_addr my_ip)
2934
{
2935
    AVFormatContext *avc;
2936
    AVStream avs[MAX_STREAMS];
2937
    int i;
2938

    
2939
    avc =  avformat_alloc_context();
2940
    if (avc == NULL) {
2941
        return -1;
2942
    }
2943
    av_metadata_set2(&avc->metadata, "title",
2944
                     stream->title[0] ? stream->title : "No Title", 0);
2945
    avc->nb_streams = stream->nb_streams;
2946
    if (stream->is_multicast) {
2947
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2948
                 inet_ntoa(stream->multicast_ip),
2949
                 stream->multicast_port, stream->multicast_ttl);
2950
    } else {
2951
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2952
    }
2953

    
2954
    for(i = 0; i < stream->nb_streams; i++) {
2955
        avc->streams[i] = &avs[i];
2956
        avc->streams[i]->codec = stream->streams[i]->codec;
2957
    }
2958
    *pbuffer = av_mallocz(2048);
2959
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2960
    av_metadata_free(&avc->metadata);
2961
    av_free(avc);
2962

    
2963
    return strlen(*pbuffer);
2964
}
2965

    
2966
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2967
{
2968
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2969
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2970
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2971
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2972
    url_fprintf(c->pb, "\r\n");
2973
}
2974

    
2975
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2976
{
2977
    FFStream *stream;
2978
    char path1[1024];
2979
    const char *path;
2980
    uint8_t *content;
2981
    int content_length, len;
2982
    struct sockaddr_in my_addr;
2983

    
2984
    /* find which url is asked */
2985
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2986
    path = path1;
2987
    if (*path == '/')
2988
        path++;
2989

    
2990
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2991
        if (!stream->is_feed &&
2992
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2993
            !strcmp(path, stream->filename)) {
2994
            goto found;
2995
        }
2996
    }
2997
    /* no stream found */
2998
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2999
    return;
3000

    
3001
 found:
3002
    /* prepare the media description in sdp format */
3003

    
3004
    /* get the host IP */
3005
    len = sizeof(my_addr);
3006
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3007
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3008
    if (content_length < 0) {
3009
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3010
        return;
3011
    }
3012
    rtsp_reply_header(c, RTSP_STATUS_OK);
3013
    url_fprintf(c->pb, "Content-Base: %s/\r\n", url);
3014
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
3015
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
3016
    url_fprintf(c->pb, "\r\n");
3017
    put_buffer(c->pb, content, content_length);
3018
    av_free(content);
3019
}
3020

    
3021
static HTTPContext *find_rtp_session(const char *session_id)
3022
{
3023
    HTTPContext *c;
3024

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

    
3028
    for(c = first_http_ctx; c != NULL; c = c->next) {
3029
        if (!strcmp(c->session_id, session_id))
3030
            return c;
3031
    }
3032
    return NULL;
3033
}
3034

    
3035
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3036
{
3037
    RTSPTransportField *th;
3038
    int i;
3039

    
3040
    for(i=0;i<h->nb_transports;i++) {
3041
        th = &h->transports[i];
3042
        if (th->lower_transport == lower_transport)
3043
            return th;
3044
    }
3045
    return NULL;
3046
}
3047

    
3048
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3049
                           RTSPMessageHeader *h)
3050
{
3051
    FFStream *stream;
3052
    int stream_index, rtp_port, rtcp_port;
3053
    char buf[1024];
3054
    char path1[1024];
3055
    const char *path;
3056
    HTTPContext *rtp_c;
3057
    RTSPTransportField *th;
3058
    struct sockaddr_in dest_addr;
3059
    RTSPActionServerSetup setup;
3060

    
3061
    /* find which url is asked */
3062
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3063
    path = path1;
3064
    if (*path == '/')
3065
        path++;
3066

    
3067
    /* now check each stream */
3068
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3069
        if (!stream->is_feed &&
3070
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3071
            /* accept aggregate filenames only if single stream */
3072
            if (!strcmp(path, stream->filename)) {
3073
                if (stream->nb_streams != 1) {
3074
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3075
                    return;
3076
                }
3077
                stream_index = 0;
3078
                goto found;
3079
            }
3080

    
3081
            for(stream_index = 0; stream_index < stream->nb_streams;
3082
                stream_index++) {
3083
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
3084
                         stream->filename, stream_index);
3085
                if (!strcmp(path, buf))
3086
                    goto found;
3087
            }
3088
        }
3089
    }
3090
    /* no stream found */
3091
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3092
    return;
3093
 found:
3094

    
3095
    /* generate session id if needed */
3096
    if (h->session_id[0] == '\0')
3097
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3098
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3099

    
3100
    /* find rtp session, and create it if none found */
3101
    rtp_c = find_rtp_session(h->session_id);
3102
    if (!rtp_c) {
3103
        /* always prefer UDP */
3104
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3105
        if (!th) {
3106
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3107
            if (!th) {
3108
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3109
                return;
3110
            }
3111
        }
3112

    
3113
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3114
                                   th->lower_transport);
3115
        if (!rtp_c) {
3116
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3117
            return;
3118
        }
3119

    
3120
        /* open input stream */
3121
        if (open_input_stream(rtp_c, "") < 0) {
3122
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3123
            return;
3124
        }
3125
    }
3126

    
3127
    /* test if stream is OK (test needed because several SETUP needs
3128
       to be done for a given file) */
3129
    if (rtp_c->stream != stream) {
3130
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3131
        return;
3132
    }
3133

    
3134
    /* test if stream is already set up */
3135
    if (rtp_c->rtp_ctx[stream_index]) {
3136
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3137
        return;
3138
    }
3139

    
3140
    /* check transport */
3141
    th = find_transport(h, rtp_c->rtp_protocol);
3142
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3143
                th->client_port_min <= 0)) {
3144
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3145
        return;
3146
    }
3147

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

    
3153
    /* setup stream */
3154
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3155
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3156
        return;
3157
    }
3158

    
3159
    /* now everything is OK, so we can send the connection parameters */
3160
    rtsp_reply_header(c, RTSP_STATUS_OK);
3161
    /* session ID */
3162
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3163

    
3164
    switch(rtp_c->rtp_protocol) {
3165
    case RTSP_LOWER_TRANSPORT_UDP:
3166
        rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3167
        rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3168
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3169
                    "client_port=%d-%d;server_port=%d-%d",
3170
                    th->client_port_min, th->client_port_max,
3171
                    rtp_port, rtcp_port);
3172
        break;
3173
    case RTSP_LOWER_TRANSPORT_TCP:
3174
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3175
                    stream_index * 2, stream_index * 2 + 1);
3176
        break;
3177
    default:
3178
        break;
3179
    }
3180
    if (setup.transport_option[0] != '\0')
3181
        url_fprintf(c->pb, ";%s", setup.transport_option);
3182
    url_fprintf(c->pb, "\r\n");
3183

    
3184

    
3185
    url_fprintf(c->pb, "\r\n");
3186
}
3187

    
3188

    
3189
/* find an rtp connection by using the session ID. Check consistency
3190
   with filename */
3191
static HTTPContext *find_rtp_session_with_url(const char *url,
3192
                                              const char *session_id)
3193
{
3194
    HTTPContext *rtp_c;
3195
    char path1[1024];
3196
    const char *path;
3197
    char buf[1024];
3198
    int s;
3199

    
3200
    rtp_c = find_rtp_session(session_id);
3201
    if (!rtp_c)
3202
        return NULL;
3203

    
3204
    /* find which url is asked */
3205
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3206
    path = path1;
3207
    if (*path == '/')
3208
        path++;
3209
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3210
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3211
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3212
        rtp_c->stream->filename, s);
3213
      if(!strncmp(path, buf, sizeof(buf))) {
3214
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3215
        return rtp_c;
3216
      }
3217
    }
3218
    return NULL;
3219
}
3220

    
3221
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3222
{
3223
    HTTPContext *rtp_c;
3224

    
3225
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3226
    if (!rtp_c) {
3227
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3228
        return;
3229
    }
3230

    
3231
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3232
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3233
        rtp_c->state != HTTPSTATE_READY) {
3234
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3235
        return;
3236
    }
3237

    
3238
    rtp_c->state = HTTPSTATE_SEND_DATA;
3239

    
3240
    /* now everything is OK, so we can send the connection parameters */
3241
    rtsp_reply_header(c, RTSP_STATUS_OK);
3242
    /* session ID */
3243
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3244
    url_fprintf(c->pb, "\r\n");
3245
}
3246

    
3247
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3248
{
3249
    HTTPContext *rtp_c;
3250

    
3251
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3252
    if (!rtp_c) {
3253
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3254
        return;
3255
    }
3256

    
3257
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3258
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3259
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3260
        return;
3261
    }
3262

    
3263
    rtp_c->state = HTTPSTATE_READY;
3264
    rtp_c->first_pts = AV_NOPTS_VALUE;
3265
    /* now everything is OK, so we can send the connection parameters */
3266
    rtsp_reply_header(c, RTSP_STATUS_OK);
3267
    /* session ID */
3268
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3269
    url_fprintf(c->pb, "\r\n");
3270
}
3271

    
3272
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3273
{
3274
    HTTPContext *rtp_c;
3275
    char session_id[32];
3276

    
3277
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3278
    if (!rtp_c) {
3279
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3280
        return;
3281
    }
3282

    
3283
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3284

    
3285
    /* abort the session */
3286
    close_connection(rtp_c);
3287

    
3288
    /* now everything is OK, so we can send the connection parameters */
3289
    rtsp_reply_header(c, RTSP_STATUS_OK);
3290
    /* session ID */
3291
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3292
    url_fprintf(c->pb, "\r\n");
3293
}
3294

    
3295

    
3296
/********************************************************************/
3297
/* RTP handling */
3298

    
3299
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3300
                                       FFStream *stream, const char *session_id,
3301
                                       enum RTSPLowerTransport rtp_protocol)
3302
{
3303
    HTTPContext *c = NULL;
3304
    const char *proto_str;
3305

    
3306
    /* XXX: should output a warning page when coming
3307
       close to the connection limit */
3308
    if (nb_connections >= nb_max_connections)
3309
        goto fail;
3310

    
3311
    /* add a new connection */
3312
    c = av_mallocz(sizeof(HTTPContext));
3313
    if (!c)
3314
        goto fail;
3315

    
3316
    c->fd = -1;
3317
    c->poll_entry = NULL;
3318
    c->from_addr = *from_addr;
3319
    c->buffer_size = IOBUFFER_INIT_SIZE;
3320
    c->buffer = av_malloc(c->buffer_size);
3321
    if (!c->buffer)
3322
        goto fail;
3323
    nb_connections++;
3324
    c->stream = stream;
3325
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3326
    c->state = HTTPSTATE_READY;
3327
    c->is_packetized = 1;
3328
    c->rtp_protocol = rtp_protocol;
3329

    
3330
    /* protocol is shown in statistics */
3331
    switch(c->rtp_protocol) {
3332
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3333
        proto_str = "MCAST";
3334
        break;
3335
    case RTSP_LOWER_TRANSPORT_UDP:
3336
        proto_str = "UDP";
3337
        break;
3338
    case RTSP_LOWER_TRANSPORT_TCP:
3339
        proto_str = "TCP";
3340
        break;
3341
    default:
3342
        proto_str = "???";
3343
        break;
3344
    }
3345
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3346
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3347

    
3348
    current_bandwidth += stream->bandwidth;
3349

    
3350
    c->next = first_http_ctx;
3351
    first_http_ctx = c;
3352
    return c;
3353

    
3354
 fail:
3355
    if (c) {
3356
        av_free(c->buffer);
3357
        av_free(c);
3358
    }
3359
    return NULL;
3360
}
3361

    
3362
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3363
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3364
   used. */
3365
static int rtp_new_av_stream(HTTPContext *c,
3366
                             int stream_index, struct sockaddr_in *dest_addr,
3367
                             HTTPContext *rtsp_c)
3368
{
3369
    AVFormatContext *ctx;
3370
    AVStream *st;
3371
    char *ipaddr;
3372
    URLContext *h = NULL;
3373
    uint8_t *dummy_buf;
3374
    int max_packet_size;
3375

    
3376
    /* now we can open the relevant output stream */
3377
    ctx = avformat_alloc_context();
3378
    if (!ctx)
3379
        return -1;
3380
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3381

    
3382
    st = av_mallocz(sizeof(AVStream));
3383
    if (!st)
3384
        goto fail;
3385
    ctx->nb_streams = 1;
3386
    ctx->streams[0] = st;
3387

    
3388
    if (!c->stream->feed ||
3389
        c->stream->feed == c->stream)
3390
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3391
    else
3392
        memcpy(st,
3393
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3394
               sizeof(AVStream));
3395
    st->priv_data = NULL;
3396

    
3397
    /* build destination RTP address */
3398
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3399

    
3400
    switch(c->rtp_protocol) {
3401
    case RTSP_LOWER_TRANSPORT_UDP:
3402
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3403
        /* RTP/UDP case */
3404

    
3405
        /* XXX: also pass as parameter to function ? */
3406
        if (c->stream->is_multicast) {
3407
            int ttl;
3408
            ttl = c->stream->multicast_ttl;
3409
            if (!ttl)
3410
                ttl = 16;
3411
            snprintf(ctx->filename, sizeof(ctx->filename),
3412
                     "rtp://%s:%d?multicast=1&ttl=%d",
3413
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3414
        } else {
3415
            snprintf(ctx->filename, sizeof(ctx->filename),
3416
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3417
        }
3418

    
3419
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3420
            goto fail;
3421
        c->rtp_handles[stream_index] = h;
3422
        max_packet_size = url_get_max_packet_size(h);
3423
        break;
3424
    case RTSP_LOWER_TRANSPORT_TCP:
3425
        /* RTP/TCP case */
3426
        c->rtsp_c = rtsp_c;
3427
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3428
        break;
3429
    default:
3430
        goto fail;
3431
    }
3432

    
3433
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3434
             ipaddr, ntohs(dest_addr->sin_port),
3435
             c->stream->filename, stream_index, c->protocol);
3436

    
3437
    /* normally, no packets should be output here, but the packet size may be checked */
3438
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3439
        /* XXX: close stream */
3440
        goto fail;
3441
    }
3442
    av_set_parameters(ctx, NULL);
3443
    if (av_write_header(ctx) < 0) {
3444
    fail:
3445
        if (h)
3446
            url_close(h);
3447
        av_free(ctx);
3448
        return -1;
3449
    }
3450
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3451
    av_free(dummy_buf);
3452

    
3453
    c->rtp_ctx[stream_index] = ctx;
3454
    return 0;
3455
}
3456

    
3457
/********************************************************************/
3458
/* ffserver initialization */
3459

    
3460
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3461
{
3462
    AVStream *fst;
3463

    
3464
    fst = av_mallocz(sizeof(AVStream));
3465
    if (!fst)
3466
        return NULL;
3467
    if (copy) {
3468
        fst->codec= avcodec_alloc_context();
3469
        memcpy(fst->codec, codec, sizeof(AVCodecContext));
3470
        if (codec->extradata_size) {
3471
            fst->codec->extradata = av_malloc(codec->extradata_size);
3472
            memcpy(fst->codec->extradata, codec->extradata,
3473
                codec->extradata_size);
3474
        }
3475
    } else {
3476
        /* live streams must use the actual feed's codec since it may be
3477
         * updated later to carry extradata needed by the streams.
3478
         */
3479
        fst->codec = codec;
3480
    }
3481
    fst->priv_data = av_mallocz(sizeof(FeedData));
3482
    fst->index = stream->nb_streams;
3483
    av_set_pts_info(fst, 33, 1, 90000);
3484
    stream->streams[stream->nb_streams++] = fst;
3485
    return fst;
3486
}
3487

    
3488
/* return the stream number in the feed */
3489
static int add_av_stream(FFStream *feed, AVStream *st)
3490
{
3491
    AVStream *fst;
3492
    AVCodecContext *av, *av1;
3493
    int i;
3494

    
3495
    av = st->codec;
3496
    for(i=0;i<feed->nb_streams;i++) {
3497
        st = feed->streams[i];
3498
        av1 = st->codec;
3499
        if (av1->codec_id == av->codec_id &&
3500
            av1->codec_type == av->codec_type &&
3501
            av1->bit_rate == av->bit_rate) {
3502

    
3503
            switch(av->codec_type) {
3504
            case AVMEDIA_TYPE_AUDIO:
3505
                if (av1->channels == av->channels &&
3506
                    av1->sample_rate == av->sample_rate)
3507
                    goto found;
3508
                break;
3509
            case AVMEDIA_TYPE_VIDEO:
3510
                if (av1->width == av->width &&
3511
                    av1->height == av->height &&
3512
                    av1->time_base.den == av->time_base.den &&
3513
                    av1->time_base.num == av->time_base.num &&
3514
                    av1->gop_size == av->gop_size)
3515
                    goto found;
3516
                break;
3517
            default:
3518
                abort();
3519
            }
3520
        }
3521
    }
3522

    
3523
    fst = add_av_stream1(feed, av, 0);
3524
    if (!fst)
3525
        return -1;
3526
    return feed->nb_streams - 1;
3527
 found:
3528
    return i;
3529
}
3530

    
3531
static void remove_stream(FFStream *stream)
3532
{
3533
    FFStream **ps;
3534
    ps = &first_stream;
3535
    while (*ps != NULL) {
3536
        if (*ps == stream)
3537
            *ps = (*ps)->next;
3538
        else
3539
            ps = &(*ps)->next;
3540
    }
3541
}
3542

    
3543
/* specific mpeg4 handling : we extract the raw parameters */
3544
static void extract_mpeg4_header(AVFormatContext *infile)
3545
{
3546
    int mpeg4_count, i, size;
3547
    AVPacket pkt;
3548
    AVStream *st;
3549
    const uint8_t *p;
3550

    
3551
    mpeg4_count = 0;
3552
    for(i=0;i<infile->nb_streams;i++) {
3553
        st = infile->streams[i];
3554
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3555
            st->codec->extradata_size == 0) {
3556
            mpeg4_count++;
3557
        }
3558
    }
3559
    if (!mpeg4_count)
3560
        return;
3561

    
3562
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3563
    while (mpeg4_count > 0) {
3564
        if (av_read_packet(infile, &pkt) < 0)
3565
            break;
3566
        st = infile->streams[pkt.stream_index];
3567
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3568
            st->codec->extradata_size == 0) {
3569
            av_freep(&st->codec->extradata);
3570
            /* fill extradata with the header */
3571
            /* XXX: we make hard suppositions here ! */
3572
            p = pkt.data;
3573
            while (p < pkt.data + pkt.size - 4) {
3574
                /* stop when vop header is found */
3575
                if (p[0] == 0x00 && p[1] == 0x00 &&
3576
                    p[2] == 0x01 && p[3] == 0xb6) {
3577
                    size = p - pkt.data;
3578
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3579
                    st->codec->extradata = av_malloc(size);
3580
                    st->codec->extradata_size = size;
3581
                    memcpy(st->codec->extradata, pkt.data, size);
3582
                    break;
3583
                }
3584
                p++;
3585
            }
3586
            mpeg4_count--;
3587
        }
3588
        av_free_packet(&pkt);
3589
    }
3590
}
3591

    
3592
/* compute the needed AVStream for each file */
3593
static void build_file_streams(void)
3594
{
3595
    FFStream *stream, *stream_next;
3596
    AVFormatContext *infile;
3597
    int i, ret;
3598

    
3599
    /* gather all streams */
3600
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3601
        stream_next = stream->next;
3602
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3603
            !stream->feed) {
3604
            /* the stream comes from a file */
3605
            /* try to open the file */
3606
            /* open stream */
3607
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3608
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3609
                /* specific case : if transport stream output to RTP,
3610
                   we use a raw transport stream reader */
3611
                stream->ap_in->mpeg2ts_raw = 1;
3612
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3613
            }
3614

    
3615
            http_log("Opening file '%s'\n", stream->feed_filename);
3616
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3617
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3618
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3619
                /* remove stream (no need to spend more time on it) */
3620
            fail:
3621
                remove_stream(stream);
3622
            } else {
3623
                /* find all the AVStreams inside and reference them in
3624
                   'stream' */
3625
                if (av_find_stream_info(infile) < 0) {
3626
                    http_log("Could not find codec parameters from '%s'\n",
3627
                             stream->feed_filename);
3628
                    av_close_input_file(infile);
3629
                    goto fail;
3630
                }
3631
                extract_mpeg4_header(infile);
3632

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

    
3636
                av_close_input_file(infile);
3637
            }
3638
        }
3639
    }
3640
}
3641

    
3642
/* compute the needed AVStream for each feed */
3643
static void build_feed_streams(void)
3644
{
3645
    FFStream *stream, *feed;
3646
    int i;
3647

    
3648
    /* gather all streams */
3649
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3650
        feed = stream->feed;
3651
        if (feed) {
3652
            if (!stream->is_feed) {
3653
                /* we handle a stream coming from a feed */
3654
                for(i=0;i<stream->nb_streams;i++)
3655
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3656
            }
3657
        }
3658
    }
3659

    
3660
    /* gather all streams */
3661
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3662
        feed = stream->feed;
3663
        if (feed) {
3664
            if (stream->is_feed) {
3665
                for(i=0;i<stream->nb_streams;i++)
3666
                    stream->feed_streams[i] = i;
3667
            }
3668
        }
3669
    }
3670

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

    
3675
        if (url_exist(feed->feed_filename)) {
3676
            /* See if it matches */
3677
            AVFormatContext *s;
3678
            int matches = 0;
3679

    
3680
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3681
                /* Now see if it matches */
3682
                if (s->nb_streams == feed->nb_streams) {
3683
                    matches = 1;
3684
                    for(i=0;i<s->nb_streams;i++) {
3685
                        AVStream *sf, *ss;
3686
                        sf = feed->streams[i];
3687
                        ss = s->streams[i];
3688

    
3689
                        if (sf->index != ss->index ||
3690
                            sf->id != ss->id) {
3691
                            http_log("Index & Id do not match for stream %d (%s)\n",
3692
                                   i, feed->feed_filename);
3693
                            matches = 0;
3694
                        } else {
3695
                            AVCodecContext *ccf, *ccs;
3696

    
3697
                            ccf = sf->codec;
3698
                            ccs = ss->codec;
3699
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3700

    
3701
                            if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3702
                                http_log("Codecs do not match for stream %d\n", i);
3703
                                matches = 0;
3704
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3705
                                http_log("Codec bitrates do not match for stream %d\n", i);
3706
                                matches = 0;
3707
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3708
                                if (CHECK_CODEC(time_base.den) ||
3709
                                    CHECK_CODEC(time_base.num) ||
3710
                                    CHECK_CODEC(width) ||
3711
                                    CHECK_CODEC(height)) {
3712
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3713
                                    matches = 0;
3714
                                }
3715
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3716
                                if (CHECK_CODEC(sample_rate) ||
3717
                                    CHECK_CODEC(channels) ||
3718
                                    CHECK_CODEC(frame_size)) {
3719
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3720
                                    matches = 0;
3721
                                }
3722
                            } else {
3723
                                http_log("Unknown codec type\n");
3724
                                matches = 0;
3725
                            }
3726
                        }
3727
                        if (!matches)
3728
                            break;
3729
                    }
3730
                } else
3731
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3732
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3733

    
3734
                av_close_input_file(s);
3735
            } else
3736
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3737
                        feed->feed_filename);
3738

    
3739
            if (!matches) {
3740
                if (feed->readonly) {
3741
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3742
                        feed->feed_filename);
3743
                    exit(1);
3744
                }
3745
                unlink(feed->feed_filename);
3746
            }
3747
        }
3748
        if (!url_exist(feed->feed_filename)) {
3749
            AVFormatContext s1 = {0}, *s = &s1;
3750

    
3751
            if (feed->readonly) {
3752
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3753
                    feed->feed_filename);
3754
                exit(1);
3755
            }
3756

    
3757
            /* only write the header of the ffm file */
3758
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3759
                http_log("Could not open output feed file '%s'\n",
3760
                         feed->feed_filename);
3761
                exit(1);
3762
            }
3763
            s->oformat = feed->fmt;
3764
            s->nb_streams = feed->nb_streams;
3765
            for(i=0;i<s->nb_streams;i++) {
3766
                AVStream *st;
3767
                st = feed->streams[i];
3768
                s->streams[i] = st;
3769
            }
3770
            av_set_parameters(s, NULL);
3771
            if (av_write_header(s) < 0) {
3772
                http_log("Container doesn't supports the required parameters\n");
3773
                exit(1);
3774
            }
3775
            /* XXX: need better api */
3776
            av_freep(&s->priv_data);
3777
            url_fclose(s->pb);
3778
        }
3779
        /* get feed size and write index */
3780
        fd = open(feed->feed_filename, O_RDONLY);
3781
        if (fd < 0) {
3782
            http_log("Could not open output feed file '%s'\n",
3783
                    feed->feed_filename);
3784
            exit(1);
3785
        }
3786

    
3787
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3788
        feed->feed_size = lseek(fd, 0, SEEK_END);
3789
        /* ensure that we do not wrap before the end of file */
3790
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3791
            feed->feed_max_size = feed->feed_size;
3792

    
3793
        close(fd);
3794
    }
3795
}
3796

    
3797
/* compute the bandwidth used by each stream */
3798
static void compute_bandwidth(void)
3799
{
3800
    unsigned bandwidth;
3801
    int i;
3802
    FFStream *stream;
3803

    
3804
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3805
        bandwidth = 0;
3806
        for(i=0;i<stream->nb_streams;i++) {
3807
            AVStream *st = stream->streams[i];
3808
            switch(st->codec->codec_type) {
3809
            case AVMEDIA_TYPE_AUDIO:
3810
            case AVMEDIA_TYPE_VIDEO:
3811
                bandwidth += st->codec->bit_rate;
3812
                break;
3813
            default:
3814
                break;
3815
            }
3816
        }
3817
        stream->bandwidth = (bandwidth + 999) / 1000;
3818
    }
3819
}
3820

    
3821
/* add a codec and set the default parameters */
3822
static void add_codec(FFStream *stream, AVCodecContext *av)
3823
{
3824
    AVStream *st;
3825

    
3826
    /* compute default parameters */
3827
    switch(av->codec_type) {
3828
    case AVMEDIA_TYPE_AUDIO:
3829
        if (av->bit_rate == 0)
3830
            av->bit_rate = 64000;
3831
        if (av->sample_rate == 0)
3832
            av->sample_rate = 22050;
3833
        if (av->channels == 0)
3834
            av->channels = 1;
3835
        break;
3836
    case AVMEDIA_TYPE_VIDEO:
3837
        if (av->bit_rate == 0)
3838
            av->bit_rate = 64000;
3839
        if (av->time_base.num == 0){
3840
            av->time_base.den = 5;
3841
            av->time_base.num = 1;
3842
        }
3843
        if (av->width == 0 || av->height == 0) {
3844
            av->width = 160;
3845
            av->height = 128;
3846
        }
3847
        /* Bitrate tolerance is less for streaming */
3848
        if (av->bit_rate_tolerance == 0)
3849
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3850
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3851
        if (av->qmin == 0)
3852
            av->qmin = 3;
3853
        if (av->qmax == 0)
3854
            av->qmax = 31;
3855
        if (av->max_qdiff == 0)
3856
            av->max_qdiff = 3;
3857
        av->qcompress = 0.5;
3858
        av->qblur = 0.5;
3859

    
3860
        if (!av->nsse_weight)
3861
            av->nsse_weight = 8;
3862

    
3863
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3864
        if (!av->me_method)
3865
            av->me_method = ME_EPZS;
3866
        av->rc_buffer_aggressivity = 1.0;
3867

    
3868
        if (!av->rc_eq)
3869
            av->rc_eq = "tex^qComp";
3870
        if (!av->i_quant_factor)
3871
            av->i_quant_factor = -0.8;
3872
        if (!av->b_quant_factor)
3873
            av->b_quant_factor = 1.25;
3874
        if (!av->b_quant_offset)
3875
            av->b_quant_offset = 1.25;
3876
        if (!av->rc_max_rate)
3877
            av->rc_max_rate = av->bit_rate * 2;
3878

    
3879
        if (av->rc_max_rate && !av->rc_buffer_size) {
3880
            av->rc_buffer_size = av->rc_max_rate;
3881
        }
3882

    
3883

    
3884
        break;
3885
    default:
3886
        abort();
3887
    }
3888

    
3889
    st = av_mallocz(sizeof(AVStream));
3890
    if (!st)
3891
        return;
3892
    st->codec = avcodec_alloc_context();
3893
    stream->streams[stream->nb_streams++] = st;
3894
    memcpy(st->codec, av, sizeof(AVCodecContext));
3895
}
3896

    
3897
static enum CodecID opt_audio_codec(const char *arg)
3898
{
3899
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3900

    
3901
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3902
        return CODEC_ID_NONE;
3903

    
3904
    return p->id;
3905
}
3906

    
3907
static enum CodecID opt_video_codec(const char *arg)
3908
{
3909
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3910

    
3911
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3912
        return CODEC_ID_NONE;
3913

    
3914
    return p->id;
3915
}
3916

    
3917
/* simplistic plugin support */
3918

    
3919
#if HAVE_DLOPEN
3920
static void load_module(const char *filename)
3921
{
3922
    void *dll;
3923
    void (*init_func)(void);
3924
    dll = dlopen(filename, RTLD_NOW);
3925
    if (!dll) {
3926
        fprintf(stderr, "Could not load module '%s' - %s\n",
3927
                filename, dlerror());
3928
        return;
3929
    }
3930

    
3931
    init_func = dlsym(dll, "ffserver_module_init");
3932
    if (!init_func) {
3933
        fprintf(stderr,
3934
                "%s: init function 'ffserver_module_init()' not found\n",
3935
                filename);
3936
        dlclose(dll);
3937
    }
3938

    
3939
    init_func();
3940
}
3941
#endif
3942

    
3943
static int ffserver_opt_default(const char *opt, const char *arg,
3944
                       AVCodecContext *avctx, int type)
3945
{
3946
    int ret = 0;
3947
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3948
    if(o)
3949
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3950
    return ret;
3951
}
3952

    
3953
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3954
                                             const char *mime_type)
3955
{
3956
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3957

    
3958
    if (fmt) {
3959
        AVOutputFormat *stream_fmt;
3960
        char stream_format_name[64];
3961

    
3962
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3963
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3964

    
3965
        if (stream_fmt)
3966
            fmt = stream_fmt;
3967
    }
3968

    
3969
    return fmt;
3970
}
3971

    
3972
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3973
{
3974
    va_list vl;
3975
    va_start(vl, fmt);
3976
    fprintf(stderr, "%s:%d: ", filename, line_num);
3977
    vfprintf(stderr, fmt, vl);
3978
    va_end(vl);
3979

    
3980
    (*errors)++;
3981
}
3982

    
3983
static int parse_ffconfig(const char *filename)
3984
{
3985
    FILE *f;
3986
    char line[1024];
3987
    char cmd[64];
3988
    char arg[1024];
3989
    const char *p;
3990
    int val, errors, line_num;
3991
    FFStream **last_stream, *stream, *redirect;
3992
    FFStream **last_feed, *feed, *s;
3993
    AVCodecContext audio_enc, video_enc;
3994
    enum CodecID audio_id, video_id;
3995

    
3996
    f = fopen(filename, "r");
3997
    if (!f) {
3998
        perror(filename);
3999
        return -1;
4000
    }
4001

    
4002
    errors = 0;
4003
    line_num = 0;
4004
    first_stream = NULL;
4005
    last_stream = &first_stream;
4006
    first_feed = NULL;
4007
    last_feed = &first_feed;
4008
    stream = NULL;
4009
    feed = NULL;
4010
    redirect = NULL;
4011
    audio_id = CODEC_ID_NONE;
4012
    video_id = CODEC_ID_NONE;
4013

    
4014
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4015
    for(;;) {
4016
        if (fgets(line, sizeof(line), f) == NULL)
4017
            break;
4018
        line_num++;
4019
        p = line;
4020
        while (isspace(*p))
4021
            p++;
4022
        if (*p == '\0' || *p == '#')
4023
            continue;
4024

    
4025
        get_arg(cmd, sizeof(cmd), &p);
4026

    
4027
        if (!strcasecmp(cmd, "Port")) {
4028
            get_arg(arg, sizeof(arg), &p);
4029
            val = atoi(arg);
4030
            if (val < 1 || val > 65536) {
4031
                ERROR("Invalid_port: %s\n", arg);
4032
            }
4033
            my_http_addr.sin_port = htons(val);
4034
        } else if (!strcasecmp(cmd, "BindAddress")) {
4035
            get_arg(arg, sizeof(arg), &p);
4036
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4037
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4038
            }
4039
        } else if (!strcasecmp(cmd, "NoDaemon")) {
4040
            ffserver_daemon = 0;
4041
        } else if (!strcasecmp(cmd, "RTSPPort")) {
4042
            get_arg(arg, sizeof(arg), &p);
4043
            val = atoi(arg);
4044
            if (val < 1 || val > 65536) {
4045
                ERROR("%s:%d: Invalid port: %s\n", arg);
4046
            }
4047
            my_rtsp_addr.sin_port = htons(atoi(arg));
4048
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4049
            get_arg(arg, sizeof(arg), &p);
4050
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4051
                ERROR("Invalid host/IP address: %s\n", arg);
4052
            }
4053
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4054
            get_arg(arg, sizeof(arg), &p);
4055
            val = atoi(arg);
4056
            if (val < 1 || val > 65536) {
4057
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4058
            }
4059
            nb_max_http_connections = val;
4060
        } else if (!strcasecmp(cmd, "MaxClients")) {
4061
            get_arg(arg, sizeof(arg), &p);
4062
            val = atoi(arg);
4063
            if (val < 1 || val > nb_max_http_connections) {
4064
                ERROR("Invalid MaxClients: %s\n", arg);
4065
            } else {
4066
                nb_max_connections = val;
4067
            }
4068
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4069
            int64_t llval;
4070
            get_arg(arg, sizeof(arg), &p);
4071
            llval = atoll(arg);
4072
            if (llval < 10 || llval > 10000000) {
4073
                ERROR("Invalid MaxBandwidth: %s\n", arg);
4074
            } else
4075
                max_bandwidth = llval;
4076
        } else if (!strcasecmp(cmd, "CustomLog")) {
4077
            if (!ffserver_debug)
4078
                get_arg(logfilename, sizeof(logfilename), &p);
4079
        } else if (!strcasecmp(cmd, "<Feed")) {
4080
            /*********************************************/
4081
            /* Feed related options */
4082
            char *q;
4083
            if (stream || feed) {
4084
                ERROR("Already in a tag\n");
4085
            } else {
4086
                feed = av_mallocz(sizeof(FFStream));
4087
                get_arg(feed->filename, sizeof(feed->filename), &p);
4088
                q = strrchr(feed->filename, '>');
4089
                if (*q)
4090
                    *q = '\0';
4091

    
4092
                for (s = first_feed; s; s = s->next) {
4093
                    if (!strcmp(feed->filename, s->filename)) {
4094
                        ERROR("Feed '%s' already registered\n", s->filename);
4095
                    }
4096
                }
4097

    
4098
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4099
                /* defaut feed file */
4100
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4101
                         "/tmp/%s.ffm", feed->filename);
4102
                feed->feed_max_size = 5 * 1024 * 1024;
4103
                feed->is_feed = 1;
4104
                feed->feed = feed; /* self feeding :-) */
4105

    
4106
                /* add in stream list */
4107
                *last_stream = feed;
4108
                last_stream = &feed->next;
4109
                /* add in feed list */
4110
                *last_feed = feed;
4111
                last_feed = &feed->next_feed;
4112
            }
4113
        } else if (!strcasecmp(cmd, "Launch")) {
4114
            if (feed) {
4115
                int i;
4116

    
4117
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4118

    
4119
                for (i = 0; i < 62; i++) {
4120
                    get_arg(arg, sizeof(arg), &p);
4121
                    if (!arg[0])
4122
                        break;
4123

    
4124
                    feed->child_argv[i] = av_strdup(arg);
4125
                }
4126

    
4127
                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4128

    
4129
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4130
                    "http://%s:%d/%s",
4131
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4132
                    inet_ntoa(my_http_addr.sin_addr),
4133
                    ntohs(my_http_addr.sin_port), feed->filename);
4134
            }
4135
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4136
            if (feed) {
4137
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4138
                feed->readonly = 1;
4139
            } else if (stream) {
4140
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4141
            }
4142
        } else if (!strcasecmp(cmd, "File")) {
4143
            if (feed) {
4144
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4145
            } else if (stream)
4146
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4147
        } else if (!strcasecmp(cmd, "Truncate")) {
4148
            if (feed) {
4149
                get_arg(arg, sizeof(arg), &p);
4150
                feed->truncate = strtod(arg, NULL);
4151
            }
4152
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4153
            if (feed) {
4154
                char *p1;
4155
                double fsize;
4156

    
4157
                get_arg(arg, sizeof(arg), &p);
4158
                p1 = arg;
4159
                fsize = strtod(p1, &p1);
4160
                switch(toupper(*p1)) {
4161
                case 'K':
4162
                    fsize *= 1024;
4163
                    break;
4164
                case 'M':
4165
                    fsize *= 1024 * 1024;
4166
                    break;
4167
                case 'G':
4168
                    fsize *= 1024 * 1024 * 1024;
4169
                    break;
4170
                }
4171
                feed->feed_max_size = (int64_t)fsize;
4172
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4173
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4174
                }
4175
            }
4176
        } else if (!strcasecmp(cmd, "</Feed>")) {
4177
            if (!feed) {
4178
                ERROR("No corresponding <Feed> for </Feed>\n");
4179
            }
4180
            feed = NULL;
4181
        } else if (!strcasecmp(cmd, "<Stream")) {
4182
            /*********************************************/
4183
            /* Stream related options */
4184
            char *q;
4185
            if (stream || feed) {
4186
                ERROR("Already in a tag\n");
4187
            } else {
4188
                FFStream *s;
4189
                stream = av_mallocz(sizeof(FFStream));
4190
                get_arg(stream->filename, sizeof(stream->filename), &p);
4191
                q = strrchr(stream->filename, '>');
4192
                if (*q)
4193
                    *q = '\0';
4194

    
4195
                for (s = first_stream; s; s = s->next) {
4196
                    if (!strcmp(stream->filename, s->filename)) {
4197
                        ERROR("Stream '%s' already registered\n", s->filename);
4198
                    }
4199
                }
4200

    
4201
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4202
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4203
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4204
                audio_id = CODEC_ID_NONE;
4205
                video_id = CODEC_ID_NONE;
4206
                if (stream->fmt) {
4207
                    audio_id = stream->fmt->audio_codec;
4208
                    video_id = stream->fmt->video_codec;
4209
                }
4210

    
4211
                *last_stream = stream;
4212
                last_stream = &stream->next;
4213
            }
4214
        } else if (!strcasecmp(cmd, "Feed")) {
4215
            get_arg(arg, sizeof(arg), &p);
4216
            if (stream) {
4217
                FFStream *sfeed;
4218

    
4219
                sfeed = first_feed;
4220
                while (sfeed != NULL) {
4221
                    if (!strcmp(sfeed->filename, arg))
4222
                        break;
4223
                    sfeed = sfeed->next_feed;
4224
                }
4225
                if (!sfeed)
4226
                    ERROR("feed '%s' not defined\n", arg);
4227
                else
4228
                    stream->feed = sfeed;
4229
            }
4230
        } else if (!strcasecmp(cmd, "Format")) {
4231
            get_arg(arg, sizeof(arg), &p);
4232
            if (stream) {
4233
                if (!strcmp(arg, "status")) {
4234
                    stream->stream_type = STREAM_TYPE_STATUS;
4235
                    stream->fmt = NULL;
4236
                } else {
4237
                    stream->stream_type = STREAM_TYPE_LIVE;
4238
                    /* jpeg cannot be used here, so use single frame jpeg */
4239
                    if (!strcmp(arg, "jpeg"))
4240
                        strcpy(arg, "mjpeg");
4241
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4242
                    if (!stream->fmt) {
4243
                        ERROR("Unknown Format: %s\n", arg);
4244
                    }
4245
                }
4246
                if (stream->fmt) {
4247
                    audio_id = stream->fmt->audio_codec;
4248
                    video_id = stream->fmt->video_codec;
4249
                }
4250
            }
4251
        } else if (!strcasecmp(cmd, "InputFormat")) {
4252
            get_arg(arg, sizeof(arg), &p);
4253
            if (stream) {
4254
                stream->ifmt = av_find_input_format(arg);
4255
                if (!stream->ifmt) {
4256
                    ERROR("Unknown input format: %s\n", arg);
4257
                }
4258
            }
4259
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4260
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4261
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4262
            } else {
4263
                ERROR("FaviconURL only permitted for status streams\n");
4264
            }
4265
        } else if (!strcasecmp(cmd, "Author")) {
4266
            if (stream)
4267
                get_arg(stream->author, sizeof(stream->author), &p);
4268
        } else if (!strcasecmp(cmd, "Comment")) {
4269
            if (stream)
4270
                get_arg(stream->comment, sizeof(stream->comment), &p);
4271
        } else if (!strcasecmp(cmd, "Copyright")) {
4272
            if (stream)
4273
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4274
        } else if (!strcasecmp(cmd, "Title")) {
4275
            if (stream)
4276
                get_arg(stream->title, sizeof(stream->title), &p);
4277
        } else if (!strcasecmp(cmd, "Preroll")) {
4278
            get_arg(arg, sizeof(arg), &p);
4279
            if (stream)
4280
                stream->prebuffer = atof(arg) * 1000;
4281
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4282
            if (stream)
4283
                stream->send_on_key = 1;
4284
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4285
            get_arg(arg, sizeof(arg), &p);
4286
            audio_id = opt_audio_codec(arg);
4287
            if (audio_id == CODEC_ID_NONE) {
4288
                ERROR("Unknown AudioCodec: %s\n", arg);
4289
            }
4290
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4291
            get_arg(arg, sizeof(arg), &p);
4292
            video_id = opt_video_codec(arg);
4293
            if (video_id == CODEC_ID_NONE) {
4294
                ERROR("Unknown VideoCodec: %s\n", arg);
4295
            }
4296
        } else if (!strcasecmp(cmd, "MaxTime")) {
4297
            get_arg(arg, sizeof(arg), &p);
4298
            if (stream)
4299
                stream->max_time = atof(arg) * 1000;
4300
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4301
            get_arg(arg, sizeof(arg), &p);
4302
            if (stream)
4303
                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4304
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4305
            get_arg(arg, sizeof(arg), &p);
4306
            if (stream)
4307
                audio_enc.channels = atoi(arg);
4308
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4309
            get_arg(arg, sizeof(arg), &p);
4310
            if (stream)
4311
                audio_enc.sample_rate = atoi(arg);
4312
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4313
            get_arg(arg, sizeof(arg), &p);
4314
            if (stream) {
4315
//                audio_enc.quality = atof(arg) * 1000;
4316
            }
4317
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4318
            if (stream) {
4319
                int minrate, maxrate;
4320

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

    
4323
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4324
                    video_enc.rc_min_rate = minrate * 1000;
4325
                    video_enc.rc_max_rate = maxrate * 1000;
4326
                } else {
4327
                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4328
                }
4329
            }
4330
        } else if (!strcasecmp(cmd, "Debug")) {
4331
            if (stream) {
4332
                get_arg(arg, sizeof(arg), &p);
4333
                video_enc.debug = strtol(arg,0,0);
4334
            }
4335
        } else if (!strcasecmp(cmd, "Strict")) {
4336
            if (stream) {
4337
                get_arg(arg, sizeof(arg), &p);
4338
                video_enc.strict_std_compliance = atoi(arg);
4339
            }
4340
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4341
            if (stream) {
4342
                get_arg(arg, sizeof(arg), &p);
4343
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4344
            }
4345
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4346
            if (stream) {
4347
                get_arg(arg, sizeof(arg), &p);
4348
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4349
            }
4350
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4351
            get_arg(arg, sizeof(arg), &p);
4352
            if (stream) {
4353
                video_enc.bit_rate = atoi(arg) * 1000;
4354
            }
4355
        } else if (!strcasecmp(cmd, "VideoSize")) {
4356
            get_arg(arg, sizeof(arg), &p);
4357
            if (stream) {
4358
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4359
                if ((video_enc.width % 16) != 0 ||
4360
                    (video_enc.height % 16) != 0) {
4361
                    ERROR("Image size must be a multiple of 16\n");
4362
                }
4363
            }
4364
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4365
            get_arg(arg, sizeof(arg), &p);
4366
            if (stream) {
4367
                AVRational frame_rate;
4368
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4369
                    ERROR("Incorrect frame rate: %s\n", arg);
4370
                } else {
4371
                    video_enc.time_base.num = frame_rate.den;
4372
                    video_enc.time_base.den = frame_rate.num;
4373
                }
4374
            }
4375
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4376
            get_arg(arg, sizeof(arg), &p);
4377
            if (stream)
4378
                video_enc.gop_size = atoi(arg);
4379
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4380
            if (stream)
4381
                video_enc.gop_size = 1;
4382
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4383
            if (stream)
4384
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4385
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4386
            if (stream) {
4387
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4388
                video_enc.flags |= CODEC_FLAG_4MV;
4389
            }
4390
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4391
                   !strcasecmp(cmd, "AVOptionAudio")) {
4392
            char arg2[1024];
4393
            AVCodecContext *avctx;
4394
            int type;
4395
            get_arg(arg, sizeof(arg), &p);
4396
            get_arg(arg2, sizeof(arg2), &p);
4397
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4398
                avctx = &video_enc;
4399
                type = AV_OPT_FLAG_VIDEO_PARAM;
4400
            } else {
4401
                avctx = &audio_enc;
4402
                type = AV_OPT_FLAG_AUDIO_PARAM;
4403
            }
4404
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4405
                ERROR("AVOption error: %s %s\n", arg, arg2);
4406
            }
4407
        } else if (!strcasecmp(cmd, "VideoTag")) {
4408
            get_arg(arg, sizeof(arg), &p);
4409
            if ((strlen(arg) == 4) && stream)
4410
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4411
        } else if (!strcasecmp(cmd, "BitExact")) {
4412
            if (stream)
4413
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4414
        } else if (!strcasecmp(cmd, "DctFastint")) {
4415
            if (stream)
4416
                video_enc.dct_algo  = FF_DCT_FASTINT;
4417
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4418
            if (stream)
4419
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4420
        } else if (!strcasecmp(cmd, "Qscale")) {
4421
            get_arg(arg, sizeof(arg), &p);
4422
            if (stream) {
4423
                video_enc.flags |= CODEC_FLAG_QSCALE;
4424
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4425
            }
4426
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4427
            get_arg(arg, sizeof(arg), &p);
4428
            if (stream) {
4429
                video_enc.max_qdiff = atoi(arg);
4430
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4431
                    ERROR("VideoQDiff out of range\n");
4432
                }
4433
            }
4434
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4435
            get_arg(arg, sizeof(arg), &p);
4436
            if (stream) {
4437
                video_enc.qmax = atoi(arg);
4438
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4439
                    ERROR("VideoQMax out of range\n");
4440
                }
4441
            }
4442
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4443
            get_arg(arg, sizeof(arg), &p);
4444
            if (stream) {
4445
                video_enc.qmin = atoi(arg);
4446
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4447
                    ERROR("VideoQMin out of range\n");
4448
                }
4449
            }
4450
        } else if (!strcasecmp(cmd, "LumaElim")) {
4451
            get_arg(arg, sizeof(arg), &p);
4452
            if (stream)
4453
                video_enc.luma_elim_threshold = atoi(arg);
4454
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4455
            get_arg(arg, sizeof(arg), &p);
4456
            if (stream)
4457
                video_enc.chroma_elim_threshold = atoi(arg);
4458
        } else if (!strcasecmp(cmd, "LumiMask")) {
4459
            get_arg(arg, sizeof(arg), &p);
4460
            if (stream)
4461
                video_enc.lumi_masking = atof(arg);
4462
        } else if (!strcasecmp(cmd, "DarkMask")) {
4463
            get_arg(arg, sizeof(arg), &p);
4464
            if (stream)
4465
                video_enc.dark_masking = atof(arg);
4466
        } else if (!strcasecmp(cmd, "NoVideo")) {
4467
            video_id = CODEC_ID_NONE;
4468
        } else if (!strcasecmp(cmd, "NoAudio")) {
4469
            audio_id = CODEC_ID_NONE;
4470
        } else if (!strcasecmp(cmd, "ACL")) {
4471
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4472
        } else if (!strcasecmp(cmd, "DynamicACL")) {
4473
            if (stream) {
4474
                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4475
            }
4476
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4477
            get_arg(arg, sizeof(arg), &p);
4478
            if (stream) {
4479
                av_freep(&stream->rtsp_option);
4480
                stream->rtsp_option = av_strdup(arg);
4481
            }
4482
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4483
            get_arg(arg, sizeof(arg), &p);
4484
            if (stream) {
4485
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4486
                    ERROR("Invalid host/IP address: %s\n", arg);
4487
                }
4488
                stream->is_multicast = 1;
4489
                stream->loop = 1; /* default is looping */
4490
            }
4491
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4492
            get_arg(arg, sizeof(arg), &p);
4493
            if (stream)
4494
                stream->multicast_port = atoi(arg);
4495
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4496
            get_arg(arg, sizeof(arg), &p);
4497
            if (stream)
4498
                stream->multicast_ttl = atoi(arg);
4499
        } else if (!strcasecmp(cmd, "NoLoop")) {
4500
            if (stream)
4501
                stream->loop = 0;
4502
        } else if (!strcasecmp(cmd, "</Stream>")) {
4503
            if (!stream) {
4504
                ERROR("No corresponding <Stream> for </Stream>\n");
4505
            } else {
4506
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4507
                    if (audio_id != CODEC_ID_NONE) {
4508
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4509
                        audio_enc.codec_id = audio_id;
4510
                        add_codec(stream, &audio_enc);
4511
                    }
4512
                    if (video_id != CODEC_ID_NONE) {
4513
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4514
                        video_enc.codec_id = video_id;
4515
                        add_codec(stream, &video_enc);
4516
                    }
4517
                }
4518
                stream = NULL;
4519
            }
4520
        } else if (!strcasecmp(cmd, "<Redirect")) {
4521
            /*********************************************/
4522
            char *q;
4523
            if (stream || feed || redirect) {
4524
                ERROR("Already in a tag\n");
4525
            } else {
4526
                redirect = av_mallocz(sizeof(FFStream));
4527
                *last_stream = redirect;
4528
                last_stream = &redirect->next;
4529

    
4530
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4531
                q = strrchr(redirect->filename, '>');
4532
                if (*q)
4533
                    *q = '\0';
4534
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4535
            }
4536
        } else if (!strcasecmp(cmd, "URL")) {
4537
            if (redirect)
4538
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4539
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4540
            if (!redirect) {
4541
                ERROR("No corresponding <Redirect> for </Redirect>\n");
4542
            } else {
4543
                if (!redirect->feed_filename[0]) {
4544
                    ERROR("No URL found for <Redirect>\n");
4545
                }
4546
                redirect = NULL;
4547
            }
4548
        } else if (!strcasecmp(cmd, "LoadModule")) {
4549
            get_arg(arg, sizeof(arg), &p);
4550
#if HAVE_DLOPEN
4551
            load_module(arg);
4552
#else
4553
            ERROR("Module support not compiled into this version: '%s'\n", arg);
4554
#endif
4555
        } else {
4556
            ERROR("Incorrect keyword: '%s'\n", cmd);
4557
        }
4558
    }
4559
#undef ERROR
4560

    
4561
    fclose(f);
4562
    if (errors)
4563
        return -1;
4564
    else
4565
        return 0;
4566
}
4567

    
4568
static void handle_child_exit(int sig)
4569
{
4570
    pid_t pid;
4571
    int status;
4572

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

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

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

    
4583
                if (uptime < 30)
4584
                    /* Turn off any more restarts */
4585
                    feed->child_argv = 0;
4586
            }
4587
        }
4588
    }
4589

    
4590
    need_to_start_children = 1;
4591
}
4592

    
4593
static void opt_debug(void)
4594
{
4595
    ffserver_debug = 1;
4596
    ffserver_daemon = 0;
4597
    logfilename[0] = '-';
4598
}
4599

    
4600
static void show_help(void)
4601
{
4602
    printf("usage: ffserver [options]\n"
4603
           "Hyper fast multi format Audio/Video streaming server\n");
4604
    printf("\n");
4605
    show_help_options(options, "Main options:\n", 0, 0);
4606
}
4607

    
4608
static const OptionDef options[] = {
4609
#include "cmdutils_common_opts.h"
4610
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4611
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4612
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4613
    { NULL },
4614
};
4615

    
4616
int main(int argc, char **argv)
4617
{
4618
    struct sigaction sigact;
4619

    
4620
    av_register_all();
4621

    
4622
    show_banner();
4623

    
4624
    my_program_name = argv[0];
4625
    my_program_dir = getcwd(0, 0);
4626
    ffserver_daemon = 1;
4627

    
4628
    parse_options(argc, argv, options, NULL);
4629

    
4630
    unsetenv("http_proxy");             /* Kill the http_proxy */
4631

    
4632
    av_lfg_init(&random_state, av_get_random_seed());
4633

    
4634
    memset(&sigact, 0, sizeof(sigact));
4635
    sigact.sa_handler = handle_child_exit;
4636
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4637
    sigaction(SIGCHLD, &sigact, 0);
4638

    
4639
    if (parse_ffconfig(config_filename) < 0) {
4640
        fprintf(stderr, "Incorrect config file - exiting.\n");
4641
        exit(1);
4642
    }
4643

    
4644
    /* open log file if needed */
4645
    if (logfilename[0] != '\0') {
4646
        if (!strcmp(logfilename, "-"))
4647
            logfile = stdout;
4648
        else
4649
            logfile = fopen(logfilename, "a");
4650
        av_log_set_callback(http_av_log);
4651
    }
4652

    
4653
    build_file_streams();
4654

    
4655
    build_feed_streams();
4656

    
4657
    compute_bandwidth();
4658

    
4659
    /* put the process in background and detach it from its TTY */
4660
    if (ffserver_daemon) {
4661
        int pid;
4662

    
4663
        pid = fork();
4664
        if (pid < 0) {
4665
            perror("fork");
4666
            exit(1);
4667
        } else if (pid > 0) {
4668
            /* parent : exit */
4669
            exit(0);
4670
        } else {
4671
            /* child */
4672
            setsid();
4673
            close(0);
4674
            open("/dev/null", O_RDWR);
4675
            if (strcmp(logfilename, "-") != 0) {
4676
                close(1);
4677
                dup(0);
4678
            }
4679
            close(2);
4680
            dup(0);
4681
        }
4682
    }
4683

    
4684
    /* signal init */
4685
    signal(SIGPIPE, SIG_IGN);
4686

    
4687
    if (ffserver_daemon)
4688
        chdir("/");
4689

    
4690
    if (http_server() < 0) {
4691
        http_log("Could not start server\n");
4692
        exit(1);
4693
    }
4694

    
4695
    return 0;
4696
}