Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 686d6f40

History | View | Annotate | Download (152 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

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

    
56
#include "cmdutils.h"
57

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

    
61
static const OptionDef options[];
62

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

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

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

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

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

    
94
#define IOBUFFER_INIT_SIZE 8192
95

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

    
100
#define SYNC_TIMEOUT (10 * 1000)
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
313
static AVLFG random_state;
314

    
315
static FILE *logfile = NULL;
316

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

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

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

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

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

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

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

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

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

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

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

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

    
434

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

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

    
444
            feed->pid = fork();
445

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

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

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

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

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

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

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

    
487
                signal(SIGPIPE, SIG_DFL);
488

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

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

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

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

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

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

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

    
526
    return server_fd;
527
}
528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
616
    start_children(first_feed);
617

    
618
    start_multicast();
619

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

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

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

    
692
        cur_time = av_gettime() / 1000;
693

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

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

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

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

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

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

    
754

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

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

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

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

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

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

    
792
    start_wait_request(c, is_rtsp);
793

    
794
    return;
795

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

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

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

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

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

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

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

    
857
    ctx = &c->fmt_ctx;
858

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

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

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

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

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

    
889
static int handle_connection(HTTPContext *c)
890
{
891
    int len, ret;
892

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

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

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

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

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

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

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

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

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

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

    
1074
            while (*q && *q != '\n' && isspace(*q))
1075
                q++;
1076

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

    
1081
                q += 20;
1082

    
1083
                memset(rates, 0xff, ratelen);
1084

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

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

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

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

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

    
1107
        p++;
1108
    }
1109

    
1110
    return 0;
1111
}
1112

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

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

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

    
1128
        /* Potential stream */
1129

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

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

    
1147
    return best;
1148
}
1149

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

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

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

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

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

    
1185
    return action_required;
1186
}
1187

    
1188

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

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

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

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

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

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

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

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

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

    
1280
    get_arg(arg, sizeof(arg), &p);
1281

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

    
1289
    get_arg(arg, sizeof(arg), &p);
1290

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

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

    
1303
        acl.next = 0;
1304
        *nacl = acl;
1305

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

    
1318
        if (naclp) {
1319
            while (*naclp)
1320
                naclp = &(*naclp)->next;
1321

    
1322
            *naclp = nacl;
1323
        }
1324
    }
1325
}
1326

    
1327

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

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

    
1343
    acl = av_mallocz(sizeof(IPAddressACL));
1344

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

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

    
1364

    
1365
static void free_acl_list(IPAddressACL *in_acl)
1366
{
1367
    IPAddressACL *pacl,*pacl2;
1368

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

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

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

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

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

    
1399

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

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

    
1406
        ret = validate_acl_list(acl, c);
1407

    
1408
        free_acl_list(acl);
1409
    }
1410

    
1411
    return ret;
1412
}
1413

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

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

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

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

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

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

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

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

    
1483
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1484

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

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

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

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

    
1509
        p++;
1510
    }
1511

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

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

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

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

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

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

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

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

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

    
1608
    if (redir_type != REDIR_NONE) {
1609
        char *hostinfo = 0;
1610

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

    
1620
            p++;
1621
        }
1622

    
1623
        if (hostinfo) {
1624
            char *eoh;
1625
            char hostbuf[260];
1626

    
1627
            while (isspace(*hostinfo))
1628
                hostinfo++;
1629

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

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

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

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

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

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

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

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

    
1728
    stream->conns_served++;
1729

    
1730
    /* XXX: add there authenticate and IP match */
1731

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

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

    
1751
                p++;
1752
            }
1753

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

    
1757
                logline += 17;
1758

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

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

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

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

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

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

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

    
1802
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1803
        goto send_status;
1804

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

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

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

    
1823
        c->wmp_client_id = av_lfg_get(&random_state);
1824

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2021
                url_fprintf(pb, "<p>");
2022
            }
2023
            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");
2024

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

    
2031
                parameters[0] = 0;
2032

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

    
2051
        }
2052
        stream = stream->next;
2053
    }
2054

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2225

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

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

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

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

    
2261
        c->got_key_frame = 0;
2262

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

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

    
2278
        av_set_parameters(&c->fmt_ctx, NULL);
2279
        if (av_write_header(&c->fmt_ctx) < 0) {
2280
            http_log("Error writing output header\n");
2281
            return -1;
2282
        }
2283

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2742
            for (i = 0; i < s->nb_streams; i++) {
2743
                AVStream *fst = feed->streams[i];
2744
                AVStream *st = s->streams[i];
2745
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2746
                if (fst->codec->extradata_size) {
2747
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2748
                    if (!fst->codec->extradata)
2749
                        goto fail;
2750
                    memcpy(fst->codec->extradata, st->codec->extradata,
2751
                           fst->codec->extradata_size);
2752
                }
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 = strchr(p, '\n');
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[MAX_STREAMS];
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
    for(i = 0; i < stream->nb_streams; i++) {
2952
        avc->streams[i] = &avs[i];
2953
        avc->streams[i]->codec = stream->streams[i]->codec;
2954
    }
2955
    *pbuffer = av_mallocz(2048);
2956
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2957
    av_free(avc);
2958

    
2959
    return strlen(*pbuffer);
2960
}
2961

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

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

    
2980
    /* find which url is asked */
2981
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2982
    path = path1;
2983
    if (*path == '/')
2984
        path++;
2985

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

    
2997
 found:
2998
    /* prepare the media description in sdp format */
