Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 1bf5228e

History | View | Annotate | Download (152 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

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

    
56
#include "cmdutils.h"
57

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

    
61
static const OptionDef options[];
62

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

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

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

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

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

    
94
#define IOBUFFER_INIT_SIZE 8192
95

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

    
100
#define SYNC_TIMEOUT (10 * 1000)
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
313
static AVLFG random_state;
314

    
315
static FILE *logfile = NULL;
316

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

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

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

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

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

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

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

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

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

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

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

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

    
434

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

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

    
444
            feed->pid = fork();
445

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

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

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

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

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

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

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

    
487
                signal(SIGPIPE, SIG_DFL);
488

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

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

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

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

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

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

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

    
526
    return server_fd;
527
}
528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
616
    start_children(first_feed);
617

    
618
    start_multicast();
619

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

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

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

    
692
        cur_time = av_gettime() / 1000;
693

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

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

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

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

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

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

    
754

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

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

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

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

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

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

    
792
    start_wait_request(c, is_rtsp);
793

    
794
    return;
795

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

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

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

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

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

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

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

    
857
    ctx = &c->fmt_ctx;
858

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1081
                q += 20;
1082

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

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

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

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

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

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

    
1107
        p++;
1108
    }
1109

    
1110
    return 0;
1111
}
1112

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

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

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

    
1128
        /* Potential stream */
1129

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

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

    
1147
    return best;
1148
}
1149

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

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

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

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

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

    
1185
    return action_required;
1186
}
1187

    
1188

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1327

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

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

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

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

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

    
1364

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

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

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

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

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

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

    
1399

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

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

    
1406
        ret = validate_acl_list(acl, c);
1407

    
1408
        free_acl_list(acl);
1409
    }
1410

    
1411
    return ret;
1412
}
1413

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1509
        p++;
1510
    }
1511

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

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

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

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

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

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

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

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

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

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

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

    
1620
            p++;
1621
        }
1622

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

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

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

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

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

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

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

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

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

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

    
1728
    stream->conns_served++;
1729

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

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

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

    
1751
                p++;
1752
            }
1753

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

    
1757
                logline += 17;
1758

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2031
                parameters[0] = 0;
2032

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2225

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

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

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

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

    
2261
        c->got_key_frame = 0;
2262

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2627
        if (len < 0) {
2628
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2629
                ff_neterrno() != FF_NETERROR(EINTR))
2630
                /* error : close connection */
2631
                goto fail;
2632
        } 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() != FF_NETERROR(EAGAIN) &&
2655
                ff_neterrno() != FF_NETERROR(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
            ByteIOContext *pb;
2716
            AVInputFormat *fmt_in;
2717
            int i;
2718

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

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

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

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

    
2741
            for (i = 0; i < s->nb_streams; i++) {
2742
                AVStream *fst = feed->streams[i];
2743
                AVStream *st = s->streams[i];
2744
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2745
                if (fst->codec->extradata_size) {
2746
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2747
                    if (!fst->codec->extradata)
2748
                        goto fail;
2749
                    memcpy(fst->codec->extradata, st->codec->extradata,
2750
                           fst->codec->extradata_size);
2751
                }
2752
            }
2753

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2958
    return strlen(*pbuffer);
2959
}
2960

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3177

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

    
3181

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

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

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

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

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

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

    
3231
    rtp_c->state = HTTPSTATE_SEND_DATA;
3232

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

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

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

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

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

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

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

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

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

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

    
3288

    
3289
/********************************************************************/
3290
/* RTP handling */
3291

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

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

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

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

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

    
3341
    current_bandwidth += stream->bandwidth;
3342

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3451
/********************************************************************/
3452
/* ffserver initialization */
3453

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3775
        close(fd);
3776
    }
3777
}
3778

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

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

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

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

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

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

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

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

    
3865

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

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

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

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

    
3886
    return p->id;
3887
}
3888

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

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

    
3896
    return p->id;
3897
}
3898

    
3899
/* simplistic plugin support */
3900

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

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

    
3921
    init_func();
3922
}
3923
#endif
3924

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

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

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

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

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

    
3951
    return fmt;
3952
}
3953

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

    
3962
    (*errors)++;
3963
}
3964

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4572
    need_to_start_children = 1;
4573
}
4574

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

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

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

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

    
4602
    av_register_all();
4603

    
4604
    show_banner();
4605

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

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

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

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

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

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

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

    
4635
    build_file_streams();
4636

    
4637
    build_feed_streams();
4638

    
4639
    compute_bandwidth();
4640

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

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

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

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

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

    
4677
    return 0;
4678
}