Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ f3bfe388

History | View | Annotate | Download (155 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

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

    
56
#include "cmdutils.h"
57

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

    
61
static const OptionDef options[];
62

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

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

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

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

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

    
94
#define IOBUFFER_INIT_SIZE 8192
95

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

    
100
#define SYNC_TIMEOUT (10 * 1000)
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
313
static AVLFG random_state;
314

    
315
static FILE *logfile = NULL;
316

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

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

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

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

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

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

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

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

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

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

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

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

    
434

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

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

    
444
            feed->pid = fork();
445

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

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

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

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

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

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

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

    
487
                signal(SIGPIPE, SIG_DFL);
488

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

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

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

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

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

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

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

    
526
    return server_fd;
527
}
528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
616
    start_children(first_feed);
617

    
618
    start_multicast();
619

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

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

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

    
692
        cur_time = av_gettime() / 1000;
693

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

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

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

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

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

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

    
754

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

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

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

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

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

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

    
792
    start_wait_request(c, is_rtsp);
793

    
794
    return;
795

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

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

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

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

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

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

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

    
859
    ctx = &c->fmt_ctx;
860

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1083
                q += 20;
1084

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

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

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

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

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

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

    
1109
        p++;
1110
    }
1111

    
1112
    return 0;
1113
}
1114

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

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

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

    
1130
        /* Potential stream */
1131

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

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

    
1149
    return best;
1150
}
1151

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

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

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

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

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

    
1187
    return action_required;
1188
}
1189

    
1190

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1329

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

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

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

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

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

    
1366

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

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

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

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

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

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

    
1401

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

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

    
1408
        ret = validate_acl_list(acl, c);
1409

    
1410
        free_acl_list(acl);
1411
    }
1412

    
1413
    return ret;
1414
}
1415

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1511
        p++;
1512
    }
1513

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

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

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

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

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

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

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

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

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

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

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

    
1622
            p++;
1623
        }
1624

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

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

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

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

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

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

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

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

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

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

    
1730
    stream->conns_served++;
1731

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

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

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

    
1753
                p++;
1754
            }
1755

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

    
1759
                logline += 17;
1760

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

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

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

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

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

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

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

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

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

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

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

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

    
1827
        q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1828
    }
1829
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1830
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1831

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2033
                parameters[0] = 0;
2034

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2227

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

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

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

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

    
2263
        c->got_key_frame = 0;
2264

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2773
/********************************************************************/
2774
/* RTSP handling */
2775

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2928
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2929
                                   struct in_addr my_ip)
2930
{
2931
    AVFormatContext *avc;
2932
    AVStream avs[MAX_STREAMS];
2933
    int i;
2934

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

    
2950
    for(i = 0; i < stream->nb_streams; i++) {
2951
        avc->streams[i] = &avs[i];
2952
        avc->streams[i]->codec = stream->streams[i]->codec;
2953
    }
2954
    *pbuffer = av_mallocz(2048);
2955
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2956
    av_metadata_free(&avc->metadata);
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
    av_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-Base: %s/\r\n", url);
3010
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
3011
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
3012
    url_fprintf(c->pb, "\r\n");
3013
    put_buffer(c->pb, content, content_length);
3014
    av_free(content);
3015
}
3016

    
3017
static HTTPContext *find_rtp_session(const char *session_id)
3018
{
3019
    HTTPContext *c;
3020

    
3021
    if (session_id[0] == '\0')
3022
        return NULL;
3023

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3180

    
3181
    url_fprintf(c->pb, "\r\n");
3182
}
3183

    
3184

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

    
3196
    rtp_c = find_rtp_session(session_id);
3197
    if (!rtp_c)
3198
        return NULL;
3199

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

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

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

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

    
3234
    rtp_c->state = HTTPSTATE_SEND_DATA;
3235

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

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

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

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

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

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

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

    
3279
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3280

    
3281
    /* abort the session */
3282
    close_connection(rtp_c);
3283

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

    
3291

    
3292
/********************************************************************/
3293
/* RTP handling */
3294

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

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

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

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

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

    
3344
    current_bandwidth += stream->bandwidth;