2999

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

    
3015
static HTTPContext *find_rtp_session(const char *session_id)
3016
{
3017
    HTTPContext *c;
3018

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

    
3022
    for(c = first_http_ctx; c != NULL; c = c->next) {
3023
        if (!strcmp(c->session_id, session_id))
3024
            return c;
3025
    }
3026
    return NULL;
3027
}
3028

    
3029
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3030
{
3031
    RTSPTransportField *th;
3032
    int i;
3033

    
3034
    for(i=0;i<h->nb_transports;i++) {
3035
        th = &h->transports[i];
3036
        if (th->lower_transport == lower_transport)
3037
            return th;
3038
    }
3039
    return NULL;
3040
}
3041

    
3042
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3043
                           RTSPMessageHeader *h)
3044
{
3045
    FFStream *stream;
3046
    int stream_index, rtp_port, rtcp_port;
3047
    char buf[1024];
3048
    char path1[1024];
3049
    const char *path;
3050
    HTTPContext *rtp_c;
3051
    RTSPTransportField *th;
3052
    struct sockaddr_in dest_addr;
3053
    RTSPActionServerSetup setup;
3054

    
3055
    /* find which url is asked */
3056
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3057
    path = path1;
3058
    if (*path == '/')
3059
        path++;
3060

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

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

    
3089
    /* generate session id if needed */
3090
    if (h->session_id[0] == '\0')
3091
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3092
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3093

    
3094
    /* find rtp session, and create it if none found */
3095
    rtp_c = find_rtp_session(h->session_id);
3096
    if (!rtp_c) {
3097
        /* always prefer UDP */
3098
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3099
        if (!th) {
3100
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3101
            if (!th) {
3102
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3103
                return;
3104
            }
3105
        }
3106

    
3107
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3108
                                   th->lower_transport);
3109
        if (!rtp_c) {
3110
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3111
            return;
3112
        }
3113

    
3114
        /* open input stream */
3115
        if (open_input_stream(rtp_c, "") < 0) {
3116
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3117
            return;
3118
        }
3119
    }
3120

    
3121
    /* test if stream is OK (test needed because several SETUP needs
3122
       to be done for a given file) */
3123
    if (rtp_c->stream != stream) {
3124
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3125
        return;
3126
    }
3127

    
3128
    /* test if stream is already set up */
3129
    if (rtp_c->rtp_ctx[stream_index]) {
3130
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3131
        return;
3132
    }
3133

    
3134
    /* check transport */
3135
    th = find_transport(h, rtp_c->rtp_protocol);
3136
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3137
                th->client_port_min <= 0)) {
3138
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3139
        return;
3140
    }
3141

    
3142
    /* setup default options */
3143
    setup.transport_option[0] = '\0';
3144
    dest_addr = rtp_c->from_addr;
3145
    dest_addr.sin_port = htons(th->client_port_min);
3146

    
3147
    /* setup stream */
3148
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3149
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3150
        return;
3151
    }
3152

    
3153
    /* now everything is OK, so we can send the connection parameters */
3154
    rtsp_reply_header(c, RTSP_STATUS_OK);
3155
    /* session ID */
3156
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3157

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

    
3178

    
3179
    url_fprintf(c->pb, "\r\n");
3180
}
3181

    
3182

    
3183
/* find an rtp connection by using the session ID. Check consistency
3184
   with filename */
3185
static HTTPContext *find_rtp_session_with_url(const char *url,
3186
                                              const char *session_id)
3187
{
3188
    HTTPContext *rtp_c;
3189
    char path1[1024];
3190
    const char *path;
3191
    char buf[1024];
3192
    int s;
3193

    
3194
    rtp_c = find_rtp_session(session_id);
3195
    if (!rtp_c)
3196
        return NULL;
3197

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

    
3215
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3216
{
3217
    HTTPContext *rtp_c;
3218

    
3219
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3220
    if (!rtp_c) {
3221
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3222
        return;
3223
    }
3224

    
3225
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3226
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3227
        rtp_c->state != HTTPSTATE_READY) {
3228
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3229
        return;
3230
    }
3231

    
3232
    rtp_c->state = HTTPSTATE_SEND_DATA;
3233

    
3234
    /* now everything is OK, so we can send the connection parameters */
3235
    rtsp_reply_header(c, RTSP_STATUS_OK);
3236
    /* session ID */
3237
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3238
    url_fprintf(c->pb, "\r\n");
3239
}
3240

    
3241
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3242
{
3243
    HTTPContext *rtp_c;
3244

    
3245
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3246
    if (!rtp_c) {
3247
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3248
        return;
3249
    }
3250

    
3251
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3252
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3253
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3254
        return;
3255
    }
3256

    
3257
    rtp_c->state = HTTPSTATE_READY;
3258
    rtp_c->first_pts = AV_NOPTS_VALUE;
3259
    /* now everything is OK, so we can send the connection parameters */
3260
    rtsp_reply_header(c, RTSP_STATUS_OK);
3261
    /* session ID */
3262
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3263
    url_fprintf(c->pb, "\r\n");
3264
}
3265

    
3266
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3267
{
3268
    HTTPContext *rtp_c;
3269
    char session_id[32];
3270

    
3271
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3272
    if (!rtp_c) {
3273
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3274
        return;
3275
    }
3276

    
3277
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3278

    
3279
    /* abort the session */
3280
    close_connection(rtp_c);
3281

    
3282
    /* now everything is OK, so we can send the connection parameters */
3283
    rtsp_reply_header(c, RTSP_STATUS_OK);
3284
    /* session ID */
3285
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3286
    url_fprintf(c->pb, "\r\n");
3287
}
3288

    
3289

    
3290
/********************************************************************/
3291
/* RTP handling */
3292

    
3293
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3294
                                       FFStream *stream, const char *session_id,
