Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 34c340d4

History | View | Annotate | Download (155 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 "libavutil/parseutils.h"
40
#include "libavcodec/opt.h"
41
#include <stdarg.h>
42
#include <unistd.h>
43
#include <fcntl.h>
44
#include <sys/ioctl.h>
45
#if HAVE_POLL_H
46
#include <poll.h>
47
#endif
48
#include <errno.h>
49
#include <sys/time.h>
50
#include <time.h>
51
#include <sys/wait.h>
52
#include <signal.h>
53
#if HAVE_DLFCN_H
54
#include <dlfcn.h>
55
#endif
56

    
57
#include "cmdutils.h"
58

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

    
62
static const OptionDef options[];
63

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

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

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

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

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

    
95
#if !FF_API_MAX_STREAMS
96
#define MAX_STREAMS 20
97
#endif
98

    
99
#define IOBUFFER_INIT_SIZE 8192
100

    
101
/* timeouts are in ms */
102
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
103
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
104

    
105
#define SYNC_TIMEOUT (10 * 1000)
106

    
107
typedef struct RTSPActionServerSetup {
108
    uint32_t ipaddr;
109
    char transport_option[512];
110
} RTSPActionServerSetup;
111

    
112
typedef struct {
113
    int64_t count1, count2;
114
    int64_t time1, time2;
115
} DataRateData;
116

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

    
164
    /* RTSP state specific */
165
    uint8_t *pb_buffer; /* XXX: use that in all the code */
166
    ByteIOContext *pb;
167
    int seq; /* RTSP sequence number */
168

    
169
    /* RTP state specific */
170
    enum RTSPLowerTransport rtp_protocol;
171
    char session_id[32]; /* session id */
172
    AVFormatContext *rtp_ctx[MAX_STREAMS];
173

    
174
    /* RTP/UDP specific */
175
    URLContext *rtp_handles[MAX_STREAMS];
176

    
177
    /* RTP/TCP specific */
178
    struct HTTPContext *rtsp_c;
179
    uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
180
} HTTPContext;
181

    
182
/* each generated stream is described here */
183
enum StreamType {
184
    STREAM_TYPE_LIVE,
185
    STREAM_TYPE_STATUS,
186
    STREAM_TYPE_REDIRECT,
187
};
188

    
189
enum IPAddressAction {
190
    IP_ALLOW = 1,
191
    IP_DENY,
192
};
193

    
194
typedef struct IPAddressACL {
195
    struct IPAddressACL *next;
196
    enum IPAddressAction action;
197
    /* These are in host order */
198
    struct in_addr first;
199
    struct in_addr last;
200
} IPAddressACL;
201

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

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

    
252
typedef struct FeedData {
253
    long long data_count;
254
    float avg_frame_size;   /* frame size averaged over last frames with exponential mean */
255
} FeedData;
256

    
257
static struct sockaddr_in my_http_addr;
258
static struct sockaddr_in my_rtsp_addr;
259

    
260
static char logfilename[1024];
261
static HTTPContext *first_http_ctx;
262
static FFStream *first_feed;   /* contains only feeds */
263
static FFStream *first_stream; /* contains all streams, including feeds */
264

    
265
static void new_connection(int server_fd, int is_rtsp);
266
static void close_connection(HTTPContext *c);
267

    
268
/* HTTP handling */
269
static int handle_connection(HTTPContext *c);
270
static int http_parse_request(HTTPContext *c);
271
static int http_send_data(HTTPContext *c);
272
static void compute_status(HTTPContext *c);
273
static int open_input_stream(HTTPContext *c, const char *info);
274
static int http_start_receive_data(HTTPContext *c);
275
static int http_receive_data(HTTPContext *c);
276

    
277
/* RTSP handling */
278
static int rtsp_parse_request(HTTPContext *c);
279
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
280
static void rtsp_cmd_options(HTTPContext *c, const char *url);
281
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
282
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285

    
286
/* SDP handling */
287
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
288
                                   struct in_addr my_ip);
289

    
290
/* RTP handling */
291
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
292
                                       FFStream *stream, const char *session_id,
293
                                       enum RTSPLowerTransport rtp_protocol);
294
static int rtp_new_av_stream(HTTPContext *c,
295
                             int stream_index, struct sockaddr_in *dest_addr,
296
                             HTTPContext *rtsp_c);
297

    
298
static const char *my_program_name;
299
static const char *my_program_dir;
300

    
301
static const char *config_filename = "/etc/ffserver.conf";
302

    
303
static int ffserver_debug;
304
static int ffserver_daemon;
305
static int no_launch;
306
static int need_to_start_children;
307

    
308
/* maximum number of simultaneous HTTP connections */
309
static unsigned int nb_max_http_connections = 2000;
310
static unsigned int nb_max_connections = 5;
311
static unsigned int nb_connections;
312

    
313
static uint64_t max_bandwidth = 1000;
314
static uint64_t current_bandwidth;
315

    
316
static int64_t cur_time;           // Making this global saves on passing it around everywhere
317

    
318
static AVLFG random_state;
319

    
320
static FILE *logfile = NULL;
321

    
322
/* FIXME: make ffserver work with IPv6 */
323
/* resolve host with also IP address parsing */
324
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
325
{
326

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

    
358
static char *ctime1(char *buf2)
359
{
360
    time_t ti;
361
    char *p;
362

    
363
    ti = time(NULL);
364
    p = ctime(&ti);
365
    strcpy(buf2, p);
366
    p = buf2 + strlen(p) - 1;
367
    if (*p == '\n')
368
        *p = '\0';
369
    return buf2;
370
}
371

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

    
387
#ifdef __GNUC__
388
__attribute__ ((format (printf, 1, 2)))
389
#endif
390
static void http_log(const char *fmt, ...)
391
{
392
    va_list vargs;
393
    va_start(vargs, fmt);
394
    http_vlog(fmt, vargs);
395
    va_end(vargs);
396
}
397

    
398
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
399
{
400
    static int print_prefix = 1;
401
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
402
    if (level > av_log_get_level())
403
        return;
404
    if (print_prefix && avc)
405
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
406
    print_prefix = strstr(fmt, "\n") != NULL;
407
    http_vlog(fmt, vargs);
408
}
409

    
410
static void log_connection(HTTPContext *c)
411
{
412
    if (c->suppress_log)
413
        return;
414

    
415
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
416
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
417
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
418
}
419

    
420
static void update_datarate(DataRateData *drd, int64_t count)
421
{
422
    if (!drd->time1 && !drd->count1) {
423
        drd->time1 = drd->time2 = cur_time;
424
        drd->count1 = drd->count2 = count;
425
    } else if (cur_time - drd->time2 > 5000) {
426
        drd->time1 = drd->time2;
427
        drd->count1 = drd->count2;
428
        drd->time2 = cur_time;
429
        drd->count2 = count;
430
    }
431
}
432

    
433
/* In bytes per second */
434
static int compute_datarate(DataRateData *drd, int64_t count)
435
{
436
    if (cur_time == drd->time1)
437
        return 0;
438

    
439
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
440
}
441

    
442

    
443
static void start_children(FFStream *feed)
444
{
445
    if (no_launch)
446
        return;
447

    
448
    for (; feed; feed = feed->next) {
449
        if (feed->child_argv && !feed->pid) {
450
            feed->pid_start = time(0);
451

    
452
            feed->pid = fork();
453

    
454
            if (feed->pid < 0) {
455
                http_log("Unable to create children\n");
456
                exit(1);
457
            }
458
            if (!feed->pid) {
459
                /* In child */
460
                char pathname[1024];
461
                char *slash;
462
                int i;
463

    
464
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
465

    
466
                slash = strrchr(pathname, '/');
467
                if (!slash)
468
                    slash = pathname;
469
                else
470
                    slash++;
471
                strcpy(slash, "ffmpeg");
472

    
473
                http_log("Launch commandline: ");
474
                http_log("%s ", pathname);
475
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
476
                    http_log("%s ", feed->child_argv[i]);
477
                http_log("\n");
478

    
479
                for (i = 3; i < 256; i++)
480
                    close(i);
481

    
482
                if (!ffserver_debug) {
483
                    i = open("/dev/null", O_RDWR);
484
                    if (i != -1) {
485
                        dup2(i, 0);
486
                        dup2(i, 1);
487
                        dup2(i, 2);
488
                        close(i);
489
                    }
490
                }
491

    
492
                /* This is needed to make relative pathnames work */
493
                chdir(my_program_dir);
494

    
495
                signal(SIGPIPE, SIG_DFL);
496

    
497
                execvp(pathname, feed->child_argv);
498

    
499
                _exit(1);
500
            }
501
        }
502
    }
503
}
504

    
505
/* open a listening socket */
506
static int socket_open_listen(struct sockaddr_in *my_addr)
507
{
508
    int server_fd, tmp;
509

    
510
    server_fd = socket(AF_INET,SOCK_STREAM,0);
511
    if (server_fd < 0) {
512
        perror ("socket");
513
        return -1;
514
    }
515

    
516
    tmp = 1;
517
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
518

    
519
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
520
        char bindmsg[32];
521
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
522
        perror (bindmsg);
523
        closesocket(server_fd);
524
        return -1;
525
    }
526

    
527
    if (listen (server_fd, 5) < 0) {
528
        perror ("listen");
529
        closesocket(server_fd);
530
        return -1;
531
    }
532
    ff_socket_nonblock(server_fd, 1);
533

    
534
    return server_fd;
535
}
536

    
537
/* start all multicast streams */
538
static void start_multicast(void)
539
{
540
    FFStream *stream;
541
    char session_id[32];
542
    HTTPContext *rtp_c;
543
    struct sockaddr_in dest_addr;
544
    int default_port, stream_index;
545

    
546
    default_port = 6000;
547
    for(stream = first_stream; stream != NULL; stream = stream->next) {
548
        if (stream->is_multicast) {
549
            /* open the RTP connection */
550
            snprintf(session_id, sizeof(session_id), "%08x%08x",
551
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
552

    
553
            /* choose a port if none given */
554
            if (stream->multicast_port == 0) {
555
                stream->multicast_port = default_port;
556
                default_port += 100;
557
            }
558

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

    
563
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
564
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
565
            if (!rtp_c)
566
                continue;
567

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

    
574
            /* open each RTP stream */
575
            for(stream_index = 0; stream_index < stream->nb_streams;
576
                stream_index++) {
577
                dest_addr.sin_port = htons(stream->multicast_port +
578
                                           2 * stream_index);
579
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
580
                    http_log("Could not open output stream '%s/streamid=%d'\n",
581
                             stream->filename, stream_index);
582
                    exit(1);
583
                }
584
            }
585

    
586
            /* change state to send data */
587
            rtp_c->state = HTTPSTATE_SEND_DATA;
588
        }
589
    }
590
}
591

    
592
/* main loop of the http server */
593
static int http_server(void)
594
{
595
    int server_fd = 0, rtsp_server_fd = 0;
596
    int ret, delay, delay1;
597
    struct pollfd *poll_table, *poll_entry;
598
    HTTPContext *c, *c_next;
599

    
600
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
601
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
602
        return -1;
603
    }
