Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ bf7aa642

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 "libavcore/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
static void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
388
{
389
    va_list vargs;
390
    va_start(vargs, fmt);
391
    http_vlog(fmt, vargs);
392
    va_end(vargs);
393
}
394

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

    
407
static void log_connection(HTTPContext *c)
408
{
409
    if (c->suppress_log)
410
        return;
411

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

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

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

    
436
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
437
}
438

    
439

    
440
static void start_children(FFStream *feed)
441
{
442
    if (no_launch)
443
        return;
444

    
445
    for (; feed; feed = feed->next) {
446
        if (feed->child_argv && !feed->pid) {
447
            feed->pid_start = time(0);
448

    
449
            feed->pid = fork();
450

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

    
461
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
462

    
463
                slash = strrchr(pathname, '/');
464
                if (!slash)
465
                    slash = pathname;
466
                else
467
                    slash++;
468
                strcpy(slash, "ffmpeg");
469

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

    
476
                for (i = 3; i < 256; i++)
477
                    close(i);
478

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

    
489
                /* This is needed to make relative pathnames work */
490
                chdir(my_program_dir);
491

    
492
                signal(SIGPIPE, SIG_DFL);
493

    
494
                execvp(pathname, feed->child_argv);
495

    
496
                _exit(1);
497
            }
498
        }
499
    }
500
}
501

    
502
/* open a listening socket */
503
static int socket_open_listen(struct sockaddr_in *my_addr)
504
{
505
    int server_fd, tmp;
506

    
507
    server_fd = socket(AF_INET,SOCK_STREAM,0);
508
    if (server_fd < 0) {
509
        perror ("socket");
510
        return -1;
511
    }
512

    
513
    tmp = 1;
514
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
515

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

    
524
    if (listen (server_fd, 5) < 0) {
525
        perror ("listen");
526
        closesocket(server_fd);
527
        return -1;
528
    }
529
    ff_socket_nonblock(server_fd, 1);
530

    
531
    return server_fd;
532
}
533

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

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

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

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

    
560
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
561
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
562
            if (!rtp_c)
563
                continue;
564

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

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

    
583
            /* change state to send data */
584
            rtp_c->state = HTTPSTATE_SEND_DATA;
585
        }
586
    }
587
}
588

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

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

    
602
    if (my_http_addr.sin_port) {
603
        server_fd = socket_open_listen(&my_http_addr);
604
        if (server_fd < 0)
605
            return -1;
606
    }
607

    
608
    if (my_rtsp_addr.sin_port) {
609
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
610
        if (rtsp_server_fd < 0)
611
            return -1;
612
    }
613

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

    
619
    http_log("FFserver started.\n");
620

    
621
    start_children(first_feed);
622

    
623
    start_multicast();
624

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

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

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

    
697
        cur_time = av_gettime() / 1000;
698

    
699
        if (need_to_start_children) {
700
            need_to_start_children = 0;
701
            start_children(first_feed);
702
        }
703

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

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

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

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

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

    
759

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

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

    
775
    if (nb_connections >= nb_max_connections) {
776
        http_send_too_busy_reply(fd);
777
        goto fail;
778
    }
779

    
780
    /* add a new connection */
781
    c = av_mallocz(sizeof(HTTPContext));
782
    if (!c)
783
        goto fail;
784

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

    
793
    c->next = first_http_ctx;
794
    first_http_ctx = c;
795
    nb_connections++;
796

    
797
    start_wait_request(c, is_rtsp);
798

    
799
    return;
800

    
801
 fail:
802
    if (c) {
803
        av_free(c->buffer);
804
        av_free(c);
805
    }
806
    closesocket(fd);
807
}
808

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

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

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

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

    
846
    /* free RTP output streams if any */
847
    nb_streams = 0;
848
    if (c->stream)
849
        nb_streams = c->stream->nb_streams;
850

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

    
864
    ctx = &c->fmt_ctx;
865

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

    
877
    for(i=0; i<ctx->nb_streams; i++)
878
        av_free(ctx->streams[i]);
879

    
880
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
881
        current_bandwidth -= c->stream->bandwidth;
882

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

    
889
    av_freep(&c->pb_buffer);
890
    av_freep(&c->packet_buffer);
891
    av_free(c->buffer);
892
    av_free(c);
893
    nb_connections--;