3295
                                       enum RTSPLowerTransport rtp_protocol)
3296
{
3297
    HTTPContext *c = NULL;
3298
    const char *proto_str;
3299

    
3300
    /* XXX: should output a warning page when coming
3301
       close to the connection limit */
3302
    if (nb_connections >= nb_max_connections)
3303
        goto fail;
3304

    
3305
    /* add a new connection */
3306
    c = av_mallocz(sizeof(HTTPContext));
3307
    if (!c)
3308
        goto fail;
3309

    
3310
    c->fd = -1;
3311
    c->poll_entry = NULL;
3312
    c->from_addr = *from_addr;
3313
    c->buffer_size = IOBUFFER_INIT_SIZE;
3314
    c->buffer = av_malloc(c->buffer_size);
3315
    if (!c->buffer)
3316
        goto fail;
3317
    nb_connections++;
3318
    c->stream = stream;
3319
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3320
    c->state = HTTPSTATE_READY;
3321
    c->is_packetized = 1;
3322
    c->rtp_protocol = rtp_protocol;
3323

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

    
3342
    current_bandwidth += stream->bandwidth;
3343

    
3344
    c->next = first_http_ctx;
3345
    first_http_ctx = c;
3346
    return c;
3347

    
3348
 fail:
3349
    if (c) {
3350
        av_free(c->buffer);
3351
        av_free(c);
3352
    }
3353
    return NULL;
3354
}
3355

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

    
3370
    /* now we can open the relevant output stream */
3371
    ctx = avformat_alloc_context();
3372
    if (!ctx)
3373
        return -1;
3374
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3375

    
3376
    st = av_mallocz(sizeof(AVStream));
3377
    if (!st)
3378
        goto fail;
3379
    st->codec= avcodec_alloc_context();
3380
    ctx->nb_streams = 1;
3381
    ctx->streams[0] = st;
3382

    
3383
    if (!c->stream->feed ||
3384
        c->stream->feed == c->stream)
3385
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3386
    else
3387
        memcpy(st,
3388
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3389
               sizeof(AVStream));
3390
    st->priv_data = NULL;
3391

    
3392
    /* build destination RTP address */
3393
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3394

    
3395
    switch(c->rtp_protocol) {
3396
    case RTSP_LOWER_TRANSPORT_UDP:
3397
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3398
        /* RTP/UDP case */
3399

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

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

    
3428
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3429
             ipaddr, ntohs(dest_addr->sin_port),
3430
             c->stream->filename, stream_index, c->protocol);
3431

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

    
3448
    c->rtp_ctx[stream_index] = ctx;
3449
    return 0;
3450
}
3451

    
3452
/********************************************************************/
3453
/* ffserver initialization */
3454

    
3455
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3456
{
3457
    AVStream *fst;
3458

    
3459
    fst = av_mallocz(sizeof(AVStream));
3460
    if (!fst)
3461
        return NULL;
3462
    fst->codec= avcodec_alloc_context();
3463
    fst->priv_data = av_mallocz(sizeof(FeedData));
3464
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3465
    fst->index = stream->nb_streams;
3466
    av_set_pts_info(fst, 33, 1, 90000);
3467
    stream->streams[stream->nb_streams++] = fst;
3468
    return fst;
3469
}
3470

    
3471
/* return the stream number in the feed */
3472
static int add_av_stream(FFStream *feed, AVStream *st)
3473
{
3474
    AVStream *fst;
3475
    AVCodecContext *av, *av1;
3476
    int i;
3477

    
3478
    av = st->codec;
3479
    for(i=0;i<feed->nb_streams;i++) {
3480
        st = feed->streams[i];
3481
        av1 = st->codec;
3482
        if (av1->codec_id == av->codec_id &&
3483
            av1->codec_type == av->codec_type &&
3484
            av1->bit_rate == av->bit_rate) {
3485

    
3486
            switch(av->codec_type) {
3487
            case AVMEDIA_TYPE_AUDIO:
3488
                if (av1->channels == av->channels &&
3489
                    av1->sample_rate == av->sample_rate)
3490
                    goto found;
3491
                break;
3492
            case AVMEDIA_TYPE_VIDEO:
3493
                if (av1->width == av->width &&
3494
                    av1->height == av->height &&
3495
                    av1->time_base.den == av->time_base.den &&
3496
                    av1->time_base.num == av->time_base.num &&
3497
                    av1->gop_size == av->gop_size)
3498
                    goto found;
3499
                break;
3500
            default:
3501
                abort();
3502
            }
3503
        }
3504
    }
3505

    
3506
    fst = add_av_stream1(feed, av);
3507
    if (!fst)
3508
        return -1;
3509
    return feed->nb_streams - 1;
3510
 found:
3511
    return i;
3512
}
3513

    
3514
static void remove_stream(FFStream *stream)
3515
{
3516
    FFStream **ps;
3517
    ps = &first_stream;
3518
    while (*ps != NULL) {
3519
        if (*ps == stream)
3520
            *ps = (*ps)->next;
3521
        else
3522
            ps = &(*ps)->next;
3523
    }
3524
}
3525

    
3526
/* specific mpeg4 handling : we extract the raw parameters */
3527
static void extract_mpeg4_header(AVFormatContext *infile)
3528
{
3529
    int mpeg4_count, i, size;
3530
    AVPacket pkt;
3531
    AVStream *st;
3532
    const uint8_t *p;
3533

    
3534
    mpeg4_count = 0;
3535
    for(i=0;i<infile->nb_streams;i++) {
3536
        st = infile->streams[i];
3537
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3538
            st->codec->extradata_size == 0) {
3539
            mpeg4_count++;
3540
        }
3541
    }
