Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 9389b925

History | View | Annotate | Download (156 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
#define IOBUFFER_INIT_SIZE 8192
96

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

    
101
#define SYNC_TIMEOUT (10 * 1000)
102

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
314
static AVLFG random_state;
315

    
316
static FILE *logfile = NULL;
317

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

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

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

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

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

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

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

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

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

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

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

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

    
435

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

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

    
445
            feed->pid = fork();
446

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

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

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

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

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

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

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

    
488
                signal(SIGPIPE, SIG_DFL);
489

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

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

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

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

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

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

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

    
527
    return server_fd;
528
}
529

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
617
    start_children(first_feed);
618

    
619
    start_multicast();
620

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

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

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

    
693
        cur_time = av_gettime() / 1000;
694

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

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

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

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

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

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

    
755

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

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

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

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

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

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

    
793
    start_wait_request(c, is_rtsp);
794

    
795
    return;
796

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

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

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

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

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

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

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

    
860
    ctx = &c->fmt_ctx;
861

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1084
                q += 20;
1085

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

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

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

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

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

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

    
1110
        p++;
1111
    }
1112

    
1113
    return 0;
1114
}
1115

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

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

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

    
1131
        /* Potential stream */
1132

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

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

    
1150
    return best;
1151
}
1152

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

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

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

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

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

    
1188
    return action_required;
1189
}
1190

    
1191

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1330

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

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

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

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

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

    
1367

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

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

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

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

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

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

    
1402

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

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

    
1409
        ret = validate_acl_list(acl, c);
1410

    
1411
        free_acl_list(acl);
1412
    }
1413

    
1414
    return ret;
1415
}
1416

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1512
        p++;
1513
    }
1514

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

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

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

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

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

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

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

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

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

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

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

    
1623
            p++;
1624
        }
1625

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

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

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

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

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

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

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

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

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

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

    
1731
    stream->conns_served++;
1732

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

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

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

    
1754
                p++;
1755
            }
1756

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

    
1760
                logline += 17;
1761

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2024
                url_fprintf(pb, "<p>");
2025
            }
2026
            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");
2027

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

    
2034
                parameters[0] = 0;
2035

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

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

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

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

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

    
2067
    url_fprintf(pb, "<table>\n");
2068
    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");
2069
    c1 = first_http_ctx;
2070
    i = 0;
2071
    while (c1 != NULL) {
2072
        int bitrate;
2073
        int j;
2074

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2228

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

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

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

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

    
2264
        c->got_key_frame = 0;
2265

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

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

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

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

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

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

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

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

    
2421
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2422
                    c->cur_frame_bytes = len;
2423
                    c->buffer_ptr = c->pb_buffer;
2424
                    c->buffer_end = c->pb_buffer + len;
2425

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

    
2453
        c->last_packet_sent = 1;
2454
        break;
2455
    }
2456
    return 0;
2457
}
2458

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

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

    
2495
                c->data_count += len;
2496
                update_datarate(&c->datarate, c->data_count);
2497
                if (c->stream)
2498
                    c->stream->bytes_served += len;
2499

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

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

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

    
2570
                c->data_count += len;
2571
                update_datarate(&c->datarate, c->data_count);
2572
                if (c->stream)
2573
                    c->stream->bytes_served += len;
2574
                break;
2575
            }
2576
        }
2577
    } /* for(;;) */
2578
    return 0;
2579
}
2580

    
2581
static int http_start_receive_data(HTTPContext *c)
2582
{
2583
    int fd;
2584

    
2585
    if (c->stream->feed_opened)
2586
        return -1;
2587

    
2588
    /* Don't permit writing to this one */
2589
    if (c->stream->readonly)
2590
        return -1;
2591

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

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

    
2612
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2613
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2614
    lseek(fd, 0, SEEK_SET);
2615

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

    
2624
static int http_receive_data(HTTPContext *c)
2625
{
2626
    HTTPContext *c1;
2627
    int len, loop_run = 0;
2628

    
2629
    while (c->chunked_encoding && !c->chunk_size &&
2630
           c->buffer_end > c->buffer_ptr) {
2631
        /* read chunk header, if present */
2632
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2633

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

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

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

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

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

    
2699
            feed->feed_write_index += FFM_PACKET_SIZE;
2700
            /* update file size */
2701
            if (feed->feed_write_index > c->stream->feed_size)
2702
                feed->feed_size = feed->feed_write_index;
2703

    
2704
            /* handle wrap around if max file size reached */
2705
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2706
                feed->feed_write_index = FFM_PACKET_SIZE;
2707

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

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

    
2727
            /* use feed output format name to find corresponding input format */
2728
            fmt_in = av_find_input_format(feed->fmt->name);
2729
            if (!fmt_in)
2730
                goto fail;
2731

    
2732
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2733
            pb->is_streamed = 1;
2734

    
2735
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2736
                av_free(pb);
2737
                goto fail;
2738
            }
2739

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

    
2749
            for (i = 0; i < s->nb_streams; i++) {
2750
                AVStream *fst = feed->streams[i];
2751
                AVStream *st = s->streams[i];
2752
                avcodec_copy_context(fst->codec, st->codec);
2753
            }
2754

    
2755
            av_close_input_stream(s);
2756
            av_free(pb);
2757
        }
2758
        c->buffer_ptr = c->buffer;
2759
    }