894
}
895

    
896
static int handle_connection(HTTPContext *c)
897
{
898
    int len, ret;
899

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

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

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

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

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

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

    
1009
        /* nothing to do, we'll be waken up by incoming feed packets */
1010
        break;
1011

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

    
1073
static int extract_rates(char *rates, int ratelen, const char *request)
1074
{
1075
    const char *p;
1076

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

    
1081
            while (*q && *q != '\n' && isspace(*q))
1082
                q++;
1083

    
1084
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1085
                int stream_no;
1086
                int rate_no;
1087

    
1088
                q += 20;
1089

    
1090
                memset(rates, 0xff, ratelen);
1091

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

    
1096
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1097
                        break;
1098

    
1099
                    stream_no--;
1100
                    if (stream_no < ratelen && stream_no >= 0)
1101
                        rates[stream_no] = rate_no;
1102

    
1103
                    while (*q && *q != '\n' && !isspace(*q))
1104
                        q++;
1105
                }
1106

    
1107
                return 1;
1108
            }
1109
        }
1110
        p = strchr(p, '\n');
1111
        if (!p)
1112
            break;
1113

    
1114
        p++;
1115
    }
1116

    
1117
    return 0;
1118
}
1119

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

    
1126
    for (i = 0; i < feed->nb_streams; i++) {
1127
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1128

    
1129
        if (feed_codec->codec_id != codec->codec_id ||
1130
            feed_codec->sample_rate != codec->sample_rate ||
1131
            feed_codec->width != codec->width ||
1132
            feed_codec->height != codec->height)
1133
            continue;
1134

    
1135
        /* Potential stream */
1136

    
1137
        /* We want the fastest stream less than bit_rate, or the slowest
1138
         * faster than bit_rate
1139
         */
1140

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

    
1154
    return best;
1155
}
1156

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

    
1163
    /* Not much we can do for a feed */
1164
    if (!req->feed)
1165
        return 0;
1166

    
1167
    for (i = 0; i < req->nb_streams; i++) {
1168
        AVCodecContext *codec = req->streams[i]->codec;
1169

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

    
1188
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1189
            action_required = 1;
1190
    }
1191

    
1192
    return action_required;
1193
}
1194

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

    
1206
static void get_word(char *buf, int buf_size, const char **pp)
1207
{
1208
    const char *p;
1209
    char *q;
1210

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

    
1224
static void get_arg(char *buf, int buf_size, const char **pp)
1225
{
1226
    const char *p;
1227
    char *q;
1228
    int quote;
1229

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

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

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

    
1274
    get_arg(arg, sizeof(arg), &p);
1275

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

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

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

    
1293
    if (!errors) {
1294
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1295
        IPAddressACL **naclp = 0;
1296

    
1297
        acl.next = 0;
1298
        *nacl = acl;
1299

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

    
1312
        if (naclp) {
1313
            while (*naclp)
1314
                naclp = &(*naclp)->next;
1315

    
1316
            *naclp = nacl;
1317
        }
1318
    }
1319
}
1320

    
1321

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

    
1331
    f = fopen(stream->dynamic_acl, "r");
1332
    if (!f) {
1333
        perror(stream->dynamic_acl);
1334
        return NULL;
1335
    }
1336

    
1337
    acl = av_mallocz(sizeof(IPAddressACL));
1338

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

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

    
1358

    
1359
static void free_acl_list(IPAddressACL *in_acl)
1360
{
1361
    IPAddressACL *pacl,*pacl2;
1362

    
1363
    pacl = in_acl;
1364
    while(pacl) {
1365
        pacl2 = pacl;
1366
        pacl = pacl->next;
1367
        av_freep(pacl2);
1368
    }
1369
}
1370

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

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

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

    
1388
static int validate_acl(FFStream *stream, HTTPContext *c)
1389
{
1390
    int ret = 0;
1391
    IPAddressACL *acl;
1392

    
1393

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

    
1397
    if (stream->dynamic_acl[0]) {
1398
        acl = parse_dynamic_acl(stream, c);
1399

    
1400
        ret = validate_acl_list(acl, c);
1401

    
1402
        free_acl_list(acl);
1403
    }
1404

    
1405
    return ret;
1406
}
1407

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

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

    
1434
enum RedirType {
1435
    REDIR_NONE,
1436
    REDIR_ASX,
1437
    REDIR_RAM,
1438
    REDIR_ASF,
1439
    REDIR_RTSP,
1440
    REDIR_SDP,
1441
};
1442

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

    
1459
    p = c->buffer;
1460
    get_word(cmd, sizeof(cmd), (const char **)&p);
1461
    av_strlcpy(c->method, cmd, sizeof(c->method));
1462

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

    
1470
    get_word(url, sizeof(url), (const char **)&p);
1471
    av_strlcpy(c->url, url, sizeof(c->url));
1472

    
1473
    get_word(protocol, sizeof(protocol), (const char **)&p);
1474
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1475
        return -1;
1476

    
1477
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1478

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

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

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

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

    
1503
        p++;
1504
    }