604

    
605
    if (my_http_addr.sin_port) {
606
        server_fd = socket_open_listen(&my_http_addr);
607
        if (server_fd < 0)
608
            return -1;
609
    }
610

    
611
    if (my_rtsp_addr.sin_port) {
612
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
613
        if (rtsp_server_fd < 0)
614
            return -1;
615
    }
616

    
617
    if (!rtsp_server_fd && !server_fd) {
618
        http_log("HTTP and RTSP disabled.\n");
619
        return -1;
620
    }
621

    
622
    http_log("FFserver started.\n");
623

    
624
    start_children(first_feed);
625

    
626
    start_multicast();
627

    
628
    for(;;) {
629
        poll_entry = poll_table;
630
        if (server_fd) {
631
            poll_entry->fd = server_fd;
632
            poll_entry->events = POLLIN;
633
            poll_entry++;
634
        }
635
        if (rtsp_server_fd) {
636
            poll_entry->fd = rtsp_server_fd;
637
            poll_entry->events = POLLIN;
638
            poll_entry++;
639
        }
640

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

    
691
        /* wait for an event on one connection. We poll at least every
692
           second to handle timeouts */
693
        do {
694
            ret = poll(poll_table, poll_entry - poll_table, delay);
695
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
696
                ff_neterrno() != FF_NETERROR(EINTR))
697
                return -1;
698
        } while (ret < 0);
699

    
700
        cur_time = av_gettime() / 1000;
701

    
702
        if (need_to_start_children) {
703
            need_to_start_children = 0;
704
            start_children(first_feed);
705
        }
706

    
707
        /* now handle the events */
708
        for(c = first_http_ctx; c != NULL; c = c_next) {
709
            c_next = c->next;
710
            if (handle_connection(c) < 0) {
711
                /* close and free the connection */
712
                log_connection(c);
713
                close_connection(c);
714
            }
715
        }
716

    
717
        poll_entry = poll_table;
718
        if (server_fd) {
719
            /* new HTTP connection request ? */
720
            if (poll_entry->revents & POLLIN)
721
                new_connection(server_fd, 0);
722
            poll_entry++;
723
        }
724
        if (rtsp_server_fd) {
725
            /* new RTSP connection request ? */
726
            if (poll_entry->revents & POLLIN)
727
                new_connection(rtsp_server_fd, 1);
728
        }
729
    }
730
}
731

    
732
/* start waiting for a new HTTP/RTSP request */
733
static void start_wait_request(HTTPContext *c, int is_rtsp)
734
{
735
    c->buffer_ptr = c->buffer;
736
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
737

    
738
    if (is_rtsp) {
739
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
740
        c->state = RTSPSTATE_WAIT_REQUEST;
741
    } else {
742
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
743
        c->state = HTTPSTATE_WAIT_REQUEST;
744
    }
745
}
746

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

    
762

    
763
static void new_connection(int server_fd, int is_rtsp)
764
{
765
    struct sockaddr_in from_addr;
766
    int fd, len;
767
    HTTPContext *c = NULL;
768

    
769
    len = sizeof(from_addr);
770
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
771
                &len);
772
    if (fd < 0) {
773
        http_log("error during accept %s\n", strerror(errno));
774
        return;
775
    }
776
    ff_socket_nonblock(fd, 1);
777

    
778
    if (nb_connections >= nb_max_connections) {
779
        http_send_too_busy_reply(fd);
780
        goto fail;
781
    }
782

    
783
    /* add a new connection */
784
    c = av_mallocz(sizeof(HTTPContext));
785
    if (!c)
786
        goto fail;
787

    
788
    c->fd = fd;
789
    c->poll_entry = NULL;
790
    c->from_addr = from_addr;
791
    c->buffer_size = IOBUFFER_INIT_SIZE;
792
    c->buffer = av_malloc(c->buffer_size);
793
    if (!c->buffer)
794
        goto fail;
795

    
796
    c->next = first_http_ctx;
797
    first_http_ctx = c;
798
    nb_connections++;
799

    
800
    start_wait_request(c, is_rtsp);
801

    
802
    return;
803

    
804
 fail:
805
    if (c) {
806
        av_free(c->buffer);
807
        av_free(c);
808
    }
809
    closesocket(fd);
810
}
811

    
812
static void close_connection(HTTPContext *c)
813
{
814
    HTTPContext **cp, *c1;
815
    int i, nb_streams;
816
    AVFormatContext *ctx;
817
    URLContext *h;
818
    AVStream *st;
819

    
820
    /* remove connection from list */
821
    cp = &first_http_ctx;
822
    while ((*cp) != NULL) {
823
        c1 = *cp;
824
        if (c1 == c)
825
            *cp = c->next;
826
        else
827
            cp = &c1->next;
828
    }
829

    
830
    /* remove references, if any (XXX: do it faster) */
831
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
832
        if (c1->rtsp_c == c)
833
            c1->rtsp_c = NULL;
834
    }
835

    
836
    /* remove connection associated resources */
837
    if (c->fd >= 0)
838
        closesocket(c->fd);
839
    if (c->fmt_in) {
840
        /* close each frame parser */
841
        for(i=0;i<c->fmt_in->nb_streams;i++) {
842
            st = c->fmt_in->streams[i];
843
            if (st->codec->codec)
844
                avcodec_close(st->codec);
845
        }
846
        av_close_input_file(c->fmt_in);
847
    }
848

    
849
    /* free RTP output streams if any */
850
    nb_streams = 0;
851
    if (c->stream)
852
        nb_streams = c->stream->nb_streams;
853

    
854
    for(i=0;i<nb_streams;i++) {
855
        ctx = c->rtp_ctx[i];
856
        if (ctx) {
857
            av_write_trailer(ctx);
858
            av_metadata_free(&ctx->metadata);
859
            av_free(ctx->streams[0]);
860
            av_free(ctx);
861
        }
862
        h = c->rtp_handles[i];
863
        if (h)
864
            url_close(h);
865
    }
866

    
867
    ctx = &c->fmt_ctx;
868

    
869
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
870
        if (ctx->oformat) {
871
            /* prepare header */
872
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
873
                av_write_trailer(ctx);
874
                av_freep(&c->pb_buffer);
875
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
876
            }
877
        }
878
    }
879

    
880
    for(i=0; i<ctx->nb_streams; i++)
881
        av_free(ctx->streams[i]);
882

    
883
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
884
        current_bandwidth -= c->stream->bandwidth;
885

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

    
892
    av_freep(&c->pb_buffer);
893
    av_freep(&c->packet_buffer);
894
    av_free(c->buffer);
895
    av_free(c);
896
    nb_connections--;
897
}
898

    
899
static int handle_connection(HTTPContext *c)
900
{
901
    int len, ret;
902

    
903
    switch(c->state) {
904
    case HTTPSTATE_WAIT_REQUEST:
905
    case RTSPSTATE_WAIT_REQUEST:
906
        /* timeout ? */
907
        if ((c->timeout - cur_time) < 0)
908
            return -1;
909
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
910
            return -1;
911

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

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

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

    
978
    case HTTPSTATE_SEND_DATA:
979
    case HTTPSTATE_SEND_DATA_HEADER:
980
    case HTTPSTATE_SEND_DATA_TRAILER:
981
        /* for packetized output, we consider we can always write (the
982
           input streams sets the speed). It may be better to verify
983
           that we do not rely too much on the kernel queues */
984
        if (!c->is_packetized) {
985
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
986
                return -1;
987

    
988
            /* no need to read if no events */
989
            if (!(c->poll_entry->revents & POLLOUT))
990
                return 0;
991
        }
992
        if (http_send_data(c) < 0)
993
            return -1;
994
        /* close connection if trailer sent */
995
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
996
            return -1;
997
        break;
998
    case HTTPSTATE_RECEIVE_DATA:
999
        /* no need to read if no events */
1000
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
1001
            return -1;
1002
        if (!(c->poll_entry->revents & POLLIN))
1003
            return 0;
1004
        if (http_receive_data(c) < 0)
1005
            return -1;
1006
        break;
1007
    case HTTPSTATE_WAIT_FEED:
1008
        /* no need to read if no events */
1009
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1010
            return -1;
1011

    
1012
        /* nothing to do, we'll be waken up by incoming feed packets */
1013
        break;
1014

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

    
1076
static int extract_rates(char *rates, int ratelen, const char *request)
1077
{
1078
    const char *p;
1079

    
1080
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1081
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1082
            const char *q = p + 7;
1083

    
1084
            while (*q && *q != '\n' && isspace(*q))
1085
                q++;
1086

    
1087
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1088
                int stream_no;
1089
                int rate_no;
1090

    
1091
                q += 20;
1092

    
1093
                memset(rates, 0xff, ratelen);
1094

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

    
1099
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1100
                        break;
1101

    
1102
                    stream_no--;
1103
                    if (stream_no < ratelen && stream_no >= 0)
1104
                        rates[stream_no] = rate_no;
1105

    
1106
                    while (*q && *q != '\n' && !isspace(*q))
1107
                        q++;
1108
                }
1109

    
1110
                return 1;
1111
            }
1112
        }
1113
        p = strchr(p, '\n');
1114
        if (!p)
1115
            break;
1116

    
1117
        p++;
1118
    }
1119

    
1120
    return 0;
1121
}
1122

    
1123
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1124
{
1125
    int i;
1126
    int best_bitrate = 100000000;
1127
    int best = -1;
1128

    
1129
    for (i = 0; i < feed->nb_streams; i++) {
1130
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1131

    
1132
        if (feed_codec->codec_id != codec->codec_id ||
1133
            feed_codec->sample_rate != codec->sample_rate ||
1134
            feed_codec->width != codec->width ||
1135
            feed_codec->height != codec->height)
1136
            continue;
1137

    
1138
        /* Potential stream */
1139

    
1140
        /* We want the fastest stream less than bit_rate, or the slowest
1141
         * faster than bit_rate
1142
         */
1143

    
1144
        if (feed_codec->bit_rate <= bit_rate) {
1145
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1146
                best_bitrate = feed_codec->bit_rate;
1147
                best = i;
1148
            }
1149
        } else {
1150
            if (feed_codec->bit_rate < best_bitrate) {
1151
                best_bitrate = feed_codec->bit_rate;
1152
                best = i;
1153
            }
1154
        }
1155
    }
1156

    
1157
    return best;
1158
}
1159

    
1160
static int modify_current_stream(HTTPContext *c, char *rates)
1161
{
1162
    int i;
1163
    FFStream *req = c->stream;
1164
    int action_required = 0;
1165

    
1166
    /* Not much we can do for a feed */
1167
    if (!req->feed)
1168
        return 0;
1169

    
1170
    for (i = 0; i < req->nb_streams; i++) {
1171
        AVCodecContext *codec = req->streams[i]->codec;
1172

    
1173
        switch(rates[i]) {
1174
            case 0:
1175
                c->switch_feed_streams[i] = req->feed_streams[i];
1176
                break;
1177
            case 1:
1178
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1179
                break;
1180
            case 2:
1181
                /* Wants off or slow */
1182
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1183
#ifdef WANTS_OFF
1184
                /* This doesn't work well when it turns off the only stream! */
1185
                c->switch_feed_streams[i] = -2;
1186
                c->feed_streams[i] = -2;
1187
#endif
1188
                break;
1189
        }
1190

    
1191
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1192
            action_required = 1;
1193
    }
1194

    
1195
    return action_required;
1196
}
1197

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

    
1209
static void get_word(char *buf, int buf_size, const char **pp)
1210
{
1211
    const char *p;
1212
    char *q;
1213

    
1214
    p = *pp;
1215
    skip_spaces(&p);
1216
    q = buf;
1217
    while (!isspace(*p) && *p != '\0') {
1218
        if ((q - buf) < buf_size - 1)
1219
            *q++ = *p;
1220
        p++;
1221
    }
1222
    if (buf_size > 0)
1223
        *q = '\0';
1224
    *pp = p;
1225
}
1226

    
1227
static void get_arg(char *buf, int buf_size, const char **pp)
1228
{
1229
    const char *p;
1230
    char *q;
1231
    int quote;
1232

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

    
1259
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1260
                         const char *p, const char *filename, int line_num)
