Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 41d0eb1c

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 Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; 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/ffm.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35
#include "libavformat/rtpdec.h"
36
#include "libavformat/rtsp.h"
37
// XXX for ffio_open_dyn_packet_buffer, to be removed
38
#include "libavformat/avio_internal.h"
39
#include "libavutil/avstring.h"
40
#include "libavutil/lfg.h"
41
#include "libavutil/random_seed.h"
42
#include "libavutil/parseutils.h"
43
#include "libavutil/opt.h"
44
#include <stdarg.h>
45
#include <unistd.h>
46
#include <fcntl.h>
47
#include <sys/ioctl.h>
48
#if HAVE_POLL_H
49
#include <poll.h>
50
#endif
51
#include <errno.h>
52
#include <sys/time.h>
53
#include <time.h>
54
#include <sys/wait.h>
55
#include <signal.h>
56
#if HAVE_DLFCN_H
57
#include <dlfcn.h>
58
#endif
59

    
60
#include "cmdutils.h"
61

    
62
const char program_name[] = "FFserver";
63
const int program_birth_year = 2000;
64

    
65
static const OptionDef options[];
66

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

    
77
    RTSPSTATE_WAIT_REQUEST,
78
    RTSPSTATE_SEND_REPLY,
79
    RTSPSTATE_SEND_PACKET,
80
};
81

    
82
static const char *http_state[] = {
83
    "HTTP_WAIT_REQUEST",
84
    "HTTP_SEND_HEADER",
85

    
86
    "SEND_DATA_HEADER",
87
    "SEND_DATA",
88
    "SEND_DATA_TRAILER",
89
    "RECEIVE_DATA",
90
    "WAIT_FEED",
91
    "READY",
92

    
93
    "RTSP_WAIT_REQUEST",
94
    "RTSP_SEND_REPLY",
95
    "RTSP_SEND_PACKET",
96
};
97

    
98
#define MAX_STREAMS 20
99

    
100
#define IOBUFFER_INIT_SIZE 8192
101

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

    
106
#define SYNC_TIMEOUT (10 * 1000)
107

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
319
static AVLFG random_state;
320

    
321
static FILE *logfile = NULL;
322

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

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

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

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

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

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

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

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

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

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

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

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

    
443

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

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

    
453
            feed->pid = fork();
454

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

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

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

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

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

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

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

    
496
                signal(SIGPIPE, SIG_DFL);
497

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

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

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

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

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

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

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

    
535
    return server_fd;
536
}
537

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
625
    start_children(first_feed);
626

    
627
    start_multicast();
628

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

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

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

    
701
        cur_time = av_gettime() / 1000;
702

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

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

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

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

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

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

    
763

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

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

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

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

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

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

    
801
    start_wait_request(c, is_rtsp);
802

    
803
    return;
804

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

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

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

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

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

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

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

    
868
    ctx = &c->fmt_ctx;
869

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1092
                q += 20;
1093

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

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

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

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

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

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

    
1118
        p++;
1119
    }
1120

    
1121
    return 0;
1122
}
1123

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

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

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

    
1139
        /* Potential stream */
1140

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

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

    
1158
    return best;
1159
}
1160

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

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

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

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

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

    
1196
    return action_required;
1197
}
1198

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1325

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

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

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

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

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

    
1362

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

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

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

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

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

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

    
1397

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

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

    
1404
        ret = validate_acl_list(acl, c);
1405

    
1406
        free_acl_list(acl);
1407
    }
1408

    
1409
    return ret;
1410
}
1411

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1507
        p++;
1508
    }
1509

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

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

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

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

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

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

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

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

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

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

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

    
1618
            p++;
1619
        }
1620

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

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

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

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

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

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

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

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

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

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

    
1726
    stream->conns_served++;
1727

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

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

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

    
1749
                p++;
1750
            }
1751

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

    
1755
                logline += 17;
1756

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1865
    avio_printf(pb, "%"PRId64"%c", count, *s);
1866
}
1867

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

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

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

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

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

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

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

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

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

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

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

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

    
2019
                avio_printf(pb, "<p>");
2020
            }
2021
            avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
2022

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

    
2029
                parameters[0] = 0;
2030

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2221

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

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

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

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

    
2257
        c->got_key_frame = 0;
2258

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2725
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2726
                                    0, NULL, NULL, NULL, NULL);
2727
            pb->seekable = 0;
2728

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2945
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2946
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2947
        goto sdp_done;
2948
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2949
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2950
        goto sdp_done;
2951

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

    
2959
 sdp_done:
2960
    av_free(avc->streams);
2961
    av_metadata_free(&avc->metadata);
2962
    av_free(avc);
2963
    av_free(avs);
2964

    
2965
    return strlen(*pbuffer);
2966
}
2967

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3186

    
3187
    avio_printf(c->pb, "\r\n");
3188
}
3189

    
3190

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

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

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

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

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

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

    
3244
    rtp_c->state = HTTPSTATE_SEND_DATA;
3245

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

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

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

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

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

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

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

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

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

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

    
3301

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

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

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

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

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

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

    
3354
    current_bandwidth += stream->bandwidth;
3355

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3800
        close(fd);
3801
    }
3802
}
3803

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

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

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

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

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

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

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

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

    
3890

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

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

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

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

    
3911
    return p->id;
3912
}
3913

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

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

    
3921
    return p->id;
3922
}
3923

    
3924
/* simplistic plugin support */
3925

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

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

    
3946
    init_func();
3947
}
3948
#endif
3949

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

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

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

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

    
3998
    fclose(f);
3999

    
4000
    return ret;
4001
}
4002

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

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

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

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

    
4019
    return fmt;
4020
}
4021

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

    
4030
    (*errors)++;
4031
}
4032

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4657
    need_to_start_children = 1;
4658
}
4659

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

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

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

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

    
4687
    av_register_all();
4688

    
4689
    show_banner();
4690

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

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

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

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

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

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

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

    
4720
    build_file_streams();
4721

    
4722
    build_feed_streams();
4723