Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 2912e87a

History | View | Annotate | Download (155 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

    
24
#include "config.h"
25
#if !HAVE_CLOSESOCKET
26
#define closesocket close
27
#endif
28
#include <string.h>
29
#include <strings.h>
30
#include <stdlib.h>
31
#include "libavformat/avformat.h"
32
#include "libavformat/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
    avio_printf(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
    avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1884
    avio_printf(pb, "Content-type: %s\r\n", "text/html");
1885
    avio_printf(pb, "Pragma: no-cache\r\n");
1886
    avio_printf(pb, "\r\n");
1887

    
1888
    avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1889
    if (c->stream->feed_filename[0])
1890
        avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1891
    avio_printf(pb, "</head>\n<body>");
1892
    avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1893
    /* format status */
1894
    avio_printf(pb, "<h2>Available Streams</h2>\n");
1895
    avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1896
    avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
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
            avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1925
                         sfilename, stream->filename);
1926
            avio_printf(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
                    avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
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
                        avio_printf(pb, "<td>%s", stream->feed->filename);
1972
                    else
1973
                        avio_printf(pb, "<td>%s", stream->feed_filename);
1974
                    avio_printf(pb, "\n");
1975
                }
1976
                break;
1977
            default:
1978
                avio_printf(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
    avio_printf(pb, "</table>\n");
1985

    
1986
    stream = first_stream;
1987
    while (stream != NULL) {
1988
        if (stream->feed == stream) {
1989
            avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1990
            if (stream->pid) {
1991
                avio_printf(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
                            avio_printf(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
                avio_printf(pb, "<p>");
2019
            }
2020
            avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
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
                avio_printf(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
            avio_printf(pb, "</table>\n");
2047

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

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

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

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

    
2061
    avio_printf(pb, "<table>\n");
2062
    avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
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
        avio_printf(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
        avio_printf(pb, "<td align=right>");
2090
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2091
        avio_printf(pb, "<td align=right>");
2092
        fmt_bytecount(pb, c1->data_count);
2093
        avio_printf(pb, "\n");
2094
        c1 = c1->next;
2095
    }
2096
    avio_printf(pb, "</table>\n");
2097

    
2098
    /* date */
2099
    ti = time(NULL);
2100
    p = ctime(&ti);
2101
    avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2102
    avio_printf(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
            pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2725
                                    0, NULL, NULL, NULL, NULL);
2726
            pb->is_streamed = 1;
2727

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

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

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

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

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

    
2767
/********************************************************************/
2768
/* RTSP handling */
2769

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2968
    return strlen(*pbuffer);
2969
}
2970

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3189

    
3190
    avio_printf(c->pb, "\r\n");
3191
}
3192

    
3193

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

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

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

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

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

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

    
3247
    rtp_c->state = HTTPSTATE_SEND_DATA;
3248

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

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

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

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

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

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

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

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

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

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

    
3304

    
3305
/********************************************************************/
3306
/* RTP handling */
3307

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

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

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

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

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

    
3357
    current_bandwidth += stream->bandwidth;
3358

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3466
/********************************************************************/
3467
/* ffserver initialization */
3468

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3803
        close(fd);
3804
    }
3805
}
3806

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

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

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

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

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

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

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

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

    
3893

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

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

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

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

    
3914
    return p->id;
3915
}
3916

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

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

    
3924
    return p->id;
3925
}
3926

    
3927
/* simplistic plugin support */
3928

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

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

    
3949
    init_func();
3950
}
3951
#endif
3952

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

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

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

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

    
4001
    fclose(f);
4002

    
4003
    return ret;
4004
}
4005

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

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

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

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

    
4022
    return fmt;
4023
}
4024

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

    
4033
    (*errors)++;
4034
}
4035

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4660
    need_to_start_children = 1;
4661
}
4662

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

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

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

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

    
4690
    av_register_all();
4691

    
4692
    show_banner();
4693

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

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

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

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

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

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

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

    
4723
    build_