1261
{
1262
    char arg[1024];
1263
    IPAddressACL acl;
1264
    int errors = 0;
1265

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

    
1277
    get_arg(arg, sizeof(arg), &p);
1278

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

    
1286
    get_arg(arg, sizeof(arg), &p);
1287

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

    
1296
    if (!errors) {
1297
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1298
        IPAddressACL **naclp = 0;
1299

    
1300
        acl.next = 0;
1301
        *nacl = acl;
1302

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

    
1315
        if (naclp) {
1316
            while (*naclp)
1317
                naclp = &(*naclp)->next;
1318

    
1319
            *naclp = nacl;
1320
        }
1321
    }
1322
}
1323

    
1324

    
1325
static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1326
{
1327
    FILE* f;
1328
    char line[1024];
1329
    char  cmd[1024];
1330
    IPAddressACL *acl = NULL;
1331
    int line_num = 0;
1332
    const char *p;
1333

    
1334
    f = fopen(stream->dynamic_acl, "r");
1335
    if (!f) {
1336
        perror(stream->dynamic_acl);
1337
        return NULL;
1338
    }
1339

    
1340
    acl = av_mallocz(sizeof(IPAddressACL));
1341

    
1342
    /* Build ACL */
1343
    for(;;) {
1344
        if (fgets(line, sizeof(line), f) == NULL)
1345
            break;
1346
        line_num++;
1347
        p = line;
1348
        while (isspace(*p))
1349
            p++;
1350
        if (*p == '\0' || *p == '#')
1351
            continue;
1352
        get_arg(cmd, sizeof(cmd), &p);
1353

    
1354
        if (!strcasecmp(cmd, "ACL"))
1355
            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1356
    }
1357
    fclose(f);
1358
    return acl;
1359
}
1360

    
1361

    
1362
static void free_acl_list(IPAddressACL *in_acl)
1363
{
1364
    IPAddressACL *pacl,*pacl2;
1365

    
1366
    pacl = in_acl;
1367
    while(pacl) {
1368
        pacl2 = pacl;
1369
        pacl = pacl->next;
1370
        av_freep(pacl2);
1371
    }
1372
}
1373

    
1374
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1375
{
1376
    enum IPAddressAction last_action = IP_DENY;
1377
    IPAddressACL *acl;
1378
    struct in_addr *src = &c->from_addr.sin_addr;
1379
    unsigned long src_addr = src->s_addr;
1380

    
1381
    for (acl = in_acl; acl; acl = acl->next) {
1382
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1383
            return (acl->action == IP_ALLOW) ? 1 : 0;
1384
        last_action = acl->action;
1385
    }
1386

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

    
1391
static int validate_acl(FFStream *stream, HTTPContext *c)
1392
{
1393
    int ret = 0;
1394
    IPAddressACL *acl;
1395

    
1396

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

    
1400
    if (stream->dynamic_acl[0]) {
1401
        acl = parse_dynamic_acl(stream, c);
1402

    
1403
        ret = validate_acl_list(acl, c);
1404

    
1405
        free_acl_list(acl);
1406
    }
1407

    
1408
    return ret;
1409
}
1410

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

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

    
1437
enum RedirType {
1438
    REDIR_NONE,
1439
    REDIR_ASX,
1440
    REDIR_RAM,
1441
    REDIR_ASF,
1442
    REDIR_RTSP,
1443
    REDIR_SDP,
1444
};
1445

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

    
1462
    p = c->buffer;
1463
    get_word(cmd, sizeof(cmd), (const char **)&p);
1464
    av_strlcpy(c->method, cmd, sizeof(c->method));
1465

    
1466
    if (!strcmp(cmd, "GET"))
1467
        c->post = 0;
1468
    else if (!strcmp(cmd, "POST"))
1469
        c->post = 1;
1470
    else
1471
        return -1;
1472

    
1473
    get_word(url, sizeof(url), (const char **)&p);
1474
    av_strlcpy(c->url, url, sizeof(c->url));
1475

    
1476
    get_word(protocol, sizeof(protocol), (const char **)&p);
1477
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1478
        return -1;
1479

    
1480
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1481

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

    
1485
    /* find the filename and the optional info string in the request */
1486
    p = strchr(url, '?');
1487
    if (p) {
1488
        av_strlcpy(info, p, sizeof(info));
1489
        *p = '\0';
1490
    } else
1491
        info[0] = '\0';
1492

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

    
1495
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1496
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1497
            useragent = p + 11;
1498
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1499
                useragent++;
1500
            break;
1501
        }
1502
        p = strchr(p, '\n');
1503
        if (!p)
1504
            break;
1505

    
1506
        p++;
1507
    }
1508

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

    
1528
    // "redirect" / request to index.html
1529
    if (!strlen(filename))
1530
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1531

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

    
1544
    c->stream = stream;
1545
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1546
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1547

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

    
1566
    /* If this is WMP, get the rate information */
1567
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1568
        if (modify_current_stream(c, ratebuf)) {
1569
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1570
                if (c->switch_feed_streams[i] >= 0)
1571
                    c->switch_feed_streams[i] = -1;
1572
            }
1573
        }
1574
    }
1575

    
1576
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1577
        current_bandwidth += stream->bandwidth;
1578

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

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

    
1605
    if (redir_type != REDIR_NONE) {
1606
        char *hostinfo = 0;
1607

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

    
1617
            p++;
1618
        }
1619

    
1620
        if (hostinfo) {
1621
            char *eoh;
1622
            char hostbuf[260];
1623

    
1624
            while (isspace(*hostinfo))
1625
                hostinfo++;
1626

    
1627
            eoh = strchr(hostinfo, '\n');
1628
            if (eoh) {
1629
                if (eoh[-1] == '\r')
1630
                    eoh--;
1631

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

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

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

    
1692
                            len = sizeof(my_addr);
1693
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1694

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

    
1712
                    /* prepare output buffer */
1713
                    c->buffer_ptr = c->buffer;
1714
                    c->buffer_end = q;
1715
                    c->state = HTTPSTATE_SEND_HEADER;
1716
                    return 0;
1717
                }
1718
            }
1719
        }
1720

    
1721
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1722
        goto send_error;
1723
    }
1724

    
1725
    stream->conns_served++;
1726

    
1727
    /* XXX: add there authenticate and IP match */
1728

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

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

    
1748
                p++;
1749
            }
1750

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

    
1754
                logline += 17;
1755

    
1756
                if (eol) {
1757
                    if (eol[-1] == '\r')
1758
                        eol--;
1759
                    http_log("%.*s\n", (int) (eol - logline), logline);
1760
                    c->suppress_log = 1;
1761
                }
1762
            }
1763

    
1764
#ifdef DEBUG_WMP
1765
            http_log("\nGot request:\n%s\n", c->buffer);
1766
#endif
1767

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

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

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

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

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

    
1799
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1800
        goto send_status;
1801

    
1802
    /* open input stream */
1803
    if (open_input_stream(c, info) < 0) {
1804
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1805
        goto send_error;
1806
    }
1807

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

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

    
1820
        c->wmp_client_id = av_lfg_get(&random_state);
1821

    
1822
        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);
1823
    }
1824
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1825
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1826

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

    
1857
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1858
{
1859
    static const char *suffix = " kMGTP";
1860
    const char *s;
1861

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

    
1864
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1865
}
1866

    
1867
static void compute_status(HTTPContext *c)
1868
{
1869
    HTTPContext *c1;
1870
    FFStream *stream;
1871
    char *p;
1872
    time_t ti;
1873
    int i, len;
1874
    ByteIOContext *pb;
1875

    
1876
    if (url_open_dyn_buf(&pb) < 0) {
1877
        /* XXX: return an error ? */
1878
        c->buffer_ptr = c->buffer;
1879
        c->buffer_end = c->buffer;
1880
        return;
1881
    }
1882

    
1883
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1884
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1885
    url_fprintf(pb, "Pragma: no-cache\r\n");
1886
    url_fprintf(pb, "\r\n");
1887

    
1888
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1889
    if (c->stream->feed_filename[0])
1890
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1891
    url_fprintf(pb, "</head>\n<body>");
1892
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1893
    /* format status */
1894
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1895
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1896
    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");
1897
    stream = first_stream;
1898
    while (stream != NULL) {
1899
        char sfilename[1024];
1900
        char *eosf;
1901

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

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

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

    
1986
    stream = first_stream;
1987
    while (stream != NULL) {
1988
        if (stream->feed == stream) {
1989
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1990
            if (stream->pid) {
1991
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1992

    
1993
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1994
                {
1995
                    FILE *pid_stat;
1996
                    char ps_cmd[64];
1997

    
1998
                    /* This is somewhat linux specific I guess */
1999
                    snprintf(ps_cmd, sizeof(ps_cmd),
2000
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2001
                             stream->pid);
2002

    
2003
                    pid_stat = popen(ps_cmd, "r");
2004
                    if (pid_stat) {
2005
                        char cpuperc[10];
2006
                        char cpuused[64];
2007

    
2008
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
2009
                                   cpuused) == 2) {
2010
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2011
                                         cpuperc, cpuused);
2012
                        }
2013
                        fclose(pid_stat);
2014
                    }
2015
                }
2016
#endif
2017

    
2018
                url_fprintf(pb, "<p>");
2019
            }
2020
            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");
2021

    
2022
            for (i = 0; i < stream->nb_streams; i++) {
2023
                AVStream *st = stream->streams[i];
2024
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2025
                const char *type = "unknown";
2026
                char parameters[64];
2027

    
2028
                parameters[0] = 0;
2029

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

    
2048
        }
2049
        stream = stream->next;
2050
    }
2051

    
2052
    /* connection status */
2053
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
2054

    
2055
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
2056
                 nb_connections, nb_max_connections);
2057

    
2058
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2059
                 current_bandwidth, max_bandwidth);
2060

    
2061
    url_fprintf(pb, "<table>\n");
2062
    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");
2063
    c1 = first_http_ctx;
2064
    i = 0;