2760

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

    
2774
/********************************************************************/
2775
/* RTSP handling */
2776

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

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

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

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

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

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

    
2849
    c->buffer_ptr[0] = '\0';
2850
    p = c->buffer;
2851

    
2852
    get_word(cmd, sizeof(cmd), &p);
2853
    get_word(url, sizeof(url), &p);
2854
    get_word(protocol, sizeof(protocol), &p);
2855

    
2856
    av_strlcpy(c->method, cmd, sizeof(c->method));
2857
    av_strlcpy(c->url, url, sizeof(c->url));
2858
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2859

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

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

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

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

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

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

    
2929
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2930
                                   struct in_addr my_ip)
2931
{
2932
    AVFormatContext *avc;
2933
    AVStream *avs = NULL;
2934
    int i;
2935

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

    
2951
#if !FF_API_MAX_STREAMS
2952
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2953
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2954
        goto sdp_done;
2955
#endif
2956
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2957
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2958
        goto sdp_done;
2959

    
2960
    for(i = 0; i < stream->nb_streams; i++) {
2961
        avc->streams[i] = &avs[i];
2962
        avc->streams[i]->codec = stream->streams[i]->codec;
2963
    }
2964
    *pbuffer = av_mallocz(2048);
2965
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2966

    
2967
 sdp_done:
2968
#if !FF_API_MAX_STREAMS
2969
    av_free(avc->streams);
2970
#endif
2971
    av_metadata_free(&avc->metadata);
2972
    av_free(avc);
2973
    av_free(avs);
2974

    
2975
    return strlen(*pbuffer);
2976
}
2977

    
2978
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2979
{
2980
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2981
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2982
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2983
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2984
    url_fprintf(c->pb, "\r\n");
2985
}
2986

    
2987
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2988
{
2989
    FFStream *stream;
2990
    char path1[1024];
2991
    const char *path;
2992
    uint8_t *content;
2993
    int content_length, len;
2994
    struct sockaddr_in my_addr;
2995

    
2996
    /* find which url is asked */
2997
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2998
    path = path1;
2999
    if (*path == '/')
3000
        path++;
3001

    
3002
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3003
        if (!stream->is_feed &&
3004
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3005
            !strcmp(path, stream->filename)) {
3006
            goto found;
3007
        }
3008
    }
3009
    /* no stream found */
3010
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3011
    return;
3012

    
3013
 found:
3014
    /* prepare the media description in sdp format */
3015

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

    
3033
static HTTPContext *find_rtp_session(const char *session_id)
3034
{
3035
    HTTPContext *c;
3036

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

    
3040
    for(c = first_http_ctx; c != NULL; c = c->next) {
3041
        if (!strcmp(c->session_id, session_id))
3042
            return c;
3043
    }
3044
    return NULL;
3045
}
3046

    
3047
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3048
{
3049
    RTSPTransportField *th;
3050
    int i;
3051

    
3052
    for(i=0;i<h->nb_transports;i++) {
3053
        th = &h->transports[i];
3054
        if (th->lower_transport == lower_transport)
3055
            return th;
3056
    }
3057
    return NULL;
3058
}
3059

    
3060
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3061
                           RTSPMessageHeader *h)
3062
{
3063
    FFStream *stream;
3064
    int stream_index, rtp_port, rtcp_port;
3065
    char buf[1024];
3066
    char path1[1024];
3067
    const char *path;
3068
    HTTPContext *rtp_c;
3069
    RTSPTransportField *th;
3070
    struct sockaddr_in dest_addr;
3071
    RTSPActionServerSetup setup;
3072

    
3073
    /* find which url is asked */
3074
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3075
    path = path1;
3076
    if (*path == '/')
3077
        path++;
3078

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

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

    
3107
    /* generate session id if needed */
3108
    if (h->session_id[0] == '\0')
3109
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3110
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3111

    
3112
    /* find rtp session, and create it if none found */
3113
    rtp_c = find_rtp_session(h->session_id);
3114
    if (!rtp_c) {
3115
        /* always prefer UDP */
3116
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3117
        if (!th) {
3118
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3119
            if (!th) {
3120
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3121
                return;
3122
            }
3123
        }
3124

    
3125
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3126
                                   th->lower_transport);
3127
        if (!rtp_c) {
3128
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3129
            return;
3130
        }
3131

    
3132
        /* open input stream */
3133
        if (open_input_stream(rtp_c, "") < 0) {
3134
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3135
            return;
3136
        }
3137
    }
