Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ c24a4034

History | View | Annotate | Download (155 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

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

    
57
#include "cmdutils.h"
58

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

    
62
static const OptionDef options[];
63

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

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

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

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

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

    
95
#if !FF_API_MAX_STREAMS
96
#define MAX_STREAMS 20
97
#endif
98

    
99
#define IOBUFFER_INIT_SIZE 8192
100

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

    
105
#define SYNC_TIMEOUT (10 * 1000)
106

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
318
static AVLFG random_state;
319

    
320
static FILE *logfile = NULL;
321

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

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

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

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

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

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

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

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

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

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

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

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

    
442

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

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

    
452
            feed->pid = fork();
453

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

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

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

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

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

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

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

    
495
                signal(SIGPIPE, SIG_DFL);
496

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

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

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

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

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

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

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

    
534
    return server_fd;
535
}
536

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
624
    start_children(first_feed);
625

    
626
    start_multicast();
627

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

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

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

    
700
        cur_time = av_gettime() / 1000;
701

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

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

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

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

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

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

    
762

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

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

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

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

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

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

    
800
    start_wait_request(c, is_rtsp);
801

    
802
    return;
803

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

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

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

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

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

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

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

    
867
    ctx = &c->fmt_ctx;
868

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1091
                q += 20;
1092

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

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

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

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

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

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

    
1117
        p++;
1118
    }
1119

    
1120
    return 0;
1121
}
1122

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

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

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

    
1138
        /* Potential stream */
1139

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

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

    
1157
    return best;
1158
}
1159

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

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

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

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

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

    
1195
    return action_required;
1196
}
1197

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1324

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

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

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

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

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

    
1361

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

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

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

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

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

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

    
1396

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

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

    
1403
        ret = validate_acl_list(acl, c);
1404

    
1405
        free_acl_list(acl);
1406
    }
1407

    
1408
    return ret;
1409
}
1410

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1506
        p++;
1507
    }
1508

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

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

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

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

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

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

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

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

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

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

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

    
1617
            p++;
1618
        }
1619

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

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

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

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

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

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

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

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

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

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

    
1725
    stream->conns_served++;
1726

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

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

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

    
1748
                p++;
1749
            }
1750

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

    
1754
                logline += 17;
1755

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1864
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1865
}
1866

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2028
                parameters[0] = 0;
2029

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2220

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

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

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

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

    
2256
        c->got_key_frame = 0;
2257

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2766
/********************************************************************/
2767
/* RTSP handling */
2768

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2943
#if !FF_API_MAX_STREAMS
2944
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2945
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2946
        goto sdp_done;
2947
#endif
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
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2958

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

    
2967
    return strlen(*pbuffer);
2968
}
2969

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3188

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

    
3192

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

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

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

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

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

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

    
3246
    rtp_c->state = HTTPSTATE_SEND_DATA;
3247

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

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

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

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

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

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

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

    
3291
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3292

    
3293
    /* abort the session */
3294
    close_connection(rtp_c);
3295

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

    
3303

    
3304
/********************************************************************/
3305
/* RTP handling */
3306

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

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

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

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

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

    
3356
    current_bandwidth += stream->bandwidth;
3357

    
3358
    c->next = first_http_ctx;
3359
    first_http_ctx = c;
3360
    return c;
3361

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

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

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

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

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

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

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

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

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

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

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

    
3461
    c->rtp_ctx[stream_index] = ctx;
3462
    return 0;
3463
}
3464

    
3465
/********************************************************************/
3466
/* ffserver initialization */
3467

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3645
                av_close_input_file(infile);
3646
            }
3647
        }
3648
    }
3649
}
3650

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3802
        close(fd);
3803
    }
3804
}
3805

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

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

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

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

    
3869
        if (!av->nsse_weight)
3870
            av->nsse_weight = 8;
3871

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

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

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

    
3892

    
3893
        break;
3894
    default:
3895
        abort();
3896
    }
3897

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

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

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

    
3913
    return p->id;
3914
}
3915

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

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

    
3923
    return p->id;
3924
}
3925

    
3926
/* simplistic plugin support */
3927

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

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

    
3948
    init_func();
3949
}
3950
#endif
3951

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

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

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

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

    
4000
    fclose(f);
4001

    
4002
    return ret;
4003
}
4004

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

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

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

    
4017
        if (stream_fmt)
4018
            fmt = stream_fmt;
4019
    }
4020

    
4021
    return fmt;
4022
}
4023

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

    
4032
    (*errors)++;
4033
}
4034

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

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

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

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

    
4077
        get_arg(cmd, sizeof(cmd), &p);
4078

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

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

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

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

    
4169
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4170

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

    
4176
                    feed->child_argv[i] = av_strdup(arg);
4177
                }
4178

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

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

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

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

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

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

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

    
4373
                get_arg(arg, sizeof(arg), &p);
4374

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

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

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

    
4637
static void handle_child_exit(int sig)
4638
{
4639
    pid_t pid;
4640
    int status;
4641

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

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

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

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

    
4659
    need_to_start_children = 1;
4660
}
4661

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

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

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

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

    
4689
    av_register_all();
4690

    
4691
    show_banner();
4692

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

    
4697
    parse_options(argc, argv, options, NULL);
4698

    
4699
    unsetenv("http_proxy");             /* Kill the http_proxy */
4700

    
4701
    av_lfg_init(&random_state, av_get_random_seed());
4702

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

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

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

    
4722
    build_file_streams();
4723

    
4724
    build_feed_streams();