3542
    if (!mpeg4_count)
3543
        return;
3544

    
3545
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3546
    while (mpeg4_count > 0) {
3547
        if (av_read_packet(infile, &pkt) < 0)
3548
            break;
3549
        st = infile->streams[pkt.stream_index];
3550
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3551
            st->codec->extradata_size == 0) {
3552
            av_freep(&st->codec->extradata);
3553
            /* fill extradata with the header */
3554
            /* XXX: we make hard suppositions here ! */
3555
            p = pkt.data;
3556
            while (p < pkt.data + pkt.size - 4) {
3557
                /* stop when vop header is found */
3558
                if (p[0] == 0x00 && p[1] == 0x00 &&
3559
                    p[2] == 0x01 && p[3] == 0xb6) {
3560
                    size = p - pkt.data;
3561
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3562
                    st->codec->extradata = av_malloc(size);
3563
                    st->codec->extradata_size = size;
3564
                    memcpy(st->codec->extradata, pkt.data, size);
3565
                    break;
3566
                }
3567
                p++;
3568
            }
3569
            mpeg4_count--;
3570
        }
3571
        av_free_packet(&pkt);
3572
    }
3573
}
3574

    
3575
/* compute the needed AVStream for each file */
3576
static void build_file_streams(void)
3577
{
3578
    FFStream *stream, *stream_next;
3579
    AVFormatContext *infile;
3580
    int i, ret;
3581

    
3582
    /* gather all streams */
3583
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3584
        stream_next = stream->next;
3585
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3586
            !stream->feed) {
3587
            /* the stream comes from a file */
3588
            /* try to open the file */
3589
            /* open stream */
3590
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3591
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3592
                /* specific case : if transport stream output to RTP,
3593
                   we use a raw transport stream reader */
3594
                stream->ap_in->mpeg2ts_raw = 1;
3595
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3596
            }
3597

    
3598
            http_log("Opening file '%s'\n", stream->feed_filename);
3599
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3600
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3601
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3602
                /* remove stream (no need to spend more time on it) */
3603
            fail:
3604
                remove_stream(stream);
3605
            } else {
3606
                /* find all the AVStreams inside and reference them in
3607
                   'stream' */
3608
                if (av_find_stream_info(infile) < 0) {
3609
                    http_log("Could not find codec parameters from '%s'\n",
3610
                             stream->feed_filename);
3611
                    av_close_input_file(infile);
3612
                    goto fail;
3613
                }
3614
                extract_mpeg4_header(infile);
3615

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

    
3619
                av_close_input_file(infile);
3620
            }
3621
        }
3622
    }
3623
}
3624

    
3625
/* compute the needed AVStream for each feed */
3626
static void build_feed_streams(void)
3627
{
3628
    FFStream *stream, *feed;
3629
    int i;
3630

    
3631
    /* gather all streams */
3632
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3633
        feed = stream->feed;
3634
        if (feed) {
3635
            if (!stream->is_feed) {
3636
                /* we handle a stream coming from a feed */
3637
                for(i=0;i<stream->nb_streams;i++)
3638
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3639
            }
3640
        }
3641
    }
3642

    
3643
    /* gather all streams */
3644
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3645
        feed = stream->feed;
3646
        if (feed) {
3647
            if (stream->is_feed) {
3648
                for(i=0;i<stream->nb_streams;i++)
3649
                    stream->feed_streams[i] = i;
3650
            }
3651
        }
3652
    }
3653

    
3654
    /* create feed files if needed */
3655
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3656
        int fd;
3657

    
3658
        if (url_exist(feed->feed_filename)) {
3659
            /* See if it matches */
3660
            AVFormatContext *s;
3661
            int matches = 0;
3662

    
3663
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3664
                /* Now see if it matches */
3665
                if (s->nb_streams == feed->nb_streams) {
3666
                    matches = 1;
3667
                    for(i=0;i<s->nb_streams;i++) {
3668
                        AVStream *sf, *ss;
3669
                        sf = feed->streams[i];
3670
                        ss = s->streams[i];
3671

    
3672
                        if (sf->index != ss->index ||
3673
                            sf->id != ss->id) {
3674
                            http_log("Index & Id do not match for stream %d (%s)\n",
3675
                                   i, feed->feed_filename);
3676
                            matches = 0;
3677
                        } else {
3678
                            AVCodecContext *ccf, *ccs;
3679

    
3680
                            ccf = sf->codec;
3681
                            ccs = ss->codec;
3682
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3683

    
3684
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3685
                                http_log("Codecs do not match for stream %d\n", i);
3686
                                matches = 0;
3687
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3688
                                http_log("Codec bitrates do not match for stream %d\n", i);
3689
                                matches = 0;
3690
                            } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3691
                                if (CHECK_CODEC(time_base.den) ||
3692
                                    CHECK_CODEC(time_base.num) ||
3693
                                    CHECK_CODEC(width) ||
3694
                                    CHECK_CODEC(height)) {
3695
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3696
                                    matches = 0;
3697
                                }
3698
                            } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3699
                                if (CHECK_CODEC(sample_rate) ||
3700
                                    CHECK_CODEC(channels) ||
3701
                                    CHECK_CODEC(frame_size)) {
3702
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3703
                                    matches = 0;
3704
                                }
3705
                            } else {
3706
                                http_log("Unknown codec type\n");
3707
                                matches = 0;
3708
                            }
3709
                        }