3138

    
3139
    /* test if stream is OK (test needed because several SETUP needs
3140
       to be done for a given file) */
3141
    if (rtp_c->stream != stream) {
3142
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3143
        return;
3144
    }
3145

    
3146
    /* test if stream is already set up */
3147
    if (rtp_c->rtp_ctx[stream_index]) {
3148
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3149
        return;
3150
    }
3151

    
3152
    /* check transport */
3153
    th = find_transport(h, rtp_c->rtp_protocol);
3154
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3155
                th->client_port_min <= 0)) {
3156
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3157
        return;
3158
    }
3159

    
3160
    /* setup default options */
3161
    setup.transport_option[0] = '\0';
3162
    dest_addr = rtp_c->from_addr;
3163
    dest_addr.sin_port = htons(th->client_port_min);
3164

    
3165
    /* setup stream */
3166
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3167
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3168
        return;
3169
    }
3170

    
3171
    /* now everything is OK, so we can send the connection parameters */
3172
    rtsp_reply_header(c, RTSP_STATUS_OK);
3173
    /* session ID */
3174
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3175

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

    
3196

    
3197
    url_fprintf(c->pb, "\r\n");
3198
}
3199

    
3200

    
3201
/* find an rtp connection by using the session ID. Check consistency
3202
   with filename */
3203
static HTTPContext *find_rtp_session_with_url(const char *url,
3204
                                              const char *session_id)
3205
{
3206
    HTTPContext *rtp_c;
3207
    char path1[1024];
3208
    const char *path;
3209
    char buf[1024];
3210
    int s;
3211

    
3212
    rtp_c = find_rtp_session(session_id);
3213
    if (!rtp_c)
3214
        return NULL;
3215

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

    
3233
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3234
{
3235
    HTTPContext *rtp_c;
3236

    
3237
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3238
    if (!rtp_c) {
3239
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3240
        return;
3241
    }
3242

    
3243
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3244
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3245
        rtp_c->state != HTTPSTATE_READY) {
3246
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3247
        return;
3248
    }
3249

    
3250
    rtp_c->state = HTTPSTATE_SEND_DATA;
3251

    
3252
    /* now everything is OK, so we can send the connection parameters */
3253
    rtsp_reply_header(c, RTSP_STATUS_OK);
3254
    /* session ID */
3255
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3256
    url_fprintf(c->pb, "\r\n");
3257
}
3258

    
3259
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3260
{
3261
    HTTPContext *rtp_c;
3262

    
3263
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3264
    if (!rtp_c) {
3265
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3266
        return;
3267
    }
3268

    
3269
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3270
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3271
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3272
        return;
3273
    }
3274

    
3275
    rtp_c->state = HTTPSTATE_READY;
3276
    rtp_c->first_pts = AV_NOPTS_VALUE;
3277
    /* now everything is OK, so we can send the connection parameters */
3278
    rtsp_reply_header(c, RTSP_STATUS_OK);
3279
    /* session ID */
3280
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3281
    url_fprintf(c->pb, "\r\n");
3282
}
3283

    
3284
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3285
{
3286
    HTTPContext *rtp_c;
3287
    char session_id[32];
3288

    
3289
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3290
    if (!rtp_c) {
3291
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3292
        return;
3293
    }
3294

    
3295
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3296

    
3297
    /* abort the session */
3298
    close_connection(rtp_c);
3299

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

    
3307

    
3308
/********************************************************************/
3309
/* RTP handling */
3310

    
3311
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3312
                                       FFStream *stream, const char *session_id,
3313
                                       enum RTSPLowerTransport rtp_protocol)