2065
    while (c1 != NULL) {
2066
        int bitrate;
2067
        int j;
2068

    
2069
        bitrate = 0;
2070
        if (c1->stream) {
2071
            for (j = 0; j < c1->stream->nb_streams; j++) {
2072
                if (!c1->stream->feed)
2073
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2074
                else if (c1->feed_streams[j] >= 0)
2075
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2076
            }
2077
        }
2078

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

    
2098
    /* date */
2099
    ti = time(NULL);
2100
    p = ctime(&ti);
2101
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
2102
    url_fprintf(pb, "</body>\n</html>\n");
2103

    
2104
    len = url_close_dyn_buf(pb, &c->pb_buffer);
2105
    c->buffer_ptr = c->pb_buffer;
2106
    c->buffer_end = c->pb_buffer + len;
2107
}
2108

    
2109
/* check if the parser needs to be opened for stream i */
2110
static void open_parser(AVFormatContext *s, int i)
2111
{
2112
    AVStream *st = s->streams[i];
2113
    AVCodec *codec;
2114

    
2115
    if (!st->codec->codec) {
2116
        codec = avcodec_find_decoder(st->codec->codec_id);
2117
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2118
            st->codec->parse_only = 1;
2119
            if (avcodec_open(st->codec, codec) < 0)
2120
                st->codec->parse_only = 0;
2121
        }
2122
    }
2123
}
2124

    
2125
static int open_input_stream(HTTPContext *c, const char *info)
2126
{
2127
    char buf[128];
2128
    char input_filename[1024];
2129
    AVFormatContext *s;
2130
    int buf_size, i, ret;
2131
    int64_t stream_pos;
2132

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

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

    
2175
    /* open each parser */
2176
    for(i=0;i<s->nb_streams;i++)
2177
        open_parser(s, i);
2178

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

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

    
2199
/* return the server clock (in us) */
2200
static int64_t get_server_clock(HTTPContext *c)
2201
{
2202
    /* compute current pts value from system time */
2203
    return (cur_time - c->start_time) * 1000;
2204
}
2205

    
2206
/* return the estimated time at which the current packet must be sent
2207
   (in us) */
2208
static int64_t get_packet_send_clock(HTTPContext *c)
2209
{
2210
    int bytes_left, bytes_sent, frame_bytes;
2211

    
2212
    frame_bytes = c->cur_frame_bytes;
2213
    if (frame_bytes <= 0)
2214
        return c->cur_pts;
2215
    else {
2216
        bytes_left = c->buffer_end - c->buffer_ptr;
2217
        bytes_sent = frame_bytes - bytes_left;
2218
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2219
    }
2220
}
2221

    
2222

    
2223
static int http_prepare_data(HTTPContext *c)
2224
{
2225
    int i, len, ret;
2226
    AVFormatContext *ctx;
2227

    
2228
    av_freep(&c->pb_buffer);
2229
    switch(c->state) {
2230
    case HTTPSTATE_SEND_DATA_HEADER:
2231
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2232
        av_metadata_set2(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2233
        av_metadata_set2(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2234
        av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2235
        av_metadata_set2(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
2236

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

    
2249
            *st = *src;
2250
            st->priv_data = 0;
2251
            st->codec->frame_number = 0; /* XXX: should be done in
2252
                                           AVStream, not in codec */
2253
        }
2254
        /* set output format parameters */
2255
        c->fmt_ctx.oformat = c->stream->fmt;
2256
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2257

    
2258
        c->got_key_frame = 0;
2259

    
2260
        /* prepare header and save header data in a stream */
2261
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2262
            /* XXX: potential leak */
2263
            return -1;
2264
        }
2265
        c->fmt_ctx.pb->is_streamed = 1;
2266

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

    
2275
        av_set_parameters(&c->fmt_ctx, NULL);
2276
        if (av_write_header(&c->fmt_ctx) < 0) {
2277
            http_log("Error writing output header\n");
2278
            return -1;
2279
        }
2280
        av_metadata_free(&c->fmt_ctx.metadata);
2281

    
2282
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2283
        c->buffer_ptr = c->pb_buffer;
2284
        c->buffer_end = c->pb_buffer + len;
2285

    
2286
        c->state = HTTPSTATE_SEND_DATA;
2287
        c->last_packet_sent = 0;
2288
        break;
2289
    case HTTPSTATE_SEND_DATA:
2290
        /* find a new packet */
2291
        /* read a packet from the input stream */
2292
        if (c->stream->feed)
2293
            ffm_set_write_index(c->fmt_in,
2294
                                c->stream->feed->feed_write_index,
2295
                                c->stream->feed->feed_size);
2296

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

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

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

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

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

    
2447
        c->last_packet_sent = 1;
2448
        break;
2449
    }
2450
    return 0;
2451
}
2452

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

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

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

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

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

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

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

    
2575
static int http_start_receive_data(HTTPContext *c)
2576
{
2577
    int fd;
2578

    
2579
    if (c->stream->feed_opened)
2580
        return -1;
2581

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2743
            for (i = 0; i < s->nb_streams; i++) {
2744
                AVStream *fst = feed->streams[i];
2745
                AVStream *st = s->streams[i];
2746
                avcodec_copy_context(fst->codec, st->codec);
2747
            }
2748

    
2749
            av_close_input_stream(s);
2750
            av_free(pb);
2751
        }
2752
        c->buffer_ptr = c->buffer;
2753
    }
2754

    
2755
    return 0;
2756
 fail:
2757
    c->stream->feed_opened = 0;
2758
    close(c->feed_fd);
2759
    /* wake up any waiting connections to stop waiting for feed */
2760
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2761
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2762
            c1->stream->feed == c->stream->feed)
2763
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2764
    }
2765
    return -1;
2766
}
2767

    
2768
/********************************************************************/
2769
/* RTSP handling */
2770

    
2771
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2772
{
2773
    const char *str;
2774
    time_t ti;
2775
    struct tm *tm;
2776
    char buf2[32];
2777

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

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

    
2820
    /* output GMT time */
2821
    ti = time(NULL);
2822
    tm = gmtime(&ti);
2823
    strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2824
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2825
}
2826

    
2827
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2828
{
2829
    rtsp_reply_header(c, error_number);
2830
    url_fprintf(c->pb, "\r\n");
2831
}
2832

    
2833
static int rtsp_parse_request(HTTPContext *c)
2834
{
2835
    const char *p, *p1, *p2;
2836
    char cmd[32];
2837
    char url[1024];
2838
    char protocol[32];
2839
    char line[1024];
2840
    int len;
2841
    RTSPMessageHeader header1, *header = &header1;
2842

    
2843
    c->buffer_ptr[0] = '\0';
2844
    p = c->buffer;
2845

    
2846
    get_word(cmd, sizeof(cmd), &p);
2847
    get_word(url, sizeof(url), &p);
2848
    get_word(protocol, sizeof(protocol), &p);
2849

    
2850
    av_strlcpy(c->method, cmd, sizeof(c->method));
2851
    av_strlcpy(c->url, url, sizeof(c->url));
2852
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2853

    
2854
    if (url_open_dyn_buf(&c->pb) < 0) {
2855
        /* XXX: cannot do more */
2856
        c->pb = NULL; /* safety */
2857
        return -1;
2858
    }
2859

    
2860
    /* check version name */
2861
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2862
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2863
        goto the_end;
2864
    }
2865

    
2866
    /* parse each header line */
2867
    memset(header, 0, sizeof(*header));
2868
    /* skip to next line */
2869
    while (*p != '\n' && *p != '\0')
2870
        p++;
2871
    if (*p == '\n')
2872
        p++;
2873
    while (*p != '\0') {
2874
        p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2875
        if (!p1)
2876
            break;
2877
        p2 = p1;
2878
        if (p2 > p && p2[-1] == '\r')
2879
            p2--;
2880
        /* skip empty line */
2881
        if (p2 == p)
2882
            break;
2883
        len = p2 - p;
2884
        if (len > sizeof(line) - 1)
2885
            len = sizeof(line) - 1;
2886
        memcpy(line, p, len);
2887
        line[len] = '\0';
2888
        ff_rtsp_parse_line(header, line, NULL, NULL);
2889
        p = p1 + 1;
2890
    }
2891

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

    
2895
    if (!strcmp(cmd, "DESCRIBE"))
2896
        rtsp_cmd_describe(c, url);
2897
    else if (!strcmp(cmd, "OPTIONS"))
2898
        rtsp_cmd_options(c, url);
2899
    else if (!strcmp(cmd, "SETUP"))
2900
        rtsp_cmd_setup(c, url, header);
2901
    else if (!strcmp(cmd, "PLAY"))
2902
        rtsp_cmd_play(c, url, header);
2903
    else if (!strcmp(cmd, "PAUSE"))
2904
        rtsp_cmd_pause(c, url, header);
2905
    else if (!strcmp(cmd, "TEARDOWN"))
2906
        rtsp_cmd_teardown(c, url, header);
2907
    else
2908
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2909

    
2910
 the_end:
2911
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2912
    c->pb = NULL; /* safety */
2913
    if (len < 0) {
2914
        /* XXX: cannot do more */
2915
        return -1;
2916
    }
2917
    c->buffer_ptr = c->pb_buffer;
2918
    c->buffer_end = c->pb_buffer + len;
2919
    c->state = RTSPSTATE_SEND_REPLY;
2920
    return 0;
2921
}
2922

    
2923
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2924
                                   struct in_addr my_ip)
2925
{
2926
    AVFormatContext *avc;
2927
    AVStream *avs = NULL;
2928
    int i;
2929

    
2930
    avc =  avformat_alloc_context();
2931
    if (avc == NULL) {
2932
        return -1;
2933
    }
2934
    av_metadata_set2(&avc->metadata, "title",
2935
                     stream->title[0] ? stream->title : "No Title", 0);
2936
    avc->nb_streams = stream->nb_streams;
2937
    if (stream->is_multicast) {
2938
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2939
                 inet_ntoa(stream->multicast_ip),
2940
                 stream->multicast_port, stream->multicast_ttl);
2941
    } else {
2942
        snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2943
    }
2944

    
2945
#if !FF_API_MAX_STREAMS
2946
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2947
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2948
        goto sdp_done;
2949
#endif
2950
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2951
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2952
        goto sdp_done;
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

    
2961
 sdp_done:
2962
#if !FF_API_MAX_STREAMS
2963
    av_free(avc->streams);
2964
#endif
2965
    av_metadata_free(&avc->metadata);
2966
    av_free(avc);
2967
    av_free(avs);
2968

    
2969
    return strlen(*pbuffer);
2970
}
2971

    
2972
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2973
{
2974
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2975
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2976
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2977
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2978
    url_fprintf(c->pb, "\r\n");
2979
}
2980

    
2981
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2982
{
2983
    FFStream *stream;
2984
    char path1[1024];
2985
    const char *path;
2986
    uint8_t *content;
2987
    int content_length, len;
2988
    struct sockaddr_in my_addr;
2989

    
2990
    /* find which url is asked */
2991
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2992
    path = path1;
2993
    if (*path == '/')
2994
        path++;
2995

    
2996
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2997
        if (!stream->is_feed &&
2998
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2999
            !strcmp(path, stream->filename)) {
3000
            goto found;
3001
        }
3002
    }
3003
    /* no stream found */
3004
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3005
    return;
3006

    
3007
 found:
3008
    /* prepare the media description in sdp format */