1505

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

    
1525
    // "redirect" / request to index.html
1526
    if (!strlen(filename))
1527
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1528

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

    
1541
    c->stream = stream;
1542
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1543
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1544

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

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

    
1573
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1574
        current_bandwidth += stream->bandwidth;
1575

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

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

    
1602
    if (redir_type != REDIR_NONE) {
1603
        char *hostinfo = 0;
1604

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

    
1614
            p++;
1615
        }
1616

    
1617
        if (hostinfo) {
1618
            char *eoh;
1619
            char hostbuf[260];
1620

    
1621
            while (isspace(*hostinfo))
1622
                hostinfo++;
1623

    
1624
            eoh = strchr(hostinfo, '\n');
1625
            if (eoh) {
1626
                if (eoh[-1] == '\r')
1627
                    eoh--;
1628

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

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

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

    
1689
                            len = sizeof(my_addr);
1690
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1691

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

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

    
1718
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1719
        goto send_error;
1720
    }
1721

    
1722
    stream->conns_served++;
1723

    
1724
    /* XXX: add there authenticate and IP match */
1725

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

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

    
1745
                p++;
1746
            }
1747

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

    
1751
                logline += 17;
1752

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

    
1761
#ifdef DEBUG_WMP
1762
            http_log("\nGot request:\n%s\n", c->buffer);
1763
#endif
1764

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

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

    
1774
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1775
                    wmpc->switch_pending = 1;
1776
            }
1777

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

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

    
1796
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1797
        goto send_status;
1798

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

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

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

    
1817
        c->wmp_client_id = av_lfg_get(&random_state);
1818

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

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

    
1854
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1855
{
1856
    static const char *suffix = " kMGTP";
1857
    const char *s;
1858

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

    
1861
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1862
}
1863

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

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

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

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

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

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

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

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

    
1990
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1991
                {
1992
                    FILE *pid_stat;
1993
                    char ps_cmd[64];
1994

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

    
2000
                    pid_stat = popen(ps_cmd, "r");
2001
                    if (pid_stat) {
2002
                        char cpuperc[10];
2003
                        char cpuused[64];
2004

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

    
2015
                url_fprintf(pb, "<p>");
2016
            }
2017
            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");
2018

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

    
2025
                parameters[0] = 0;
2026

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

    
2045
        }
2046
        stream = stream->next;
2047
    }
2048

    
2049
    /* connection status */
2050
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
2051

    
2052
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
2053
                 nb_connections, nb_max_connections);
2054

    
2055
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2056
                 current_bandwidth, max_bandwidth);
2057

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

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

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

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

    
2101
    len = url_close_dyn_buf(pb, &c->pb_buffer);
2102
    c->buffer_ptr = c->pb_buffer;
2103
    c->buffer_end = c->pb_buffer + len;
2104
}
2105

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

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

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

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

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

    
2172
    /* open each parser */
2173
    for(i=0;i<s->nb_streams;i++)
2174
        open_parser(s, i);
2175

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

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

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

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

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

    
2219

    
2220
static int http_prepare_data(HTTPContext *c)
2221
{
2222
    int i, len, ret;
2223
    AVFormatContext *ctx;
2224

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

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

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

    
2255
        c->got_key_frame = 0;
2256

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

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

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

    
2279
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2280
        c->buffer_ptr = c->pb_buffer;
2281
        c->buffer_end = c->pb_buffer + len;
2282

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

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

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

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

    
2412
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2413
                    c->cur_frame_bytes = len;
2414
                    c->buffer_ptr = c->pb_buffer;
2415
                    c->buffer_end = c->pb_buffer + len;
2416

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

    
2444
        c->last_packet_sent = 1;
2445
        break;
2446
    }
2447
    return 0;
2448
}
2449

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

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

    
2486
                c->data_count += len;
2487
                update_datarate(&c->datarate, c->data_count);
2488
                if (c->stream)
2489
                    c->stream->bytes_served += len;