3710
                        if (!matches)
3711
                            break;
3712
                    }
3713
                } else
3714
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3715
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3716

    
3717
                av_close_input_file(s);
3718
            } else
3719
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3720
                        feed->feed_filename);
3721

    
3722
            if (!matches) {
3723
                if (feed->readonly) {
3724
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3725
                        feed->feed_filename);
3726
                    exit(1);
3727
                }
3728
                unlink(feed->feed_filename);
3729
            }
3730
        }
3731
        if (!url_exist(feed->feed_filename)) {
3732
            AVFormatContext s1 = {0}, *s = &s1;
3733

    
3734
            if (feed->readonly) {
3735
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3736
                    feed->feed_filename);
3737
                exit(1);
3738
            }
3739

    
3740
            /* only write the header of the ffm file */
3741
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3742
                http_log("Could not open output feed file '%s'\n",
3743
                         feed->feed_filename);
3744
                exit(1);
3745
            }
3746
            s->oformat = feed->fmt;
3747
            s->nb_streams = feed->nb_streams;
3748
            for(i=0;i<s->nb_streams;i++) {
3749
                AVStream *st;
3750
                st = feed->streams[i];
3751
                s->streams[i] = st;
3752
            }
3753
            av_set_parameters(s, NULL);
3754
            if (av_write_header(s) < 0) {
3755
                http_log("Container doesn't supports the required parameters\n");
3756
                exit(1);
3757
            }
3758
            /* XXX: need better api */
3759
            av_freep(&s->priv_data);
3760
            url_fclose(s->pb);
3761
        }
3762
        /* get feed size and write index */
3763
        fd = open(feed->feed_filename, O_RDONLY);
3764
        if (fd < 0) {
3765
            http_log("Could not open output feed file '%s'\n",
3766
                    feed->feed_filename);
3767
            exit(1);
3768
        }
3769

    
3770
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3771
        feed->feed_size = lseek(fd, 0, SEEK_END);
3772
        /* ensure that we do not wrap before the end of file */
3773
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3774
            feed->feed_max_size = feed->feed_size;
3775

    
3776
        close(fd);
3777
    }
3778
}
3779

    
3780
/* compute the bandwidth used by each stream */
3781
static void compute_bandwidth(void)
3782
{
3783
    unsigned bandwidth;
3784
    int i;
3785
    FFStream *stream;
3786

    
3787
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3788
        bandwidth = 0;
3789
        for(i=0;i<stream->nb_streams;i++) {
3790
            AVStream *st = stream->streams[i];
3791
            switch(st->codec->codec_type) {
3792
            case AVMEDIA_TYPE_AUDIO:
3793
            case AVMEDIA_TYPE_VIDEO:
3794
                bandwidth += st->codec->bit_rate;
3795
                break;
3796
            default:
3797
                break;
3798
            }
3799
        }
3800
        stream->bandwidth = (bandwidth + 999) / 1000;
3801
    }
3802
}
3803

    
3804
/* add a codec and set the default parameters */
3805
static void add_codec(FFStream *stream, AVCodecContext *av)
3806
{
3807
    AVStream *st;
3808

    
3809
    /* compute default parameters */
3810
    switch(av->codec_type) {
3811
    case AVMEDIA_TYPE_AUDIO:
3812
        if (av->bit_rate == 0)
3813
            av->bit_rate = 64000;
3814
        if (av->sample_rate == 0)
3815
            av->sample_rate = 22050;
3816
        if (av->channels == 0)
3817
            av->channels = 1;
3818
        break;
3819
    case AVMEDIA_TYPE_VIDEO:
3820
        if (av->bit_rate == 0)
3821
            av->bit_rate = 64000;
3822
        if (av->time_base.num == 0){
3823
            av->time_base.den = 5;
3824
            av->time_base.num = 1;
3825
        }
3826
        if (av->width == 0 || av->height == 0) {
3827
            av->width = 160;
3828
            av->height = 128;
3829
        }
3830
        /* Bitrate tolerance is less for streaming */
3831
        if (av->bit_rate_tolerance == 0)
3832
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3833
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3834
        if (av->qmin == 0)
3835
            av->qmin = 3;
3836
        if (av->qmax == 0)
3837
            av->qmax = 31;
3838
        if (av->max_qdiff == 0)
3839
            av->max_qdiff = 3;
3840
        av->qcompress = 0.5;
3841
        av->qblur = 0.5;
3842

    
3843
        if (!av->nsse_weight)
3844
            av->nsse_weight = 8;
3845

    
3846
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3847
        if (!av->me_method)
3848
            av->me_method = ME_EPZS;
3849
        av->rc_buffer_aggressivity = 1.0;
3850

    
3851
        if (!av->rc_eq)
3852
            av->rc_eq = "tex^qComp";
3853
        if (!av->i_quant_factor)
3854
            av->i_quant_factor = -0.8;
3855
        if (!av->b_quant_factor)
3856
            av->b_quant_factor = 1.25;
3857
        if (!av->b_quant_offset)
3858
            av->b_quant_offset = 1.25;
3859
        if (!av->rc_max_rate)
3860
            av->rc_max_rate = av->bit_rate * 2;
3861

    
3862
        if (av->rc_max_rate && !av->rc_buffer_size) {
3863
            av->rc_buffer_size = av->rc_max_rate;
3864
        }
3865

    
3866

    
3867
        break;
3868
    default:
3869
        abort();
3870
    }
3871

    
3872
    st = av_mallocz(sizeof(AVStream));
3873
    if (!st)
3874
        return;
3875
    st->codec = avcodec_alloc_context();
3876
    stream->streams[stream->nb_streams++] = st;
3877
    memcpy(st->codec, av, sizeof(AVCodecContext));
3878
}
3879

    
3880
static enum CodecID opt_audio_codec(const char *arg)
3881
{
3882
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3883

    
3884
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3885
        return CODEC_ID_NONE;
3886

    
3887
    return p->id;
3888
}
3889

    
3890
static enum CodecID opt_video_codec(const char *arg)
3891
{
3892
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3893

    
3894
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3895
        return CODEC_ID_NONE;
3896

    
3897
    return p->id;
3898
}
3899

    
3900
/* simplistic plugin support */
3901

    
3902
#if HAVE_DLOPEN
3903
static void load_module(const char *filename)
3904
{
3905
    void *dll;
3906
    void (*init_func)(void);
3907
    dll = dlopen(filename, RTLD_NOW);
3908
    if (!dll) {
3909
        fprintf(stderr, "Could not load module '%s' - %s\n",
3910
                filename, dlerror());
3911
        return;
3912
    }
3913

    
3914
    init_func = dlsym(dll, "ffserver_module_init");
3915
    if (!init_func) {
3916
        fprintf(stderr,
3917
                "%s: init function 'ffserver_module_init()' not found\n",
3918
                filename);
3919
        dlclose(dll);
3920
    }
3921

    
3922
    init_func();
3923
}
3924
#endif
3925

    
3926
static int ffserver_opt_default(const char *opt, const char *arg,
3927
                       AVCodecContext *avctx, int type)