3314
{
3315
    HTTPContext *c = NULL;
3316
    const char *proto_str;
3317

    
3318
    /* XXX: should output a warning page when coming
3319
       close to the connection limit */
3320
    if (nb_connections >= nb_max_connections)
3321
        goto fail;
3322

    
3323
    /* add a new connection */
3324
    c = av_mallocz(sizeof(HTTPContext));
3325
    if (!c)
3326
        goto fail;
3327

    
3328
    c->fd = -1;
3329
    c->poll_entry = NULL;
3330
    c->from_addr = *from_addr;
3331
    c->buffer_size = IOBUFFER_INIT_SIZE;
3332
    c->buffer = av_malloc(c->buffer_size);
3333
    if (!c->buffer)
3334
        goto fail;
3335
    nb_connections++;
3336
    c->stream = stream;
3337
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3338
    c->state = HTTPSTATE_READY;
3339
    c->is_packetized = 1;
3340
    c->rtp_protocol = rtp_protocol;
3341

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

    
3360
    current_bandwidth += stream->bandwidth;
3361

    
3362
    c->next = first_http_ctx;
3363
    first_http_ctx = c;
3364
    return c;
3365

    
3366
 fail:
3367
    if (c) {
3368
        av_free(c->buffer);
3369
        av_free(c);
3370
    }
3371
    return NULL;
3372
}
3373

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

    
3388
    /* now we can open the relevant output stream */
3389
    ctx = avformat_alloc_context();
3390
    if (!ctx)
3391
        return -1;
3392
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3393

    
3394
    st = av_mallocz(sizeof(AVStream));
3395
    if (!st)
3396
        goto fail;
3397
    ctx->nb_streams = 1;
3398
    ctx->streams[0] = st;
3399

    
3400
    if (!c->stream->feed ||
3401
        c->stream->feed == c->stream)
3402
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3403
    else
3404
        memcpy(st,
3405
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3406
               sizeof(AVStream));
3407
    st->priv_data = NULL;
3408

    
3409
    /* build destination RTP address */
3410
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3411

    
3412
    switch(c->rtp_protocol) {
3413
    case RTSP_LOWER_TRANSPORT_UDP:
3414
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3415
        /* RTP/UDP case */
3416

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

    
3431
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3432
            goto fail;
3433
        c->rtp_handles[stream_index] = h;
3434
        max_packet_size = url_get_max_packet_size(h);
3435
        break;
3436
    case RTSP_LOWER_TRANSPORT_TCP:
3437
        /* RTP/TCP case */
3438
        c->rtsp_c = rtsp_c;
3439
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3440
        break;
3441
    default:
3442
        goto fail;
3443
    }
3444

    
3445
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3446
             ipaddr, ntohs(dest_addr->sin_port),
3447
             c->stream->filename, stream_index, c->protocol);
3448

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

    
3465
    c->rtp_ctx[stream_index] = ctx;
3466
    return 0;
3467
}
3468

    
3469
/********************************************************************/
3470
/* ffserver initialization */
3471

    
3472
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3473
{
3474
    AVStream *fst;
3475

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

    
3500
/* return the stream number in the feed */
3501
static int add_av_stream(FFStream *feed, AVStream *st)
3502
{
3503
    AVStream *fst;
3504
    AVCodecContext *av, *av1;
3505
    int i;
3506

    
3507
    av = st->codec;
3508
    for(i=0;i<feed->nb_streams;i++) {
3509
        st = feed->streams[i];
3510
        av1 = st->codec;
3511
        if (av1->codec_id == av->codec_id &&
3512
            av1->codec_type == av->codec_type &&
3513
            av1->bit_rate == av->bit_rate) {
3514

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

    
3535
    fst = add_av_stream1(feed, av, 0);
3536
    if (!fst)
3537
        return -1;
3538
    return feed->nb_streams - 1;
3539
 found:
3540
    return i;
3541
}
3542

    
3543
static void remove_stream(FFStream *stream)
3544
{
3545
    FFStream **ps;
3546
    ps = &first_stream;
3547
    while (*ps != NULL) {
3548
        if (*ps == stream)
3549
            *ps = (*ps)->next;
3550
        else
3551
            ps = &(*ps)->next;
3552
    }
3553
}
3554

    
3555
/* specific mpeg4 handling : we extract the raw parameters */
3556
static void extract_mpeg4_header(AVFormatContext *infile)
3557
{
3558
    int mpeg4_count, i, size;
3559
    AVPacket pkt;
3560
    AVStream *st;
3561
    const uint8_t *p;
3562

    
3563
    mpeg4_count = 0;
3564
    for(i=0;i<infile->nb_streams;i++) {
3565
        st = infile->streams[i];
3566
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3567
            st->codec->extradata_size == 0) {
3568
            mpeg4_count++;
3569
        }
3570
    }
3571
    if (!mpeg4_count)
3572
        return;
3573

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

    
3604
/* compute the needed AVStream for each file */
3605
static void build_file_streams(void)
3606
{
3607
    FFStream *stream, *stream_next;
3608
    AVFormatContext *infile;
3609
    int i, ret;
3610

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

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

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

    
3648
                av_close_input_file(infile);
3649
            }
3650
        }
3651
    }
3652
}
3653

    
3654
/* compute the needed AVStream for each feed */
3655
static void build_feed_streams(void)
3656
{
3657
    FFStream *stream, *feed;
3658
    int i;
3659

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

    
3672
    /* gather all streams */
3673
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3674
        feed = stream->feed;
3675
        if (feed) {
3676
            if (stream->is_feed) {
3677
                for(i=0;i<stream->nb_streams;i++)
3678
                    stream->feed_streams[i] = i;
3679
            }
3680
        }
3681
    }