2490

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

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

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

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

    
2572
static int http_start_receive_data(HTTPContext *c)
2573
{
2574
    int fd;
2575

    
2576
    if (c->stream->feed_opened)
2577
        return -1;
2578

    
2579
    /* Don't permit writing to this one */
2580
    if (c->stream->readonly)
2581
        return -1;
2582

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

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

    
2603
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2604
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2605
    lseek(fd, 0, SEEK_SET);
2606

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

    
2615
static int http_receive_data(HTTPContext *c)
2616
{
2617
    HTTPContext *c1;
2618
    int len, loop_run = 0;
2619

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

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

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

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

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

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

    
2690
            feed->feed_write_index += FFM_PACKET_SIZE;
2691
            /* update file size */
2692
            if (feed->feed_write_index > c->stream->feed_size)
2693
                feed->feed_size = feed->feed_write_index;
2694

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

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

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

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

    
2723
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2724
            pb->is_streamed = 1;
2725

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

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

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

    
2746
            av_close_input_stream(s);
2747
            av_free(pb);
2748
        }
2749
        c->buffer_ptr = c->buffer;
2750
    }
2751

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

    
2765
/********************************************************************/
2766
/* RTSP handling */
2767

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

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

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

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

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

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

    
2840
    c->buffer_ptr[0] = '\0';
2841
    p = c->buffer;
2842

    
2843
    get_word(cmd, sizeof(cmd), &p);
2844
    get_word(url, sizeof(url), &p);
2845
    get_word(protocol, sizeof(protocol), &p);
2846

    
2847
    av_strlcpy(c->method, cmd, sizeof(c->method));
2848
    av_strlcpy(c->url, url, sizeof(c->url));
2849
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2850

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

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

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

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

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

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

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

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

    
2942
#if !FF_API_MAX_STREAMS
2943
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2944
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2945
        goto sdp_done;
2946
#endif
2947
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2948
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2949
        goto sdp_done;
2950

    
2951
    for(i = 0; i < stream->nb_streams; i++) {
2952
        avc->streams[i] = &avs[i];
2953
        avc->streams[i]->codec = stream->streams[i]->codec;
2954
    }
2955
    *pbuffer = av_mallocz(2048);
2956
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2957

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

    
2966
    return strlen(*pbuffer);
2967
}
2968

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

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

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

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

    
3004
 found:
3005
    /* prepare the media description in sdp format */
3006

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

    
3024
static HTTPContext *find_rtp_session(const char *session_id)
3025
{
3026
    HTTPContext *c;
3027

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

    
3031
    for(c = first_http_ctx; c != NULL; c = c->next) {
3032
        if (!strcmp(c->session_id, session_id))
3033
            return c;
3034
    }
3035
    return NULL;
3036
}
3037

    
3038
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3039
{
3040
    RTSPTransportField *th;
3041
    int i;
3042

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3187

    
3188
    url_fprintf(c->pb, "\r\n");
3189
}
3190

    
3191

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

    
3203
    rtp_c = find_rtp_session(session_id);
3204
    if (!rtp_c)
3205
        return NULL;
3206

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

    
3224
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3225
{
3226
    HTTPContext *rtp_c;
3227

    
3228
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3229
    if (!rtp_c) {
3230
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3231
        return;
3232
    }
3233

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

    
3241
    rtp_c->state = HTTPSTATE_SEND_DATA;
3242

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

    
3250
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3251
{
3252
    HTTPContext *rtp_c;
3253

    
3254
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3255
    if (!rtp_c) {
3256
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3257
        return;
3258
    }
3259

    
3260
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3261
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3262
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3263
        return;
3264
    }
3265

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

    
3275
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3276
{
3277
    HTTPContext *rtp_c;
3278
    char session_id[32];
3279

    
3280
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3281
    if (!rtp_c) {
3282
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3283
        return;
3284
    }
3285

    
3286
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3287

    
3288
    /* abort the session */
3289
    close_connection(rtp_c);
3290

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

    
3298

    
3299
/********************************************************************/
3300
/* RTP handling */
3301

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

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

    
3314
    /* add a new connection */
3315
    c = av_mallocz(sizeof(HTTPContext));
3316
    if (!c)
3317
        goto fail;
3318

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

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

    
3351
    current_bandwidth += stream->bandwidth;
3352

    
3353
    c->next = first_http_ctx;
3354
    first_http_ctx = c;
3355
    return c;
3356

    
3357
 fail:
3358
    if (c) {
3359
        av_free(c->buffer);
3360
        av_free(c);
3361
    }
3362
    return NULL;
3363
}
3364

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

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

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

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

    
3400
    /* build destination RTP address */
3401
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3402

    
3403
    switch(c->rtp_protocol) {
3404
    case RTSP_LOWER_TRANSPORT_UDP:
3405
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3406
        /* RTP/UDP case */
3407

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

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

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

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

    
3456
    c->rtp_ctx[stream_index] = ctx;
3457
    return 0;
3458
}
3459

    
3460
/********************************************************************/
3461
/* ffserver initialization */
3462

    
3463
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3464
{
3465
    AVStream *fst;
3466

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3640
                av_close_input_file(infile);
3641
            }
3642
        }