3928
{
3929
    int ret = 0;
3930
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3931
    if(o)
3932
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3933
    return ret;
3934
}
3935

    
3936
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3937
                                             const char *mime_type)
3938
{
3939
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3940

    
3941
    if (fmt) {
3942
        AVOutputFormat *stream_fmt;
3943
        char stream_format_name[64];
3944

    
3945
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3946
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3947

    
3948
        if (stream_fmt)
3949
            fmt = stream_fmt;
3950
    }
3951

    
3952
    return fmt;
3953
}
3954

    
3955
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3956
{
3957
    va_list vl;
3958
    va_start(vl, fmt);
3959
    fprintf(stderr, "%s:%d: ", filename, line_num);
3960
    vfprintf(stderr, fmt, vl);
3961
    va_end(vl);
3962

    
3963
    (*errors)++;
3964
}
3965

    
3966
static int parse_ffconfig(const char *filename)
3967
{
3968
    FILE *f;
3969
    char line[1024];
3970
    char cmd[64];
3971
    char arg[1024];
3972
    const char *p;
3973
    int val, errors, line_num;
3974
    FFStream **last_stream, *stream, *redirect;
3975
    FFStream **last_feed, *feed, *s;
3976
    AVCodecContext audio_enc, video_enc;
3977
    enum CodecID audio_id, video_id;
3978

    
3979
    f = fopen(filename, "r");
3980
    if (!f) {
3981
        perror(filename);
3982
        return -1;
3983
    }
3984

    
3985
    errors = 0;
3986
    line_num = 0;
3987
    first_stream = NULL;
3988
    last_stream = &first_stream;
3989
    first_feed = NULL;
3990
    last_feed = &first_feed;
3991
    stream = NULL;
3992
    feed = NULL;
3993
    redirect = NULL;
3994
    audio_id = CODEC_ID_NONE;
3995
    video_id = CODEC_ID_NONE;
3996

    
3997
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
3998
    for(;;) {
3999
        if (fgets(line, sizeof(line), f) == NULL)
4000
            break;
4001
        line_num++;
4002
        p = line;
4003
        while (isspace(*p))
4004
            p++;
4005
        if (*p == '\0' || *p == '#')
4006
            continue;
4007

    
4008
        get_arg(cmd, sizeof(cmd), &p);
4009

    
4010
        if (!strcasecmp(cmd, "Port")) {
4011
            get_arg(arg, sizeof(arg), &p);
4012
            val = atoi(arg);
4013
            if (val < 1 || val > 65536) {
4014
                ERROR("Invalid_port: %s\n", arg);
4015
            }
4016
            my_http_addr.sin_port = htons(val);
4017
        } else if (!strcasecmp(cmd, "BindAddress")) {
4018
            get_arg(arg, sizeof(arg), &p);
4019
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4020
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4021
            }
4022
        } else if (!strcasecmp(cmd, "NoDaemon")) {
4023
            ffserver_daemon = 0;
4024
        } else if (!strcasecmp(cmd, "RTSPPort")) {
4025
            get_arg(arg, sizeof(arg), &p);
4026
            val = atoi(arg);
4027
            if (val < 1 || val > 65536) {
4028
                ERROR("%s:%d: Invalid port: %s\n", arg);
4029
            }
4030
            my_rtsp_addr.sin_port = htons(atoi(arg));
4031
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4032
            get_arg(arg, sizeof(arg), &p);
4033
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4034
                ERROR("Invalid host/IP address: %s\n", arg);
4035
            }
4036
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4037
            get_arg(arg, sizeof(arg), &p);
4038
            val = atoi(arg);
4039
            if (val < 1 || val > 65536) {
4040
                ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4041
            }
4042
            nb_max_http_connections = val;
4043
        } else if (!strcasecmp(cmd, "MaxClients")) {
4044
            get_arg(arg, sizeof(arg), &p);
4045
            val = atoi(arg);
4046
            if (val < 1 || val > nb_max_http_connections) {
4047
                ERROR("Invalid MaxClients: %s\n", arg);
4048
            } else {
4049
                nb_max_connections = val;
4050
            }
4051
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4052
            int64_t llval;
4053
            get_arg(arg, sizeof(arg), &p);
4054
            llval = atoll(arg);
4055
            if (llval < 10 || llval > 10000000) {
4056
                ERROR("Invalid MaxBandwidth: %s\n", arg);
4057
            } else
4058
                max_bandwidth = llval;
4059
        } else if (!strcasecmp(cmd, "CustomLog")) {
4060
            if (!ffserver_debug)
4061
                get_arg(logfilename, sizeof(logfilename), &p);
4062
        } else if (!strcasecmp(cmd, "<Feed")) {
4063
            /*********************************************/
4064
            /* Feed related options */
4065
            char *q;
4066
            if (stream || feed) {
4067
                ERROR("Already in a tag\n");
4068
            } else {
4069
                feed = av_mallocz(sizeof(FFStream));
4070
                get_arg(feed->filename, sizeof(feed->filename), &p);
4071
                q = strrchr(feed->filename, '>');
4072
                if (*q)
4073
                    *q = '\0';
4074

    
4075
                for (s = first_feed; s; s = s->next) {
4076
                    if (!strcmp(feed->filename, s->filename)) {
4077
                        ERROR("Feed '%s' already registered\n", s->filename);
4078
                    }
4079
                }
4080

    
4081
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4082
                /* defaut feed file */
4083
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4084
                         "/tmp/%s.ffm", feed->filename);
4085
                feed->feed_max_size = 5 * 1024 * 1024;
4086
                feed->is_feed = 1;
4087
                feed->feed = feed; /* self feeding :-) */
4088

    
4089
                /* add in stream list */
4090
                *last_stream = feed;
4091
                last_stream = &feed->next;
4092
                /* add in feed list */
4093
                *last_feed = feed;
4094
                last_feed = &feed->next_feed;
4095
            }