3345

    
3346
    c->next = first_http_ctx;
3347
    first_http_ctx = c;
3348
    return c;
3349

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

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

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

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

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

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

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

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

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

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

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

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

    
3453
/********************************************************************/
3454
/* ffserver initialization */
3455

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

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

    
3484
/* return the stream number in the feed */
3485
static int add_av_stream(FFStream *feed, AVStream *st)
3486
{
3487
    AVStream *fst;
3488
    AVCodecContext *av, *av1;
3489
    int i;
3490

    
3491
    av = st->codec;
3492
    for(i=0;i<feed->nb_streams;i++) {
3493
        st = feed->streams[i];
3494
        av1 = st->codec;
3495
        if (av1->codec_id == av->codec_id &&
3496
            av1->codec_type == av->codec_type &&
3497
            av1->bit_rate == av->bit_rate) {
3498

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

    
3519
    fst = add_av_stream1(feed, av, 0);
3520
    if (!fst)
3521
        return -1;
3522
    return feed->nb_streams - 1;
3523
 found:
3524
    return i;
3525
}
3526

    
3527
static void remove_stream(FFStream *stream)
3528
{
3529
    FFStream **ps;
3530
    ps = &first_stream;
3531
    while (*ps != NULL) {
3532
        if (*ps == stream)
3533
            *ps = (*ps)->next;
3534
        else
3535
            ps = &(*ps)->next;
3536
    }
3537
}
3538

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

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

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

    
3588
/* compute the needed AVStream for each file */
3589
static void build_file_streams(void)
3590
{
3591
    FFStream *stream, *stream_next;
3592
    AVFormatContext *infile;
3593
    int i, ret;
3594

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

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

    
3629
                for(i=0;i<infile->nb_streams;i++)
3630
                    add_av_stream1(stream, infile->streams[i]->codec, 1);
3631

    
3632
                av_close_input_file(infile);
3633
            }
3634
        }
3635
    }
3636
}
3637

    
3638
/* compute the needed AVStream for each feed */
3639
static void build_feed_streams(void)
3640
{
3641
    FFStream *stream, *feed;
3642
    int i;
3643

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

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

    
3667
    /* create feed files if needed */
3668
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3669
        int fd;
3670

    
3671
        if (url_exist(feed->feed_filename)) {
3672
            /* See if it matches */
3673
            AVFormatContext *s;
3674
            int matches = 0;
3675

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

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

    
3693
                            ccf = sf->codec;
3694
                            ccs = ss->codec;
3695
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3696

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

    
3730
                av_close_input_file(s);
3731
            } else
3732
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3733
                        feed->feed_filename);
3734

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

    
3747
            if (feed->readonly) {
3748
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3749
                    feed->feed_filename);
3750
                exit(1);
3751
            }
3752

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

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

    
3789
        close(fd);
3790
    }
3791
}
3792

    
3793
/* compute the bandwidth used by each stream */
3794
static void compute_bandwidth(void)
3795
{
3796
    unsigned bandwidth;
3797
    int i;
3798
    FFStream *stream;
3799

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

    
3817
/* add a codec and set the default parameters */
3818
static void add_codec(FFStream *stream, AVCodecContext *av)
3819
{
3820
    AVStream *st;
3821

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

    
3856
        if (!av->nsse_weight)
3857
            av->nsse_weight = 8;
3858

    
3859
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3860
        if (!av->me_method)
3861
            av->me_method = ME_EPZS;
3862
        av->rc_buffer_aggressivity = 1.0;
3863

    
3864
        if (!av->rc_eq)
3865
            av->rc_eq = "tex^qComp";
3866
        if (!av->i_quant_factor)
3867
            av->i_quant_factor = -0.8;
3868
        if (!av->b_quant_factor)
3869
            av->b_quant_factor = 1.25;
3870
        if (!av->b_quant_offset)
3871
            av->b_quant_offset = 1.25;
3872
        if (!av->rc_max_rate)
3873
            av->rc_max_rate = av->bit_rate * 2;
3874

    
3875
        if (av->rc_max_rate && !av->rc_buffer_size) {
3876
            av->rc_buffer_size = av->rc_max_rate;
3877
        }
3878

    
3879

    
3880
        break;
3881
    default:
3882
        abort();
3883
    }
3884

    
3885
    st = av_mallocz(sizeof(AVStream));
3886
    if (!st)
3887
        return;
3888
    st->codec = avcodec_alloc_context();
3889
    stream->streams[stream->nb_streams++] = st;
3890
    memcpy(st->codec, av, sizeof(AVCodecContext));
3891
}
3892

    
3893
static enum CodecID opt_audio_codec(const char *arg)
3894
{
3895
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3896

    
3897
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3898
        return CODEC_ID_NONE;
3899

    
3900
    return p->id;
3901
}
3902

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

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

    
3910
    return p->id;