3682

    
3683
    /* create feed files if needed */
3684
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3685
        int fd;
3686

    
3687
        if (url_exist(feed->feed_filename)) {
3688
            /* See if it matches */
3689
            AVFormatContext *s;
3690
            int matches = 0;
3691

    
3692
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3693
                /* Now see if it matches */
3694
                if (s->nb_streams == feed->nb_streams) {
3695
                    matches = 1;
3696
                    for(i=0;i<s->nb_streams;i++) {
3697
                        AVStream *sf, *ss;
3698
                        sf = feed->streams[i];
3699
                        ss = s->streams[i];
3700

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

    
3709
                            ccf = sf->codec;
3710
                            ccs = ss->codec;
3711
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3712

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

    
3746
                av_close_input_file(s);
3747
            } else
3748
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3749
                        feed->feed_filename);
3750

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

    
3763
            if (feed->readonly) {
3764
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3765
                    feed->feed_filename);
3766
                exit(1);
3767
            }
3768

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

    
3799
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3800
        feed->feed_size = lseek(fd, 0, SEEK_END);
3801
        /* ensure that we do not wrap before the end of file */
3802
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3803
            feed->feed_max_size = feed->feed_size;
3804

    
3805
        close(fd);
3806
    }
3807
}
3808

    
3809
/* compute the bandwidth used by each stream */
3810
static void compute_bandwidth(void)
3811
{
3812
    unsigned bandwidth;
3813
    int i;
3814
    FFStream *stream;
3815

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

    
3833
/* add a codec and set the default parameters */
3834
static void add_codec(FFStream *stream, AVCodecContext *av)
3835
{
3836
    AVStream *st;
3837

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

    
3872
        if (!av->nsse_weight)
3873
            av->nsse_weight = 8;
3874

    
3875
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3876
        if (!av->me_method)
3877
            av->me_method = ME_EPZS;
3878
        av->rc_buffer_aggressivity = 1.0;
3879

    
3880
        if (!av->rc_eq)
3881
            av->rc_eq = "tex^qComp";
3882
        if (!av->i_quant_factor)
3883
            av->i_quant_factor = -0.8;
3884
        if (!av->b_quant_factor)
3885
            av->b_quant_factor = 1.25;
3886
        if (!av->b_quant_offset)
3887
            av->b_quant_offset = 1.25;
3888
        if (!av->rc_max_rate)
3889
            av->rc_max_rate = av->bit_rate * 2;
3890

    
3891
        if (av->rc_max_rate && !av->rc_buffer_size) {
3892
            av->rc_buffer_size = av->rc_max_rate;
3893
        }
3894

    
3895

    
3896
        break;
3897
    default:
3898
        abort();
3899
    }
3900

    
3901
    st = av_mallocz(sizeof(AVStream));
3902
    if (!st)
3903
        return;
3904
    st->codec = avcodec_alloc_context();
3905
    stream->streams[stream->nb_streams++] = st;
3906
    memcpy(st->codec, av, sizeof(AVCodecContext));
3907
}
3908

    
3909
static enum CodecID opt_audio_codec(const char *arg)
3910
{
3911
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3912

    
3913
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3914
        return CODEC_ID_NONE;
3915

    
3916
    return p->id;
3917
}
3918

    
3919
static enum CodecID opt_video_codec(const char *arg)
3920
{
3921
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3922

    
3923
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3924
        return CODEC_ID_NONE;
3925

    
3926
    return p->id;
3927
}
3928

    
3929
/* simplistic plugin support */
3930

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

    
3943
    init_func = dlsym(dll, "ffserver_module_init");
3944
    if (!init_func) {
3945
        fprintf(stderr,
3946
                "%s: init function 'ffserver_module_init()' not found\n",
3947
                filename);
3948
        dlclose(dll);
3949
    }
3950

    
3951
    init_func();
3952
}
3953
#endif
3954

    
3955
static int ffserver_opt_default(const char *opt, const char *arg,
3956
                       AVCodecContext *avctx, int type)
3957
{
3958
    int ret = 0;
3959
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3960
    if(o)
3961
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3962
    return ret;
3963
}
3964

    
3965
static int ffserver_opt_preset(const char *arg,
3966
                       AVCodecContext *avctx, int type,
3967
                       enum CodecID *audio_id, enum CodecID *video_id)