4096
        } else if (!strcasecmp(cmd, "Launch")) {
4097
            if (feed) {
4098
                int i;
4099

    
4100
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4101

    
4102
                for (i = 0; i < 62; i++) {
4103
                    get_arg(arg, sizeof(arg), &p);
4104
                    if (!arg[0])
4105
                        break;
4106

    
4107
                    feed->child_argv[i] = av_strdup(arg);
4108
                }
4109

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

    
4112
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4113
                    "http://%s:%d/%s",
4114
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4115
                    inet_ntoa(my_http_addr.sin_addr),
4116
                    ntohs(my_http_addr.sin_port), feed->filename);
4117
            }
4118
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4119
            if (feed) {
4120
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4121
                feed->readonly = 1;
4122
            } else if (stream) {
4123
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4124
            }
4125
        } else if (!strcasecmp(cmd, "File")) {
4126
            if (feed) {
4127
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4128
            } else if (stream)
4129
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4130
        } else if (!strcasecmp(cmd, "Truncate")) {
4131
            if (feed) {
4132
                get_arg(arg, sizeof(arg), &p);
4133
                feed->truncate = strtod(arg, NULL);
4134
            }
4135
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
4136
            if (feed) {
4137
                char *p1;
4138
                double fsize;
4139

    
4140
                get_arg(arg, sizeof(arg), &p);
4141
                p1 = arg;
4142
                fsize = strtod(p1, &p1);
4143
                switch(toupper(*p1)) {
4144
                case 'K':
4145
                    fsize *= 1024;
4146
                    break;
4147
                case 'M':
4148
                    fsize *= 1024 * 1024;
4149
                    break;
4150
                case 'G':
4151
                    fsize *= 1024 * 1024 * 1024;
4152
                    break;
4153
                }
4154
                feed->feed_max_size = (int64_t)fsize;
4155
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4156
                    ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4157
                }
4158
            }