3911
}
3912

    
3913
/* simplistic plugin support */
3914

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

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

    
3935
    init_func();
3936
}
3937
#endif
3938

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

    
3949
static int ffserver_opt_preset(const char *arg,
3950
                       AVCodecContext *avctx, int type,
3951
                       enum CodecID *audio_id, enum CodecID *video_id)
3952
{
3953
    FILE *f=NULL;
3954
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3955
    int i, ret = 0;
3956
    const char *base[3]= { getenv("FFMPEG_DATADIR"),
3957
                           getenv("HOME"),
3958
                           FFMPEG_DATADIR,
3959
                         };
3960

    
3961
    for(i=0; i<3 && !f; i++){
3962
        if(!base[i])
3963
            continue;
3964
        snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", arg);
3965
        f= fopen(filename, "r");
3966
        if(!f){
3967
            AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3968
            if (codec) {
3969
                snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i],  i != 1 ? "" : "/.ffmpeg", codec->name, arg);
3970
                f= fopen(filename, "r");
3971
            }
3972
        }
3973
    }
3974

    
3975
    if(!f){
3976
        fprintf(stderr, "File for preset '%s' not found\n", arg);
3977
        return 1;
3978
    }
3979

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

    
4003
    fclose(f);
4004

    
4005
    return ret;
4006
}
4007

    
4008
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4009
                                             const char *mime_type)
4010
{
4011
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4012

    
4013
    if (fmt) {
4014
        AVOutputFormat *stream_fmt;
4015
        char stream_format_name[64];
4016

    
4017
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4018
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4019

    
4020
        if (stream_fmt)
4021
            fmt = stream_fmt;
4022
    }
4023

    
4024
    return fmt;
4025
}
4026

    
4027
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4028
{
4029
    va_list vl;
4030
    va_start(vl, fmt);
4031
    fprintf(stderr, "%s:%d: ", filename, line_num);
4032
    vfprintf(stderr, fmt, vl);
4033
    va_end(vl);
4034

    
4035
    (*errors)++;
4036
}
4037

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

    
4051
    f = fopen(filename, "r");
4052
    if (!f) {
4053
        perror(filename);
4054
        return -1;
4055
    }
4056

    
4057
    errors = 0;
4058
    line_num = 0;
4059
    first_stream = NULL;
4060
    last_stream = &first_stream;
4061
    first_feed = NULL;
4062
    last_feed = &first_feed;
4063
    stream = NULL;
4064
    feed = NULL;
4065
    redirect = NULL;
4066
    audio_id = CODEC_ID_NONE;
4067
    video_id = CODEC_ID_NONE;
4068

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

    
4080
        get_arg(cmd, sizeof(cmd), &p);
4081

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

    
4147
                for (s = first_feed; s; s = s->next) {
4148
                    if (!strcmp(feed->filename, s->filename)) {
4149
                        ERROR("Feed '%s' already registered\n", s->filename);
4150
                    }
4151
                }
4152

    
4153
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4154
                /* defaut feed file */
4155
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4156
                         "/tmp/%s.ffm", feed->filename);
4157
                feed->feed_max_size = 5 * 1024 * 1024;
4158
                feed->is_feed = 1;
4159
                feed->feed = feed; /* self feeding :-) */