3009

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

    
3027
static HTTPContext *find_rtp_session(const char *session_id)
3028
{
3029
    HTTPContext *c;
3030

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

    
3034
    for(c = first_http_ctx; c != NULL; c = c->next) {
3035
        if (!strcmp(c->session_id, session_id))
3036
            return c;
3037
    }
3038
    return NULL;
3039
}
3040

    
3041
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3042
{
3043
    RTSPTransportField *th;
3044
    int i;
3045

    
3046
    for(i=0;i<h->nb_transports;i++) {
3047
        th = &h->transports[i];
3048
        if (th->lower_transport == lower_transport)
3049
            return th;
3050
    }
3051
    return NULL;
3052
}
3053

    
3054
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3055
                           RTSPMessageHeader *h)
3056
{
3057
    FFStream *stream;
3058
    int stream_index, rtp_port, rtcp_port;
3059
    char buf[1024];
3060
    char path1[1024];
3061
    const char *path;
3062
    HTTPContext *rtp_c;
3063
    RTSPTransportField *th;
3064
    struct sockaddr_in dest_addr;
3065
    RTSPActionServerSetup setup;
3066

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

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

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

    
3101
    /* generate session id if needed */
3102
    if (h->session_id[0] == '\0')
3103
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3104
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3105

    
3106
    /* find rtp session, and create it if none found */
3107
    rtp_c = find_rtp_session(h->session_id);
3108
    if (!rtp_c) {
3109
        /* always prefer UDP */
3110
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3111
        if (!th) {
3112
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3113
            if (!th) {
3114
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3115
                return;
3116
            }
3117
        }
3118

    
3119
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3120
                                   th->lower_transport);
3121
        if (!rtp_c) {
3122
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3123
            return;
3124
        }
3125

    
3126
        /* open input stream */
3127
        if (open_input_stream(rtp_c, "") < 0) {
3128
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3129
            return;
3130
        }
3131
    }
3132

    
3133
    /* test if stream is OK (test needed because several SETUP needs
3134
       to be done for a given file) */
3135
    if (rtp_c->stream != stream) {
3136
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3137
        return;
3138
    }
3139

    
3140
    /* test if stream is already set up */
3141
    if (rtp_c->rtp_ctx[stream_index]) {
3142
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3143
        return;
3144
    }
3145

    
3146
    /* check transport */
3147
    th = find_transport(h, rtp_c->rtp_protocol);
3148
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3149
                th->client_port_min <= 0)) {
3150
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3151
        return;
3152
    }
3153

    
3154
    /* setup default options */
3155
    setup.transport_option[0] = '\0';
3156
    dest_addr = rtp_c->from_addr;
3157
    dest_addr.sin_port = htons(th->client_port_min);
3158

    
3159
    /* setup stream */
3160
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3161
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3162
        return;
3163
    }
3164

    
3165
    /* now everything is OK, so we can send the connection parameters */
3166
    rtsp_reply_header(c, RTSP_STATUS_OK);
3167
    /* session ID */
3168
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3169

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

    
3190

    
3191
    url_fprintf(c->pb, "\r\n");
3192
}
3193

    
3194

    
3195
/* find an rtp connection by using the session ID. Check consistency
3196
   with filename */
3197
static HTTPContext *find_rtp_session_with_url(const char *url,
3198
                                              const char *session_id)
3199
{
3200
    HTTPContext *rtp_c;
3201
    char path1[1024];
3202
    const char *path;
3203
    char buf[1024];
3204
    int s;
3205

    
3206
    rtp_c = find_rtp_session(session_id);
3207
    if (!rtp_c)
3208
        return NULL;
3209

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

    
3227
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3228
{
3229
    HTTPContext *rtp_c;
3230

    
3231
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3232
    if (!rtp_c) {
3233
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3234
        return;
3235
    }
3236

    
3237
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3238
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3239
        rtp_c->state != HTTPSTATE_READY) {
3240
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3241
        return;
3242
    }
3243

    
3244
    rtp_c->state = HTTPSTATE_SEND_DATA;
3245

    
3246
    /* now everything is OK, so we can send the connection parameters */
3247
    rtsp_reply_header(c, RTSP_STATUS_OK);
3248
    /* session ID */
3249
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3250
    url_fprintf(c->pb, "\r\n");
3251
}
3252

    
3253
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3254
{
3255
    HTTPContext *rtp_c;
3256

    
3257
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3258
    if (!rtp_c) {
3259
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3260
        return;
3261
    }
3262

    
3263
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3264
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3265
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3266
        return;
3267
    }
3268

    
3269
    rtp_c->state = HTTPSTATE_READY;
3270
    rtp_c->first_pts = AV_NOPTS_VALUE;
3271
    /* now everything is OK, so we can send the connection parameters */
3272
    rtsp_reply_header(c, RTSP_STATUS_OK);
3273
    /* session ID */
3274
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3275
    url_fprintf(c->pb, "\r\n");
3276
}
3277

    
3278
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3279
{
3280
    HTTPContext *rtp_c;
3281
    char session_id[32];
3282

    
3283
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3284
    if (!rtp_c) {
3285
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3286
        return;
3287
    }
3288

    
3289
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3290

    
3291
    /* abort the session */
3292
    close_connection(rtp_c);
3293

    
3294
    /* now everything is OK, so we can send the connection parameters */
3295
    rtsp_reply_header(c, RTSP_STATUS_OK);
3296
    /* session ID */
3297
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3298
    url_fprintf(c->pb, "\r\n");
3299
}
3300

    
3301

    
3302
/********************************************************************/
3303
/* RTP handling */
3304

    
3305
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3306
                                       FFStream *stream, const char *session_id,
3307
                                       enum RTSPLowerTransport rtp_protocol)
3308
{
3309
    HTTPContext *c = NULL;
3310
    const char *proto_str;
3311

    
3312
    /* XXX: should output a warning page when coming
3313
       close to the connection limit */
3314
    if (nb_connections >= nb_max_connections)
3315
        goto fail;
3316

    
3317
    /* add a new connection */
3318
    c = av_mallocz(sizeof(HTTPContext));
3319
    if (!c)
3320
        goto fail;
3321

    
3322
    c->fd = -1;
3323
    c->poll_entry = NULL;
3324
    c->from_addr = *from_addr;
3325
    c->buffer_size = IOBUFFER_INIT_SIZE;
3326
    c->buffer = av_malloc(c->buffer_size);
3327
    if (!c->buffer)
3328
        goto fail;
3329
    nb_connections++;
3330
    c->stream = stream;
3331
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3332
    c->state = HTTPSTATE_READY;
3333
    c->is_packetized = 1;
3334
    c->rtp_protocol = rtp_protocol;
3335

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

    
3354
    current_bandwidth += stream->bandwidth;
3355

    
3356
    c->next = first_http_ctx;
3357
    first_http_ctx = c;
3358
    return c;
3359

    
3360
 fail:
3361
    if (c) {
3362
        av_free(c->buffer);
3363
        av_free(c);
3364
    }
3365
    return NULL;
3366
}
3367

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

    
3382
    /* now we can open the relevant output stream */
3383
    ctx = avformat_alloc_context();
3384
    if (!ctx)
3385
        return -1;
3386
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3387

    
3388
    st = av_mallocz(sizeof(AVStream));
3389
    if (!st)
3390
        goto fail;
3391
    ctx->nb_streams = 1;
3392
    ctx->streams[0] = st;
3393

    
3394
    if (!c->stream->feed ||
3395
        c->stream->feed == c->stream)
3396
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3397
    else
3398
        memcpy(st,
3399
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3400
               sizeof(AVStream));
3401
    st->priv_data = NULL;
3402

    
3403
    /* build destination RTP address */
3404
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3405

    
3406
    switch(c->rtp_protocol) {
3407
    case RTSP_LOWER_TRANSPORT_UDP:
3408
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3409
        /* RTP/UDP case */
3410

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

    
3425
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3426
            goto fail;
3427
        c->rtp_handles[stream_index] = h;
3428
        max_packet_size = url_get_max_packet_size(h);
3429
        break;
3430
    case RTSP_LOWER_TRANSPORT_TCP:
3431
        /* RTP/TCP case */
3432
        c->rtsp_c = rtsp_c;
3433
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3434
        break;
3435
    default:
3436
        goto fail;
3437
    }
3438

    
3439
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3440
             ipaddr, ntohs(dest_addr->sin_port),
3441
             c->stream->filename, stream_index, c->protocol);
3442

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

    
3459
    c->rtp_ctx[stream_index] = ctx;
3460
    return 0;
3461
}
3462

    
3463
/********************************************************************/
3464
/* ffserver initialization */
3465

    
3466
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3467
{
3468
    AVStream *fst;
3469

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

    
3495
/* return the stream number in the feed */
3496
static int add_av_stream(FFStream *feed, AVStream *st)
3497
{
3498
    AVStream *fst;
3499
    AVCodecContext *av, *av1;
3500
    int i;
3501

    
3502
    av = st->codec;
3503
    for(i=0;i<feed->nb_streams;i++) {
3504
        st = feed->streams[i];
3505
        av1 = st->codec;
3506
        if (av1->codec_id == av->codec_id &&
3507
            av1->codec_type == av->codec_type &&
3508
            av1->bit_rate == av->bit_rate) {
3509

    
3510
            switch(av->codec_type) {
3511
            case AVMEDIA_TYPE_AUDIO:
3512
                if (av1->channels == av->channels &&
3513
                    av1->sample_rate == av->sample_rate)
3514
                    goto found;
3515
                break;
3516
            case AVMEDIA_TYPE_VIDEO:
3517
                if (av1->width == av->width &&
3518
                    av1->height == av->height &&
3519
                    av1->time_base.den == av->time_base.den &&
3520
                    av1->time_base.num == av->time_base.num &&
3521
                    av1->gop_size == av->gop_size)
3522
                    goto found;
3523
                break;
3524
            default:
3525
                abort();
3526
            }
3527
        }
3528
    }
3529

    
3530
    fst = add_av_stream1(feed, av, 0);
3531
    if (!fst)
3532
        return -1;
3533
    return feed->nb_streams - 1;
3534
 found:
3535
    return i;
3536
}
3537

    
3538
static void remove_stream(FFStream *stream)
3539
{
3540
    FFStream **ps;
3541
    ps = &first_stream;
3542
    while (*ps != NULL) {
3543
        if (*ps == stream)
3544
            *ps = (*ps)->next;
3545
        else
3546
            ps = &(*ps)->next;
3547
    }
3548
}
3549

    
3550
/* specific mpeg4 handling : we extract the raw parameters */
3551
static void extract_mpeg4_header(AVFormatContext *infile)
3552
{
3553
    int mpeg4_count, i, size;
3554
    AVPacket pkt;
3555
    AVStream *st;
3556
    const uint8_t *p;
3557

    
3558
    mpeg4_count = 0;
3559
    for(i=0;i<infile->nb_streams;i++) {
3560
        st = infile->streams[i];
3561
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3562
            st->codec->extradata_size == 0) {
3563
            mpeg4_count++;
3564
        }
3565
    }
3566
    if (!mpeg4_count)
3567
        return;
3568

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

    
3599
/* compute the needed AVStream for each file */
3600
static void build_file_streams(void)
3601
{
3602
    FFStream *stream, *stream_next;
3603
    AVFormatContext *infile;
3604
    int i, ret;
3605

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

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

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

    
3643
                av_close_input_file(infile);
3644
            }
3645
        }