3968
{
3969
    FILE *f=NULL;
3970
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3971
    int i, ret = 0;
3972
    const char *base[3]= { getenv("FFMPEG_DATADIR"),
3973
                           getenv("HOME"),
3974
                           FFMPEG_DATADIR,
3975
                         };
3976

    
3977
    for(i=0; i<3 && !f; i++){
3978
        if(!base[i])
3979
            continue;
3980
        snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", arg);
3981
        f= fopen(filename, "r");
3982
        if(!f){
3983
            AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3984
            if (codec) {
3985
                snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i],  i != 1 ? "" : "/.ffmpeg", codec->name, arg);
3986
                f= fopen(filename, "r");
3987
            }
3988
        }
3989
    }
3990

    
3991
    if(!f){
3992
        fprintf(stderr, "File for preset '%s' not found\n", arg);
3993
        return 1;
3994
    }
3995

    
3996
    while(!feof(f)){
3997
        int e= fscanf(f, "%999[^\n]\n", line) - 1;
3998
        if(line[0] == '#' && !e)
3999
            continue;
4000
        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4001
        if(e){
4002
            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4003
            ret = 1;
4004
            break;
4005
        }
4006
        if(!strcmp(tmp, "acodec")){
4007
            *audio_id = opt_audio_codec(tmp2);
4008
        }else if(!strcmp(tmp, "vcodec")){
4009
            *video_id = opt_video_codec(tmp2);
4010
        }else if(!strcmp(tmp, "scodec")){
4011
            /* opt_subtitle_codec(tmp2); */
4012
        }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4013
            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4014
            ret = 1;
4015
            break;
4016
        }
4017
    }
4018

    
4019
    fclose(f);
4020

    
4021
    return ret;
4022
}
4023

    
4024
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4025
                                             const char *mime_type)
4026
{
4027
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4028

    
4029
    if (fmt) {
4030
        AVOutputFormat *stream_fmt;
4031
        char stream_format_name[64];
4032

    
4033
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4034
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4035

    
4036
        if (stream_fmt)
4037
            fmt = stream_fmt;
4038
    }
4039

    
4040
    return fmt;
4041
}
4042

    
4043
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4044
{
4045
    va_list vl;
4046
    va_start(vl, fmt);
4047
    fprintf(stderr, "%s:%d: ", filename, line_num);
4048
    vfprintf(stderr, fmt, vl);
4049
    va_end(vl);
4050

    
4051
    (*errors)++;
4052
}
4053

    
4054
static int parse_ffconfig(const char *filename)
4055
{
4056
    FILE *f;
4057
    char line[1024];
4058
    char cmd[64];
4059
    char arg[1024];
4060
    const char *p;
4061
    int val, errors, line_num;
4062
    FFStream **last_stream, *stream, *redirect;
4063
    FFStream **last_feed, *feed, *s;
4064
    AVCodecContext audio_enc, video_enc;
4065
    enum CodecID audio_id, video_id;
4066

    
4067
    f = fopen(filename, "r");
4068
    if (!f) {
4069
        perror(filename);
4070
        return -1;
4071
    }
4072

    
4073
    errors = 0;
4074
    line_num = 0;
4075
    first_stream = NULL;
4076
    last_stream = &first_stream;
4077
    first_feed = NULL;
4078
    last_feed = &first_feed;
4079
    stream = NULL;
4080
    feed = NULL;
4081
    redirect = NULL;
4082
    audio_id = CODEC_ID_NONE;
4083
    video_id = CODEC_ID_NONE;
4084

    
4085
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4086
    for(;;) {
4087
        if (fgets(line, sizeof(line), f) == NULL)
4088
            break;
4089
        line_num++;
4090
        p = line;
4091
        while (isspace(*p))
4092
            p++;
4093
        if (*p == '\0' || *p == '#')
4094
            continue;
4095

    
4096
        get_arg(cmd, sizeof(cmd), &p);
4097

    
4098
        if (!strcasecmp(cmd, "Port")) {
4099
            get_arg(arg, sizeof(arg), &p);
4100
            val = atoi(arg);
4101
            if (val < 1 || val > 65536) {
4102
                ERROR("Invalid_port: %s\n", arg);
4103
            }
4104
            my_http_addr.sin_port = htons(val);
4105
        } else if (!strcasecmp(cmd, "BindAddress")) {
4106
            get_arg(arg, sizeof(arg), &p);
4107
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4108
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4109
            }
4110
        } else if (!strcasecmp(cmd, "NoDaemon")) {
4111
            ffserver_daemon = 0;
4112
        } else if (!strcasecmp(cmd, "RTSPPort")) {
4113
            get_arg(arg, sizeof(arg), &p);
4114
            val = atoi(arg);
4115
            if (val < 1 || val > 65536) {
4116
                ERROR("%s:%d: Invalid port: %s\n", arg);
4117
            }
4118
            my_rtsp_addr.sin_port = htons(atoi(arg));
4119
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4120
            get_arg(arg, sizeof(arg), &p);
4121
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4122
                ERROR("Invalid host/IP address: %s\n", arg);
4123
            }
4124
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4125
            get_arg(arg, sizeof(arg), &p);
4126
            val = atoi(arg);
4127
            if (val < 1 || val > 65536) {
4128
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4129
            }
4130
            nb_max_http_connections = val;
4131
        } else if (!strcasecmp(cmd, "MaxClients")) {
4132
            get_arg(arg, sizeof(arg), &p);
4133
            val = atoi(arg);
4134
            if (val < 1 || val > nb_max_http_connections) {
4135
                ERROR("Invalid MaxClients: %s\n", arg);
4136
            } else {
4137
                nb_max_connections = val;
4138
            }
4139
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4140
            int64_t llval;
4141
            get_arg(arg, sizeof(arg), &p);
4142
            llval = atoll(arg);
4143
            if (llval < 10 || llval > 10000000) {
4144
                ERROR("Invalid MaxBandwidth: %s\n", arg);
4145
            } else
4146
                max_bandwidth = llval;
4147
        } else if (!strcasecmp(cmd, "CustomLog")) {
4148
            if (!ffserver_debug)
4149
                get_arg(logfilename, sizeof(logfilename), &p);
4150
        } else if (!strcasecmp(cmd, "<Feed")) {
4151
            /*********************************************/
4152
            /* Feed related options */
4153
            char *q;
4154
            if (stream || feed) {
4155
                ERROR("Already in a tag\n");
4156
            } else {
4157
                feed = av_mallocz(sizeof(FFStream));
4158
                get_arg(feed->filename, sizeof(feed->filename), &p);
4159
                q = strrchr(feed->filename, '>');
4160
                if (*q)
4161
                    *q = '\0';
4162

    
4163
                for (s = first_feed; s; s = s->next) {
4164
                    if (!strcmp(feed->filename, s->filename)) {
4165
                        ERROR("Feed '%s' already registered\n", s->filename);
4166
                    }
4167
                }
4168

    
4169
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4170
                /* defaut feed file */
4171
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4172
                         "/tmp/%s.ffm", feed->filename);
4173
                feed->feed_max_size = 5 * 1024 * 1024;
4174
                feed->is_feed = 1;
4175
                feed->feed = feed; /* self feeding :-) */
4176

    
4177
                /* add in stream list */
4178
                *last_stream = feed;
4179
                last_stream = &feed->next;
4180
                /* add in feed list */
4181
                *last_feed = feed;
4182
                last_feed = &feed->next_feed;
4183
            }