4159
        } else if (!strcasecmp(cmd, "</Feed>")) {
4160
            if (!feed) {
4161
                ERROR("No corresponding <Feed> for </Feed>\n");
4162
            }
4163
            feed = NULL;
4164
        } else if (!strcasecmp(cmd, "<Stream")) {
4165
            /*********************************************/
4166
            /* Stream related options */
4167
            char *q;
4168
            if (stream || feed) {
4169
                ERROR("Already in a tag\n");
4170
            } else {
4171
                FFStream *s;
4172
                stream = av_mallocz(sizeof(FFStream));
4173
                get_arg(stream->filename, sizeof(stream->filename), &p);
4174
                q = strrchr(stream->filename, '>');
4175
                if (*q)
4176
                    *q = '\0';
4177

    
4178
                for (s = first_stream; s; s = s->next) {
4179
                    if (!strcmp(stream->filename, s->filename)) {
4180
                        ERROR("Stream '%s' already registered\n", s->filename);
4181
                    }
4182
                }
4183

    
4184
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4185
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4186
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4187
                audio_id = CODEC_ID_NONE;
4188
                video_id = CODEC_ID_NONE;
4189
                if (stream->fmt) {
4190
                    audio_id = stream->fmt->audio_codec;
4191
                    video_id = stream->fmt->video_codec;
4192
                }
4193

    
4194
                *last_stream = stream;
4195
                last_stream = &stream->next;
4196
            }
4197
        } else if (!strcasecmp(cmd, "Feed")) {
4198
            get_arg(arg, sizeof(arg), &p);
4199
            if (stream) {
4200
                FFStream *sfeed;
4201

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

    
4304
                get_arg(arg, sizeof(arg), &p);
4305

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

    
4513
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4514
                q = strrchr(redirect->filename, '>');
4515
                if (*q)
4516
                    *q = '\0';
4517
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4518
            }
4519
        } else if (!strcasecmp(cmd, "URL")) {
4520
            if (redirect)
4521
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4522
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4523
            if (!redirect) {
4524
                ERROR("No corresponding <Redirect> for </Redirect>\n");
4525
            } else {
4526
                if (!redirect->feed_filename[0]) {
4527
                    ERROR("No URL found for <Redirect>\n");
4528
                }
4529
                redirect = NULL;
4530
            }
4531
        } else if (!strcasecmp(cmd, "LoadModule")) {
4532
            get_arg(arg, sizeof(arg), &p);
4533
#if HAVE_DLOPEN
4534
            load_module(arg);
4535
#else
4536
            ERROR("Module support not compiled into this version: '%s'\n", arg);
4537
#endif
4538
        } else {
4539
            ERROR("Incorrect keyword: '%s'\n", cmd);
4540
        }
4541
    }
4542
#undef ERROR
4543

    
4544
    fclose(f);
4545
    if (errors)
4546
        return -1;
4547
    else
4548
        return 0;
4549
}
4550

    
4551
static void handle_child_exit(int sig)
4552
{
4553
    pid_t pid;
4554
    int status;
4555

    
4556
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4557
        FFStream *feed;
4558

    
4559
        for (feed = first_feed; feed; feed = feed->next) {
4560
            if (feed->pid == pid) {
4561
                int uptime = time(0) - feed->pid_start;
4562

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

    
4566
                if (uptime < 30)
4567
                    /* Turn off any more restarts */
4568
                    feed->child_argv = 0;
4569
            }
4570
        }
4571
    }
4572

    
4573
    need_to_start_children = 1;
4574
}
4575

    
4576
static void opt_debug(void)
4577
{
4578
    ffserver_debug = 1;
4579
    ffserver_daemon = 0;
4580
    logfilename[0] = '-';
4581
}
4582

    
4583
static void show_help(void)
4584
{
4585
    printf("usage: ffserver [options]\n"
4586
           "Hyper fast multi format Audio/Video streaming server\n");
4587
    printf("\n");
4588
    show_help_options(options, "Main options:\n", 0, 0);
4589
}
4590

    
4591
static const OptionDef options[] = {
4592
#include "cmdutils_common_opts.h"
4593
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4594
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4595
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4596
    { NULL },
4597
};
4598

    
4599
int main(int argc, char **argv)
4600
{
4601
    struct sigaction sigact;
4602

    
4603
    av_register_all();
4604

    
4605
    show_banner();
4606

    
4607
    my_program_name = argv[0];
4608
    my_program_dir = getcwd(0, 0);
4609
    ffserver_daemon = 1;
4610

    
4611
    parse_options(argc, argv, options, NULL);
4612

    
4613
    unsetenv("http_proxy");             /* Kill the http_proxy */
4614

    
4615
    av_lfg_init(&random_state, ff_random_get_seed());
4616

    
4617
    memset(&sigact, 0, sizeof(sigact));
4618
    sigact.sa_handler = handle_child_exit;
4619
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4620
    sigaction(SIGCHLD, &sigact, 0);
4621

    
4622
    if (parse_ffconfig(config_filename) < 0) {
4623
        fprintf(stderr, "Incorrect config file - exiting.\n");
4624
        exit(1);
4625
    }
4626

    
4627
    /* open log file if needed */
4628
    if (logfilename[0] != '\0') {
4629
        if (!strcmp(logfilename, "-"))
4630
            logfile = stdout;
4631
        else
4632
            logfile = fopen(logfilename, "a");
4633
        av_log_set_callback(http_av_log);
4634
    }
4635

    
4636
    build_file_streams();
4637

    
4638
    build_feed_streams();
4639

    
4640
    compute_bandwidth();
4641

    
4642
    /* put the process in background and detach it from its TTY */
4643
    if (ffserver_daemon) {
4644
        int pid;
4645

    
4646
        pid = fork();
4647
        if (pid < 0) {
4648
            perror("fork");
4649
            exit(1);
4650
        } else if (pid > 0) {
4651
            /* parent : exit */
4652
            exit(0);
4653
        } else {
4654
            /* child */
4655
            setsid();
4656
            close(0);
4657
            open("/dev/null", O_RDWR);
4658
            if (strcmp(logfilename, "-") != 0) {
4659
                close(1);
4660
                dup(0);
4661
            }
4662
            close(2);
4663
            dup(0);
4664
        }
4665
    }
4666

    
4667
    /* signal init */
4668
    signal(SIGPIPE, SIG_IGN);
4669

    
4670
    if (ffserver_daemon)
4671
        chdir("/");
4672

    
4673
    if (http_server() < 0) {
4674
        http_log("Could not start server\n");
4675
        exit(1);
4676
    }
4677

    
4678
    return 0;
4679
}