3646
    }
3647
}
3648

    
3649
/* compute the needed AVStream for each feed */
3650
static void build_feed_streams(void)
3651
{
3652
    FFStream *stream, *feed;
3653
    int i;
3654

    
3655
    /* gather all streams */
3656
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3657
        feed = stream->feed;
3658
        if (feed) {
3659
            if (!stream->is_feed) {
3660
                /* we handle a stream coming from a feed */
3661
                for(i=0;i<stream->nb_streams;i++)
3662
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3663
            }
3664
        }
3665
    }
3666

    
3667
    /* gather all streams */
3668
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3669
        feed = stream->feed;
3670
        if (feed) {
3671
            if (stream->is_feed) {
3672
                for(i=0;i<stream->nb_streams;i++)
3673
                    stream->feed_streams[i] = i;
3674
            }
3675
        }
3676
    }
3677

    
3678
    /* create feed files if needed */
3679
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3680
        int fd;
3681

    
3682
        if (url_exist(feed->feed_filename)) {
3683
            /* See if it matches */
3684
            AVFormatContext *s;
3685
            int matches = 0;
3686

    
3687
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3688
                /* Now see if it matches */
3689
                if (s->nb_streams == feed->nb_streams) {
3690
                    matches = 1;
3691
                    for(i=0;i<s->nb_streams;i++) {
3692
                        AVStream *sf, *ss;
3693
                        sf = feed->streams[i];
3694
                        ss = s->streams[i];
3695

    
3696
                        if (sf->index != ss->index ||
3697
                            sf->id != ss->id) {
3698
                            http_log("Index & Id do not match for stream %d (%s)\n",
3699
                                   i, feed->feed_filename);
3700
                            matches = 0;
3701
                        } else {
3702
                            AVCodecContext *ccf, *ccs;
3703

    
3704
                            ccf = sf->codec;
3705
                            ccs = ss->codec;
3706
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3707

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

    
3741
                av_close_input_file(s);
3742
            } else
3743
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3744
                        feed->feed_filename);
3745

    
3746
            if (!matches) {
3747
                if (feed->readonly) {
3748
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3749
                        feed->feed_filename);
3750
                    exit(1);
3751
                }
3752
                unlink(feed->feed_filename);
3753
            }
3754
        }
3755
        if (!url_exist(feed->feed_filename)) {
3756
            AVFormatContext s1 = {0}, *s = &s1;
3757

    
3758
            if (feed->readonly) {
3759
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3760
                    feed->feed_filename);
3761
                exit(1);
3762
            }
3763

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

    
3794
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3795
        feed->feed_size = lseek(fd, 0, SEEK_END);
3796
        /* ensure that we do not wrap before the end of file */
3797
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3798
            feed->feed_max_size = feed->feed_size;
3799

    
3800
        close(fd);
3801
    }
3802
}
3803

    
3804
/* compute the bandwidth used by each stream */
3805
static void compute_bandwidth(void)
3806
{
3807
    unsigned bandwidth;
3808
    int i;
3809
    FFStream *stream;
3810

    
3811
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3812
        bandwidth = 0;
3813
        for(i=0;i<stream->nb_streams;i++) {
3814
            AVStream *st = stream->streams[i];
3815
            switch(st->codec->codec_type) {
3816
            case AVMEDIA_TYPE_AUDIO:
3817
            case AVMEDIA_TYPE_VIDEO:
3818
                bandwidth += st->codec->bit_rate;
3819
                break;
3820
            default:
3821
                break;
3822
            }
3823
        }
3824
        stream->bandwidth = (bandwidth + 999) / 1000;
3825
    }
3826
}
3827

    
3828
/* add a codec and set the default parameters */
3829
static void add_codec(FFStream *stream, AVCodecContext *av)
3830
{
3831
    AVStream *st;
3832

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

    
3867
        if (!av->nsse_weight)
3868
            av->nsse_weight = 8;
3869

    
3870
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3871
        if (!av->me_method)
3872
            av->me_method = ME_EPZS;
3873
        av->rc_buffer_aggressivity = 1.0;
3874

    
3875
        if (!av->rc_eq)
3876
            av->rc_eq = "tex^qComp";
3877
        if (!av->i_quant_factor)
3878
            av->i_quant_factor = -0.8;
3879
        if (!av->b_quant_factor)
3880
            av->b_quant_factor = 1.25;
3881
        if (!av->b_quant_offset)
3882
            av->b_quant_offset = 1.25;
3883
        if (!av->rc_max_rate)
3884
            av->rc_max_rate = av->bit_rate * 2;
3885

    
3886
        if (av->rc_max_rate && !av->rc_buffer_size) {
3887
            av->rc_buffer_size = av->rc_max_rate;
3888
        }
3889

    
3890

    
3891
        break;
3892
    default:
3893
        abort();
3894
    }
3895

    
3896
    st = av_mallocz(sizeof(AVStream));
3897
    if (!st)
3898
        return;
3899
    st->codec = avcodec_alloc_context();
3900
    stream->streams[stream->nb_streams++] = st;
3901
    memcpy(st->codec, av, sizeof(AVCodecContext));
3902
}
3903

    
3904
static enum CodecID opt_audio_codec(const char *arg)
3905
{
3906
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3907

    
3908
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3909
        return CODEC_ID_NONE;
3910

    
3911
    return p->id;
3912
}
3913

    
3914
static enum CodecID opt_video_codec(const char *arg)
3915
{
3916
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3917

    
3918
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3919
        return CODEC_ID_NONE;
3920

    
3921
    return p->id;
3922
}
3923

    
3924
/* simplistic plugin support */
3925

    
3926
#if HAVE_DLOPEN
3927
static void load_module(const char *filename)
3928
{
3929
    void *dll;
3930
    void (*init_func)(void);
3931
    dll = dlopen(filename, RTLD_NOW);
3932
    if (!dll) {
3933
        fprintf(stderr, "Could not load module '%s' - %s\n",
3934
                filename, dlerror());
3935
        return;
3936
    }
3937

    
3938
    init_func = dlsym(dll, "ffserver_module_init");
3939
    if (!init_func) {
3940
        fprintf(stderr,
3941
                "%s: init function 'ffserver_module_init()' not found\n",
3942
                filename);
3943
        dlclose(dll);
3944
    }
3945

    
3946
    init_func();
3947
}
3948
#endif
3949

    
3950
static int ffserver_opt_default(const char *opt, const char *arg,
3951
                       AVCodecContext *avctx, int type)
3952
{
3953
    int ret = 0;
3954
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3955
    if(o)
3956
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3957
    return ret;
3958
}
3959

    
3960
static int ffserver_opt_preset(const char *arg,
3961
                       AVCodecContext *avctx, int type,
3962
                       enum CodecID *audio_id, enum CodecID *video_id)
3963
{
3964
    FILE *f=NULL;
3965
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3966
    int ret = 0;
3967
    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3968

    
3969
    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3970
                              codec ? codec->name : NULL))) {
3971
        fprintf(stderr, "File for preset '%s' not found\n", arg);
3972
        return 1;
3973
    }
3974

    
3975
    while(!feof(f)){
3976
        int e= fscanf(f, "%999[^\n]\n", line) - 1;
3977
        if(line[0] == '#' && !e)
3978
            continue;
3979
        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3980
        if(e){
3981
            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3982
            ret = 1;
3983
            break;
3984
        }
3985
        if(!strcmp(tmp, "acodec")){
3986
            *audio_id = opt_audio_codec(tmp2);
3987
        }else if(!strcmp(tmp, "vcodec")){
3988
            *video_id = opt_video_codec(tmp2);
3989
        }else if(!strcmp(tmp, "scodec")){
3990
            /* opt_subtitle_codec(tmp2); */
3991
        }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3992
            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3993
            ret = 1;
3994
            break;
3995
        }
3996
    }
3997

    
3998
    fclose(f);
3999

    
4000
    return ret;
4001
}
4002

    
4003
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4004
                                             const char *mime_type)
4005
{
4006
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4007

    
4008
    if (fmt) {
4009
        AVOutputFormat *stream_fmt;
4010
        char stream_format_name[64];
4011

    
4012
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4013
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4014

    
4015
        if (stream_fmt)
4016
            fmt = stream_fmt;
4017
    }
4018

    
4019
    return fmt;
4020
}
4021

    
4022
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4023
{
4024
    va_list vl;
4025
    va_start(vl, fmt);
4026
    fprintf(stderr, "%s:%d: ", filename, line_num);
4027
    vfprintf(stderr, fmt, vl);
4028
    va_end(vl);
4029

    
4030
    (*errors)++;
4031
}
4032

    
4033
static int parse_ffconfig(const char *filename)
4034
{
4035
    FILE *f;
4036
    char line[1024];
4037
    char cmd[64];
4038
    char arg[1024];
4039
    const char *p;
4040
    int val, errors, line_num;
4041
    FFStream **last_stream, *stream, *redirect;
4042
    FFStream **last_feed, *feed, *s;
4043
    AVCodecContext audio_enc, video_enc;
4044
    enum CodecID audio_id, video_id;
4045

    
4046
    f = fopen(filename, "r");
4047
    if (!f) {
4048
        perror(filename);
4049
        return -1;
4050
    }
4051

    
4052
    errors = 0;
4053
    line_num = 0;
4054
    first_stream = NULL;
4055
    last_stream = &first_stream;
4056
    first_feed = NULL;
4057
    last_feed = &first_feed;
4058
    stream = NULL;
4059
    feed = NULL;
4060
    redirect = NULL;
4061
    audio_id = CODEC_ID_NONE;
4062
    video_id = CODEC_ID_NONE;
4063

    
4064
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4065
    for(;;) {
4066
        if (fgets(line, sizeof(line), f) == NULL)
4067
            break;
4068
        line_num++;
4069
        p = line;
4070
        while (isspace(*p))
4071
            p++;
4072
        if (*p == '\0' || *p == '#')
4073
            continue;
4074

    
4075
        get_arg(cmd, sizeof(cmd), &p);
4076

    
4077
        if (!strcasecmp(cmd, "Port")) {
4078
            get_arg(arg, sizeof(arg), &p);
4079
            val = atoi(arg);
4080
            if (val < 1 || val > 65536) {
4081
                ERROR("Invalid_port: %s\n", arg);
4082
            }
4083
            my_http_addr.sin_port = htons(val);
4084
        } else if (!strcasecmp(cmd, "BindAddress")) {
4085
            get_arg(arg, sizeof(arg), &p);
4086
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4087
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4088
            }
4089
        } else if (!strcasecmp(cmd, "NoDaemon")) {
4090
            ffserver_daemon = 0;
4091
        } else if (!strcasecmp(cmd, "RTSPPort")) {
4092
            get_arg(arg, sizeof(arg), &p);
4093
            val = atoi(arg);
4094
            if (val < 1 || val > 65536) {
4095
                ERROR("%s:%d: Invalid port: %s\n", arg);
4096
            }
4097
            my_rtsp_addr.sin_port = htons(atoi(arg));
4098
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4099
            get_arg(arg, sizeof(arg), &p);
4100
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4101
                ERROR("Invalid host/IP address: %s\n", arg);
4102
            }
4103
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4104
            get_arg(arg, sizeof(arg), &p);
4105
            val = atoi(arg);
4106
            if (val < 1 || val > 65536) {
4107
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4108
            }
4109
            nb_max_http_connections = val;
4110
        } else if (!strcasecmp(cmd, "MaxClients")) {
4111
            get_arg(arg, sizeof(arg), &p);
4112
            val = atoi(arg);
4113
            if (val < 1 || val > nb_max_http_connections) {
4114
                ERROR("Invalid MaxClients: %s\n", arg);
4115
            } else {
4116
                nb_max_connections = val;
4117
            }
4118
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4119
            int64_t llval;
4120
            get_arg(arg, sizeof(arg), &p);
4121
            llval = atoll(arg);
4122
            if (llval < 10 || llval > 10000000) {
4123
                ERROR("Invalid MaxBandwidth: %s\n", arg);
4124
            } else
4125
                max_bandwidth = llval;
4126
        } else if (!strcasecmp(cmd, "CustomLog")) {
4127
            if (!ffserver_debug)
4128
                get_arg(logfilename, sizeof(logfilename), &p);
4129
        } else if (!strcasecmp(cmd, "<Feed")) {
4130
            /*********************************************/
4131
            /* Feed related options */
4132
            char *q;
4133
            if (stream || feed) {
4134
                ERROR("Already in a tag\n");
4135
            } else {
4136
                feed = av_mallocz(sizeof(FFStream));
4137
                get_arg(feed->filename, sizeof(feed->filename), &p);
4138
                q = strrchr(feed->filename, '>');
4139
                if (*q)
4140
                    *q = '\0';
4141

    
4142
                for (s = first_feed; s; s = s->next) {
4143
                    if (!strcmp(feed->filename, s->filename)) {
4144
                        ERROR("Feed '%s' already registered\n", s->filename);
4145
                    }
4146
                }
4147

    
4148
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4149
                /* defaut feed file */
4150
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4151
                         "/tmp/%s.ffm", feed->filename);
4152
                feed->feed_max_size = 5 * 1024 * 1024;
4153
                feed->is_feed = 1;
4154
                feed->feed = feed; /* self feeding :-) */
4155

    
4156
                /* add in stream list */
4157
                *last_stream = feed;
4158
                last_stream = &feed->next;
4159
                /* add in feed list */
4160
                *last_feed = feed;
4161
                last_feed = &feed->next_feed;
4162
            }