4184
        } else if (!strcasecmp(cmd, "Launch")) {
4185
            if (feed) {
4186
                int i;
4187

    
4188
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4189

    
4190
                for (i = 0; i < 62; i++) {
4191
                    get_arg(arg, sizeof(arg), &p);
4192
                    if (!arg[0])
4193
                        break;
4194

    
4195
                    feed->child_argv[i] = av_strdup(arg);
4196
                }
4197

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

    
4200
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4201
                    "http://%s:%d/%s",
4202
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4203
                    inet_ntoa(my_http_addr.sin_addr),
4204
                    ntohs(my_http_addr.sin_port), feed->filename);
4205
            }
4206
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4207
            if (feed) {
4208
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4209
                feed->readonly = 1;
4210
            } else if (stream) {
4211
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4212
            }
4213
        } else if (!strcasecmp(cmd, "File")) {
4214
            if (feed) {
4215
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4216
            } else if (stream)
4217
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4218
        } else if (!strcasecmp(cmd, "Truncate")) {
4219
            if (feed) {
4220
                get_arg(arg, sizeof(arg), &p);
4221
                feed->truncate = strtod(arg, NULL);
4222
            }
4223
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4224
            if (feed) {
4225
                char *p1;
4226
                double fsize;
4227

    
4228
                get_arg(arg, sizeof(arg), &p);
4229
                p1 = arg;
4230
                fsize = strtod(p1, &p1);
4231
                switch(toupper(*p1)) {
4232
                case 'K':
4233
                    fsize *= 1024;
4234
                    break;
4235
                case 'M':
4236
                    fsize *= 1024 * 1024;
4237
                    break;
4238
                case 'G':
4239
                    fsize *= 1024 * 1024 * 1024;
4240
                    break;
4241
                }
4242
                feed->feed_max_size = (int64_t)fsize;
4243
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4244
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4245
                }
4246
            }