4160

    
4161
                /* add in stream list */
4162
                *last_stream = feed;
4163
                last_stream = &feed->next;
4164
                /* add in feed list */
4165
                *last_feed = feed;
4166
                last_feed = &feed->next_feed;
4167
            }
4168
        } else if (!strcasecmp(cmd, "Launch")) {
4169
            if (feed) {
4170
                int i;
4171

    
4172
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4173

    
4174
                for (i = 0; i < 62; i++) {
4175
                    get_arg(arg, sizeof(arg), &p);
4176
                    if (!arg[0])
4177
                        break;
4178

    
4179
                    feed->child_argv[i] = av_strdup(arg);
4180
                }
4181

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

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

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

    
4250
                for (s = first_stream; s; s = s->next) {
4251
                    if (!strcmp(stream->filename, s->filename)) {
4252
                        ERROR("Stream '%s' already registered\n", s->filename);
4253
                    }
4254
                }
4255

    
4256
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4257
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4258
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4259
                audio_id = CODEC_ID_NONE;
4260
                video_id = CODEC_ID_NONE;
4261
                if (stream->fmt) {
4262
                    audio_id = stream->fmt->audio_codec;
4263
                    video_id = stream->fmt->video_codec;
4264
                }
4265

    
4266
                *last_stream = stream;
4267
                last_stream = &stream->next;
4268
            }
4269
        } else if (!strcasecmp(cmd, "Feed")) {
4270
            get_arg(arg, sizeof(arg), &p);
4271
            if (stream) {
4272
                FFStream *sfeed;
4273

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

    
4376
                get_arg(arg, sizeof(arg), &p);
4377

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

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

    
4633
    fclose(f);
4634
    if (errors)
4635
        return -1;
4636
    else
4637
        return 0;
4638
}
4639

    
4640
static void handle_child_exit(int sig)
4641
{
4642
    pid_t pid;
4643
    int status;
4644

    
4645
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4646
        FFStream *feed;
4647

    
4648
        for (feed = first_feed; feed; feed = feed->next) {
4649
            if (feed->pid == pid) {
4650
                int uptime = time(0) - feed->pid_start;
4651

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

    
4655
                if (uptime < 30)
4656
                    /* Turn off any more restarts */
4657
                    feed->child_argv = 0;
4658
            }
4659
        }
4660
    }
4661

    
4662
    need_to_start_children = 1;
4663
}
4664

    
4665
static void opt_debug(void)
4666
{
4667
    ffserver_debug = 1;
4668
    ffserver_daemon = 0;
4669
    logfilename[0] = '-';
4670
}
4671

    
4672
static void show_help(void)
4673
{
4674
    printf("usage: ffserver [options]\n"
4675
           "Hyper fast multi format Audio/Video streaming server\n");
4676
    printf("\n");
4677
    show_help_options(options, "Main options:\n", 0, 0);
4678
}
4679

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

    
4688
int main(int argc, char **argv)
4689
{
4690
    struct sigaction sigact;
4691

    
4692
    av_register_all();
4693

    
4694
    show_banner();
4695

    
4696
    my_program_name = argv[0];
4697
    my_program_dir = getcwd(0, 0);
4698
    ffserver_daemon = 1;
4699

    
4700
    parse_options(argc, argv, options, NULL);
4701

    
4702
    unsetenv("http_proxy");             /* Kill the http_proxy */
4703

    
4704
    av_lfg_init(&random_state, av_get_random_seed());
4705

    
4706
    memset(&sigact, 0, sizeof(sigact));
4707
    sigact.sa_handler = handle_child_exit;
4708
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4709
    sigaction(SIGCHLD, &sigact, 0);
4710

    
4711
    if (parse_ffconfig(config_filename) < 0) {
4712
        fprintf(stderr, "Incorrect config file - exiting.\n");
4713
        exit(1);
4714
    }
4715

    
4716
    /* open log file if needed */
4717
    if (logfilename[0] != '\0') {
4718
        if (!strcmp(logfilename, "-"))
4719
            logfile = stdout;
4720