4163
        } else if (!strcasecmp(cmd, "Launch")) {
4164
            if (feed) {
4165
                int i;
4166

    
4167
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4168

    
4169
                for (i = 0; i < 62; i++) {
4170
                    get_arg(arg, sizeof(arg), &p);
4171
                    if (!arg[0])
4172
                        break;
4173

    
4174
                    feed->child_argv[i] = av_strdup(arg);
4175
                }
4176

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

    
4179
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4180
                    "http://%s:%d/%s",
4181
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4182
                    inet_ntoa(my_http_addr.sin_addr),
4183
                    ntohs(my_http_addr.sin_port), feed->filename);
4184
            }
4185
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4186
            if (feed) {
4187
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4188
                feed->readonly = 1;
4189
            } else if (stream) {
4190
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4191
            }
4192
        } else if (!strcasecmp(cmd, "File")) {
4193
            if (feed) {
4194
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4195
            } else if (stream)
4196
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4197
        } else if (!strcasecmp(cmd, "Truncate")) {
4198
            if (feed) {
4199
                get_arg(arg, sizeof(arg), &p);
4200
                feed->truncate = strtod(arg, NULL);
4201
            }
4202
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4203
            if (feed) {
4204
                char *p1;
4205
                double fsize;
4206

    
4207
                get_arg(arg, sizeof(arg), &p);
4208
                p1 = arg;
4209
                fsize = strtod(p1, &p1);
4210
                switch(toupper(*p1)) {
4211
                case 'K':
4212
                    fsize *= 1024;
4213
                    break;
4214
                case 'M':
4215
                    fsize *= 1024 * 1024;
4216
                    break;
4217
                case 'G':
4218
                    fsize *= 1024 * 1024 * 1024;
4219
                    break;
4220
                }
4221
                feed->feed_max_size = (int64_t)fsize;
4222
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4223
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4224
                }
4225
            }
4226
        } else if (!strcasecmp(cmd, "</Feed>")) {
4227
            if (!feed) {
4228
                ERROR("No corresponding <Feed> for </Feed>\n");
4229
            }
4230
            feed = NULL;
4231
        } else if (!strcasecmp(cmd, "<Stream")) {
4232
            /*********************************************/
4233
            /* Stream related options */
4234
            char *q;
4235
            if (stream || feed) {
4236
                ERROR("Already in a tag\n");
4237
            } else {
4238
                FFStream *s;
4239
                stream = av_mallocz(sizeof(FFStream));
4240
                get_arg(stream->filename, sizeof(stream->filename), &p);
4241
                q = strrchr(stream->filename, '>');
4242
                if (*q)
4243
                    *q = '\0';
4244

    
4245
                for (s = first_stream; s; s = s->next) {
4246
                    if (!strcmp(stream->filename, s->filename)) {
4247
                        ERROR("Stream '%s' already registered\n", s->filename);
4248
                    }
4249
                }
4250

    
4251
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4252
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4253
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4254
                audio_id = CODEC_ID_NONE;
4255
                video_id = CODEC_ID_NONE;
4256
                if (stream->fmt) {
4257
                    audio_id = stream->fmt->audio_codec;
4258
                    video_id = stream->fmt->video_codec;
4259
                }
4260

    
4261
                *last_stream = stream;
4262
                last_stream = &stream->next;
4263
            }
4264
        } else if (!strcasecmp(cmd, "Feed")) {
4265
            get_arg(arg, sizeof(arg), &p);
4266
            if (stream) {
4267
                FFStream *sfeed;
4268

    
4269
                sfeed = first_feed;
4270
                while (sfeed != NULL) {
4271
                    if (!strcmp(sfeed->filename, arg))
4272
                        break;
4273
                    sfeed = sfeed->next_feed;
4274
                }
4275
                if (!sfeed)
4276
                    ERROR("feed '%s' not defined\n", arg);
4277
                else
4278
                    stream->feed = sfeed;
4279
            }
4280
        } else if (!strcasecmp(cmd, "Format")) {
4281
            get_arg(arg, sizeof(arg), &p);
4282
            if (stream) {
4283
                if (!strcmp(arg, "status")) {
4284
                    stream->stream_type = STREAM_TYPE_STATUS;
4285
                    stream->fmt = NULL;
4286
                } else {
4287
                    stream->stream_type = STREAM_TYPE_LIVE;
4288
                    /* jpeg cannot be used here, so use single frame jpeg */
4289
                    if (!strcmp(arg, "jpeg"))
4290
                        strcpy(arg, "mjpeg");
4291
                    stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4292
                    if (!stream->fmt) {
4293
                        ERROR("Unknown Format: %s\n", arg);
4294
                    }
4295
                }
4296
                if (stream->fmt) {
4297
                    audio_id = stream->fmt->audio_codec;
4298
                    video_id = stream->fmt->video_codec;
4299
                }
4300
            }
4301
        } else if (!strcasecmp(cmd, "InputFormat")) {
4302
            get_arg(arg, sizeof(arg), &p);
4303
            if (stream) {
4304
                stream->ifmt = av_find_input_format(arg);
4305
                if (!stream->ifmt) {
4306
                    ERROR("Unknown input format: %s\n", arg);
4307
                }
4308
            }
4309
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4310
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4311
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4312
            } else {
4313
                ERROR("FaviconURL only permitted for status streams\n");
4314
            }
4315
        } else if (!strcasecmp(cmd, "Author")) {
4316
            if (stream)
4317
                get_arg(stream->author, sizeof(stream->author), &p);
4318
        } else if (!strcasecmp(cmd, "Comment")) {
4319
            if (stream)
4320
                get_arg(stream->comment, sizeof(stream->comment), &p);
4321
        } else if (!strcasecmp(cmd, "Copyright")) {
4322
            if (stream)
4323
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4324
        } else if (!strcasecmp(cmd, "Title")) {
4325
            if (stream)
4326
                get_arg(stream->title, sizeof(stream->title), &p);
4327
        } else if (!strcasecmp(cmd, "Preroll")) {
4328
            get_arg(arg, sizeof(arg), &p);
4329
            if (stream)
4330
                stream->prebuffer = atof(arg) * 1000;
4331
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4332
            if (stream)
4333
                stream->send_on_key = 1;
4334
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4335
            get_arg(arg, sizeof(arg), &p);
4336
            audio_id = opt_audio_codec(arg);
4337
            if (audio_id == CODEC_ID_NONE) {
4338
                ERROR("Unknown AudioCodec: %s\n", arg);
4339
            }
4340
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4341
            get_arg(arg, sizeof(arg), &p);
4342
            video_id = opt_video_codec(arg);
4343
            if (video_id == CODEC_ID_NONE) {
4344
                ERROR("Unknown VideoCodec: %s\n", arg);
4345
            }
4346
        } else if (!strcasecmp(cmd, "MaxTime")) {
4347
            get_arg(arg, sizeof(arg), &p);
4348
            if (stream)
4349
                stream->max_time = atof(arg) * 1000;
4350
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4351
            get_arg(arg, sizeof(arg), &p);
4352
            if (stream)
4353
                audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4354
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4355
            get_arg(arg, sizeof(arg), &p);
4356
            if (stream)
4357
                audio_enc.channels = atoi(arg);
4358
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4359
            get_arg(arg, sizeof(arg), &p);
4360
            if (stream)
4361
                audio_enc.sample_rate = atoi(arg);
4362
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4363
            get_arg(arg, sizeof(arg), &p);
4364
            if (stream) {
4365
//                audio_enc.quality = atof(arg) * 1000;
4366
            }
4367
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4368
            if (stream) {
4369
                int minrate, maxrate;
4370

    
4371
                get_arg(arg, sizeof(arg), &p);
4372

    
4373
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4374
                    video_enc.rc_min_rate = minrate * 1000;
4375
                    video_enc.rc_max_rate = maxrate * 1000;
4376
                } else {
4377
                    ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4378
                }
4379
            }