3643
    }
3644
}
3645

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

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

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

    
3675
    /* create feed files if needed */
3676
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3677
        int fd;
3678

    
3679
        if (url_exist(feed->feed_filename)) {
3680
            /* See if it matches */
3681
            AVFormatContext *s;
3682
            int matches = 0;
3683

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

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

    
3701
                            ccf = sf->codec;
3702
                            ccs = ss->codec;
3703
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3704

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

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

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

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

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

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

    
3797
        close(fd);
3798
    }
3799
}
3800

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

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

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

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

    
3864
        if (!av->nsse_weight)
3865
            av->nsse_weight = 8;
3866

    
3867
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3868
        if (!av->me_method)
3869
            av->me_method = ME_EPZS;
3870
        av->rc_buffer_aggressivity = 1.0;
3871

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

    
3883
        if (av->rc_max_rate && !av->rc_buffer_size) {
3884
            av->rc_buffer_size = av->rc_max_rate;
3885
        }
3886

    
3887

    
3888
        break;
3889
    default:
3890
        abort();
3891
    }
3892

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

    
3901
static enum CodecID opt_audio_codec(const char *arg)
3902
{
3903
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3904

    
3905
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3906
        return CODEC_ID_NONE;
3907

    
3908
    return p->id;
3909
}
3910

    
3911
static enum CodecID opt_video_codec(const char *arg)
3912
{
3913
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3914

    
3915
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3916
        return CODEC_ID_NONE;
3917

    
3918
    return p->id;
3919
}
3920

    
3921
/* simplistic plugin support */
3922

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

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

    
3943
    init_func();
3944
}
3945
#endif
3946

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

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

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

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

    
3995
    fclose(f);
3996

    
3997
    return ret;
3998
}
3999

    
4000
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4001
                                             const char *mime_type)
4002
{
4003
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4004

    
4005
    if (fmt) {
4006
        AVOutputFormat *stream_fmt;
4007
        char stream_format_name[64];
4008

    
4009
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4010
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4011

    
4012
        if (stream_fmt)
4013
            fmt = stream_fmt;
4014
    }
4015

    
4016
    return fmt;
4017
}
4018

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

    
4027
    (*errors)++;
4028
}
4029

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

    
4043
    f = fopen(filename, "r");
4044
    if (!f) {
4045
        perror(filename);
4046
        return -1;
4047
    }
4048

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

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

    
4072
        get_arg(cmd, sizeof(cmd), &p);
4073

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

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

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

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

    
4164
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4165

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

    
4171
                    feed->child_argv[i] = av_strdup(arg);
4172
                }
4173

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

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

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

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

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

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

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

    
4368
                get_arg(arg, sizeof(arg), &p);
4369

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

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

    
4625
    fclose(f);
4626
    if (errors)
4627
        return -1;
4628
    else
4629
        return 0;
4630
}
4631

    
4632
static void handle_child_exit(int sig)
4633
{
4634
    pid_t pid;
4635
    int status;
4636

    
4637
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4638
        FFStream *feed;
4639

    
4640
        for (feed = first_feed; feed; feed = feed->next) {
4641
            if (feed->pid == pid) {
4642
                int uptime = time(0) - feed->pid_start;
4643

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

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

    
4654
    need_to_start_children = 1;
4655
}
4656

    
4657
static void opt_debug(void)
4658
{
4659
    ffserver_debug = 1;
4660
    ffserver_daemon = 0;
4661
    logfilename[0] = '-';
4662
}
4663

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

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

    
4680
int main(int argc, char **argv)
4681
{
4682
    struct sigaction sigact;
4683

    
4684
    av_register_all();
4685

    
4686
    show_banner();
4687

    
4688
    my_program_name = argv[0];
4689
    my_program_dir = getcwd(0, 0);
4690
    ffserver_daemon = 1;
4691

    
4692
    parse_options(argc, argv, options, NULL);
4693

    
4694
    unsetenv("http_proxy");             /* Kill the http_proxy */
4695

    
4696
    av_lfg_init(&random_state, av_get_random_seed());
4697

    
4698
    memset(&sigact, 0, sizeof(sigact));
4699
    sigact.sa_handler = handle_child_exit;
4700
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4701
    sigaction(SIGCHLD, &sigact, 0);
4702

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

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

    
4717
    build_file_streams();
4718

    
4719
    build_feed_streams();
4720

    
4721
    compute_bandwidth();
4722

    
4723
    /* put the process in background and detach it from its TTY */
4724
    if (ffserver_daemon) {
4725