4247
        } else if (!strcasecmp(cmd, "</Feed>")) {
4248
            if (!feed) {
4249
                ERROR("No corresponding <Feed> for </Feed>\n");
4250
            }
4251
            feed = NULL;
4252
        } else if (!strcasecmp(cmd, "<Stream")) {
4253
            /*********************************************/
4254
            /* Stream related options */
4255
            char *q;
4256
            if (stream || feed) {
4257
                ERROR("Already in a tag\n");
4258
            } else {
4259
                FFStream *s;
4260
                stream = av_mallocz(sizeof(FFStream));
4261
                get_arg(stream->filename, sizeof(stream->filename), &p);
4262
                q = strrchr(stream->filename, '>');
4263
                if (*q)
4264
                    *q = '\0';
4265

    
4266
                for (s = first_stream; s; s = s->next) {
4267
                    if (!strcmp(stream->filename, s->filename)) {
4268
                        ERROR("Stream '%s' already registered\n", s->filename);
4269
                    }
4270
                }
4271

    
4272
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4273
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4274
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4275
                audio_id = CODEC_ID_NONE;
4276
                video_id = CODEC_ID_NONE;
4277
                if (stream->fmt) {
4278
                    audio_id = stream->fmt->audio_codec;
4279
                    video_id = stream->fmt->video_codec;
4280
                }
4281

    
4282
                *last_stream = stream;
4283
                last_stream = &stream->next;
4284
            }
4285
        } else if (!strcasecmp(cmd, "Feed")) {
4286
            get_arg(arg, sizeof(arg), &p);
4287
            if (stream) {
4288
                FFStream *sfeed;
4289

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

    
4392
                get_arg(arg, sizeof(arg), &p);
4393

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

    
4618
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4619
                q = strrchr(redirect->filename, '>');
4620
                if (*q)
4621
                    *q = '\0';
4622
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4623
            }
4624
        } else if (!strcasecmp(cmd, "URL")) {
4625
            if (redirect)
4626
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4627
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4628
            if (!redirect) {
4629
                ERROR("No corresponding <Redirect> for </Redirect>\n");
4630
            } else {
4631
                if (!redirect->feed_filename[0]) {
4632
                    ERROR("No URL found for <Redirect>\n");
4633
                }
4634
                redirect = NULL;
4635
            }
4636
        } else if (!strcasecmp(cmd, "LoadModule")) {
4637
            get_arg(arg, sizeof(arg), &p);
4638
#if HAVE_DLOPEN
4639
            load_module(arg);
4640
#else
4641
            ERROR("Module support not compiled into this version: '%s'\n", arg);
4642
#endif
4643
        } else {
4644
            ERROR("Incorrect keyword: '%s'\n", cmd);
4645
        }
4646
    }
4647
#undef ERROR
4648

    
4649
    fclose(f);
4650
    if (errors)
4651
        return -1;
4652
    else
4653
        return 0;
4654
}
4655

    
4656
static void handle_child_exit(int sig)
4657
{
4658
    pid_t pid;
4659
    int status;
4660

    
4661
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4662
        FFStream *feed;
4663

    
4664
        for (feed = first_feed; feed; feed = feed->next) {
4665
            if (feed->pid == pid) {
4666
                int uptime = time(0) - feed->pid_start;
4667

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

    
4671
                if (uptime < 30)
4672
                    /* Turn off any more restarts */
4673
                    feed->child_argv = 0;
4674
            }
4675
        }
4676
    }
4677

    
4678
    need_to_start_children = 1;
4679
}
4680

    
4681
static void opt_debug(void)
4682
{
4683
    ffserver_debug = 1;
4684
    ffserver_daemon = 0;
4685
    logfilename[0] = '-';
4686
}
4687

    
4688
static void show_help(void)
4689
{
4690
    printf("usage: ffserver [options]\n"
4691
           "Hyper fast multi format Audio/Video streaming server\n");
4692
    printf("\n");
4693
    show_help_options(options, "Main options:\n", 0, 0);
4694
}
4695

    
4696
static const OptionDef options[] = {
4697
#include "cmdutils_common_opts.h"
4698
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4699
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4700
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4701
    { NULL },
4702
};
4703

    
4704
int main(int argc, char **argv)
4705
{
4706
    struct sigaction sigact;
4707

    
4708
    av_register_all();
4709

    
4710
    show_banner();
4711

    
4712
    my_program_name = argv[0];
4713
    my_program_dir = getcwd(0, 0);
4714
    ffserver_daemon = 1;
4715

    
4716
    parse_options(argc, argv, options, NULL);
4717

    
4718
    unsetenv("http_proxy");             /* Kill the http_proxy */
4719

    
4720
    av_lfg_init(&random_state, av_get_random_seed());
4721