4380
        } else if (!strcasecmp(cmd, "Debug")) {
4381
            if (stream) {
4382
                get_arg(arg, sizeof(arg), &p);
4383
                video_enc.debug = strtol(arg,0,0);
4384
            }
4385
        } else if (!strcasecmp(cmd, "Strict")) {
4386
            if (stream) {
4387
                get_arg(arg, sizeof(arg), &p);
4388
                video_enc.strict_std_compliance = atoi(arg);
4389
            }
4390
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4391
            if (stream) {
4392
                get_arg(arg, sizeof(arg), &p);
4393
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4394
            }
4395
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4396
            if (stream) {
4397
                get_arg(arg, sizeof(arg), &p);
4398
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4399
            }
4400
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4401
            get_arg(arg, sizeof(arg), &p);
4402
            if (stream) {
4403
                video_enc.bit_rate = atoi(arg) * 1000;
4404
            }
4405
        } else if (!strcasecmp(cmd, "VideoSize")) {
4406
            get_arg(arg, sizeof(arg), &p);
4407
            if (stream) {
4408
                av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4409
                if ((video_enc.width % 16) != 0 ||
4410
                    (video_enc.height % 16) != 0) {
4411
                    ERROR("Image size must be a multiple of 16\n");
4412
                }
4413
            }
4414
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4415
            get_arg(arg, sizeof(arg), &p);
4416
            if (stream) {
4417
                AVRational frame_rate;
4418
                if (av_parse_video_rate(&frame_rate, arg) < 0) {
4419
                    ERROR("Incorrect frame rate: %s\n", arg);
4420
                } else {
4421
                    video_enc.time_base.num = frame_rate.den;
4422
                    video_enc.time_base.den = frame_rate.num;
4423
                }
4424
            }
4425
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4426
            get_arg(arg, sizeof(arg), &p);
4427
            if (stream)
4428
                video_enc.gop_size = atoi(arg);
4429
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4430
            if (stream)
4431
                video_enc.gop_size = 1;
4432
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4433
            if (stream)
4434
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4435
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4436
            if (stream) {
4437
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4438
                video_enc.flags |= CODEC_FLAG_4MV;
4439
            }
4440
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4441
                   !strcasecmp(cmd, "AVOptionAudio")) {
4442
            char arg2[1024];
4443
            AVCodecContext *avctx;
4444
            int type;
4445
            get_arg(arg, sizeof(arg), &p);
4446
            get_arg(arg2, sizeof(arg2), &p);
4447
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4448
                avctx = &video_enc;
4449
                type = AV_OPT_FLAG_VIDEO_PARAM;
4450
            } else {
4451
                avctx = &audio_enc;
4452
                type = AV_OPT_FLAG_AUDIO_PARAM;
4453
            }
4454
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4455
                ERROR("AVOption error: %s %s\n", arg, arg2);
4456
            }
4457
        } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4458
                   !strcasecmp(cmd, "AVPresetAudio")) {
4459
            AVCodecContext *avctx;
4460
            int type;
4461
            get_arg(arg, sizeof(arg), &p);
4462
            if (!strcasecmp(cmd, "AVPresetVideo")) {
4463
                avctx = &video_enc;
4464
                video_enc.codec_id = video_id;
4465
                type = AV_OPT_FLAG_VIDEO_PARAM;
4466
            } else {
4467
                avctx = &audio_enc;
4468
                audio_enc.codec_id = audio_id;
4469
                type = AV_OPT_FLAG_AUDIO_PARAM;
4470
            }
4471
            if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4472
                ERROR("AVPreset error: %s\n", arg);
4473
            }
4474
        } else if (!strcasecmp(cmd, "VideoTag")) {
4475
            get_arg(arg, sizeof(arg), &p);
4476
            if ((strlen(arg) == 4) && stream)
4477
                video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4478
        } else if (!strcasecmp(cmd, "BitExact")) {
4479
            if (stream)
4480
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4481
        } else if (!strcasecmp(cmd, "DctFastint")) {
4482
            if (stream)
4483
                video_enc.dct_algo  = FF_DCT_FASTINT;
4484
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4485
            if (stream)
4486
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4487
        } else if (!strcasecmp(cmd, "Qscale")) {
4488
            get_arg(arg, sizeof(arg), &p);
4489
            if (stream) {
4490
                video_enc.flags |= CODEC_FLAG_QSCALE;
4491
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4492
            }
4493
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4494
            get_arg(arg, sizeof(arg), &p);
4495
            if (stream) {
4496
                video_enc.max_qdiff = atoi(arg);
4497
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4498
                    ERROR("VideoQDiff out of range\n");
4499
                }
4500
            }
4501
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4502
            get_arg(arg, sizeof(arg), &p);
4503
            if (stream) {
4504
                video_enc.qmax = atoi(arg);
4505
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4506
                    ERROR("VideoQMax out of range\n");
4507
                }
4508
            }
4509
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4510
            get_arg(arg, sizeof(arg), &p);
4511
            if (stream) {
4512
                video_enc.qmin = atoi(arg);
4513
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4514
                    ERROR("VideoQMin out of range\n");
4515
                }
4516
            }
4517
        } else if (!strcasecmp(cmd, "LumaElim")) {
4518
            get_arg(arg, sizeof(arg), &p);
4519
            if (stream)
4520
                video_enc.luma_elim_threshold = atoi(arg);
4521
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4522
            get_arg(arg, sizeof(arg), &p);
4523
            if (stream)
4524
                video_enc.chroma_elim_threshold = atoi(arg);
4525
        } else if (!strcasecmp(cmd, "LumiMask")) {
4526
            get_arg(arg, sizeof(arg), &p);
4527
            if (stream)
4528
                video_enc.lumi_masking = atof(arg);
4529
        } else if (!strcasecmp(cmd, "DarkMask")) {
4530
            get_arg(arg, sizeof(arg), &p);
4531
            if (stream)
4532
                video_enc.dark_masking = atof(arg);
4533
        } else if (!strcasecmp(cmd, "NoVideo")) {
4534
            video_id = CODEC_ID_NONE;
4535
        } else if (!strcasecmp(cmd, "NoAudio")) {
4536
            audio_id = CODEC_ID_NONE;
4537
        } else if (!strcasecmp(cmd, "ACL")) {
4538
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4539
        } else if (!strcasecmp(cmd, "DynamicACL")) {
4540
            if (stream) {
4541
                get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4542
            }
4543
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4544
            get_arg(arg, sizeof(arg), &p);
4545
            if (stream) {
4546
                av_freep(&stream->rtsp_option);
4547
                stream->rtsp_option = av_strdup(arg);
4548
            }
4549
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4550
            get_arg(arg, sizeof(arg), &p);
4551
            if (stream) {
4552
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4553
                    ERROR("Invalid host/IP address: %s\n", arg);
4554
                }
4555
                stream->is_multicast = 1;
4556
                stream->loop = 1; /* default is looping */
4557
            }
4558
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4559
            get_arg(arg, sizeof(arg), &p);
4560
            if (stream)
4561
                stream->multicast_port = atoi(arg);
4562
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4563
            get_arg(arg, sizeof(arg), &p);
4564
            if (stream)
4565
                stream->multicast_ttl = atoi(arg);
4566
        } else if (!strcasecmp(cmd, "NoLoop")) {
4567
            if (stream)
4568
                stream->loop = 0;
4569
        } else if (!strcasecmp(cmd, "</Stream>")) {
4570
            if (!stream) {
4571
                ERROR("No corresponding <Stream> for </Stream>\n");
4572
            } else {
4573
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4574
                    if (audio_id != CODEC_ID_NONE) {
4575
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4576
                        audio_enc.codec_id = audio_id;
4577
                        add_codec(stream, &audio_enc);
4578
                    }
4579
                    if (video_id != CODEC_ID_NONE) {
4580
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4581
                        video_enc.codec_id = video_id;
4582
                        add_codec(stream, &video_enc);
4583
                    }
4584
                }
4585
                stream = NULL;
4586
            }
4587
        } else if (!strcasecmp(cmd, "<Redirect")) {
4588
            /*********************************************/
4589
            char *q;
4590
            if (stream || feed || redirect) {
4591
                ERROR("Already in a tag\n");
4592
            } else {
4593
                redirect = av_mallocz(sizeof(FFStream));
4594
                *last_stream = redirect;
4595
                last_stream = &redirect->next;
4596

    
4597
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4598
                q = strrchr(redirect->filename, '>');
4599
                if (*q)
4600
                    *q = '\0';
4601
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4602
            }
4603
        } else if (!strcasecmp(cmd, "URL")) {
4604
            if (redirect)
4605
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4606
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4607
            if (!redirect) {
4608
                ERROR("No corresponding <Redirect> for </Redirect>\n");
4609
            } else {
4610
                if (!redirect->feed_filename[0]) {
4611
                    ERROR("No URL found for <Redirect>\n");
4612
                }
4613
                redirect = NULL;
4614
            }
4615
        } else if (!strcasecmp(cmd, "LoadModule")) {
4616
            get_arg(arg, sizeof(arg), &p);
4617
#if HAVE_DLOPEN
4618
            load_module(arg);
4619
#else
4620
            ERROR("Module support not compiled into this version: '%s'\n", arg);
4621
#endif
4622
        } else {
4623
            ERROR("Incorrect keyword: '%s'\n", cmd);
4624
        }
4625
    }
4626
#undef ERROR
4627

    
4628
    fclose(f);
4629
    if (errors)
4630
        return -1;
4631
    else
4632
        return 0;
4633
}
4634

    
4635
static void handle_child_exit(int sig)
4636
{
4637
    pid_t pid;
4638
    int status;
4639

    
4640
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4641
        FFStream *feed;
4642

    
4643
        for (feed = first_feed; feed; feed = feed->next) {
4644
            if (feed->pid == pid) {
4645
                int uptime = time(0) - feed->pid_start;
4646

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

    
4650
                if (uptime < 30)
4651
                    /* Turn off any more restarts */
4652
                    feed->child_argv = 0;
4653
            }
4654
        }
4655
    }
4656

    
4657
    need_to_start_children = 1;
4658
}
4659

    
4660
static void opt_debug(void)
4661
{
4662
    ffserver_debug = 1;
4663
    ffserver_daemon = 0;
4664
    logfilename[0] = '-';
4665
}
4666

    
4667
static void show_help(void)
4668
{
4669
    printf("usage: ffserver [options]\n"
4670
           "Hyper fast multi format Audio/Video streaming server\n");
4671
    printf("\n");
4672
    show_help_options(options, "Main options:\n", 0, 0);
4673
}
4674

    
4675
static const OptionDef options[] = {
4676
#include "cmdutils_common_opts.h"
4677
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4678
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4679
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4680
    { NULL },
4681
};
4682

    
4683
int main(int argc, char **argv)
4684
{
4685
    struct sigaction sigact;
4686

    
4687
    av_register_all();
4688

    
4689
    show_banner();
4690

    
4691
    my_program_name = argv[0];
4692
    my_program_dir = getcwd(0, 0);
4693
    ffserver_daemon = 1;
4694

    
4695
    parse_options(argc, argv, options, NULL);
4696

    
4697
    unsetenv("http_proxy");             /* Kill the http_proxy */
4698

    
4699
    av_lfg_init(&random_state, av_get_random_seed());
4700

    
4701
    memset(&sigact, 0, sizeof(sigact));
4702
    sigact.sa_handler = handle_child_exit;
4703
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4704
    sigaction(SIGCHLD, &sigact, 0);
4705

    
4706
    if (parse_ffconfig(config_filename) < 0) {
4707
        fprintf(stderr, "Incorrect config file - exiting.\n");
4708
        exit(1);
4709
    }
4710

    
4711
    /* open log file if needed */
4712
    if (logfilename[0] != '\0') {
4713
        if (!strcmp(logfilename, "-"))
4714
            logfile = stdout;
4715
        else
4716
            logfile = fopen(logfilename, "a");
4717
        av_log_set_callback(http_av_log);
4718
    }
4719

    
4720
    build_file_streams();
4721

    
4722
    build_feed_streams();
4723

    
4724
    compute_bandwidth();
4725

    
4726