Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 9cc9a155

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_metadata_free(&ctx->metadata);
851
            av_free(ctx->streams[0]);
852
            av_free(ctx);
853
        }
854
        h = c->rtp_handles[i];
855
        if (h)
856
            url_close(h);
857
    }
858

    
859
    ctx = &c->fmt_ctx;
860

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1083
                q += 20;
1084

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

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

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

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

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

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

    
1109
        p++;
1110
    }
1111

    
1112
    return 0;
1113
}
1114

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

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

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

    
1130
        /* Potential stream */
1131

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

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

    
1149
    return best;
1150
}
1151

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

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

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

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

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

    
1187
    return action_required;
1188
}
1189

    
1190

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1329

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

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

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

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

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

    
1366

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

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

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

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

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

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

    
1401

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

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

    
1408
        ret = validate_acl_list(acl, c);
1409

    
1410
        free_acl_list(acl);
1411
    }
1412

    
1413
    return ret;
1414
}
1415

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1511
        p++;
1512
    }
1513

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

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

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

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

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

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

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

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

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

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

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

    
1622
            p++;
1623
        }
1624

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

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

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

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

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

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

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

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

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

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

    
1730
    stream->conns_served++;
1731

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

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

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

    
1753
                p++;
1754
            }
1755

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

    
1759
                logline += 17;
1760

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2033
                parameters[0] = 0;
2034

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2227

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

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

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

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

    
2263
        c->got_key_frame = 0;
2264

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

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

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

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

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

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

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

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

    
2417
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2418
                    c->cur_frame_bytes = len;
2419
                    c->buffer_ptr = c->pb_buffer;
2420
                    c->buffer_end = c->pb_buffer + len;
2421

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

    
2449
        c->last_packet_sent = 1;
2450
        break;
2451
    }
2452
    return 0;
2453
}
2454

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

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

    
2491
                c->data_count += len;
2492
                update_datarate(&c->datarate, c->data_count);
2493
                if (c->stream)
2494
                    c->stream->bytes_served += len;
2495

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

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

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

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

    
2577
static int http_start_receive_data(HTTPContext *c)
2578
{
2579
    int fd;
2580

    
2581
    if (c->stream->feed_opened)
2582
        return -1;
2583

    
2584
    /* Don't permit writing to this one */
2585
    if (c->stream->readonly)
2586
        return -1;
2587

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

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

    
2608
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2609
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2610
    lseek(fd, 0, SEEK_SET);
2611

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

    
2620
static int http_receive_data(HTTPContext *c)
2621
{
2622
    HTTPContext *c1;
2623
    int len, loop_run = 0;
2624

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

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

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

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

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

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

    
2695
            feed->feed_write_index += FFM_PACKET_SIZE;
2696
            /* update file size */
2697
            if (feed->feed_write_index > c->stream->feed_size)
2698
                feed->feed_size = feed->feed_write_index;
2699

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

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

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

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

    
2728
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2729
            pb->is_streamed = 1;
2730

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

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

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

    
2758
            av_close_input_stream(s);
2759
            av_free(pb);
2760
        }
2761
        c->buffer_ptr = c->buffer;
2762
    }
2763

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

    
2777
/********************************************************************/
2778
/* RTSP handling */
2779

    
2780
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2781
{
2782
    const char *str;
2783
    time_t ti;
2784
    struct tm *tm;
2785
    char buf2[32];
2786

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

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

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

    
2836
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2837
{
2838
    rtsp_reply_header(c, error_number);
2839
    url_fprintf(c->pb, "\r\n");
2840
}
2841

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

    
2852
    c->buffer_ptr[0] = '\0';
2853
    p = c->buffer;
2854

    
2855
    get_word(cmd, sizeof(cmd), &p);
2856
    get_word(url, sizeof(url), &p);
2857
    get_word(protocol, sizeof(protocol), &p);
2858

    
2859
    av_strlcpy(c->method, cmd, sizeof(c->method));
2860
    av_strlcpy(c->url, url, sizeof(c->url));
2861
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2862

    
2863
    if (url_open_dyn_buf(&c->pb) < 0) {
2864
        /* XXX: cannot do more */
2865
        c->pb = NULL; /* safety */
2866
        return -1;
2867
    }
2868

    
2869
    /* check version name */
2870
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2871
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2872
        goto the_end;
2873
    }
2874

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

    
2901
    /* handle sequence number */
2902
    c->seq = header->seq;
2903

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

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

    
2932
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2933
                                   struct in_addr my_ip)
2934
{
2935
    AVFormatContext *avc;
2936
    AVStream avs[MAX_STREAMS];
2937
    int i;
2938

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

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

    
2963
    return strlen(*pbuffer);
2964
}
2965

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

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

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

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

    
3001
 found:
3002
    /* prepare the media description in sdp format */
3003

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

    
3020
static HTTPContext *find_rtp_session(const char *session_id)
3021
{
3022
    HTTPContext *c;
3023

    
3024
    if (session_id[0] == '\0')
3025
        return NULL;
3026

    
3027
    for(c = first_http_ctx; c != NULL; c = c->next) {
3028
        if (!strcmp(c->session_id, session_id))
3029
            return c;
3030
    }
3031
    return NULL;
3032
}
3033

    
3034
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3035
{
3036
    RTSPTransportField *th;
3037
    int i;
3038

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

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

    
3060
    /* find which url is asked */
3061
    ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3062
    path = path1;
3063
    if (*path == '/')
3064
        path++;
3065

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3183

    
3184
    url_fprintf(c->pb, "\r\n");
3185
}
3186

    
3187

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

    
3199
    rtp_c = find_rtp_session(session_id);
3200
    if (!rtp_c)
3201
        return NULL;
3202

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

    
3220
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3221
{
3222
    HTTPContext *rtp_c;
3223

    
3224
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3225
    if (!rtp_c) {
3226
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3227
        return;
3228
    }
3229

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

    
3237
    rtp_c->state = HTTPSTATE_SEND_DATA;
3238

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

    
3246
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3247
{
3248
    HTTPContext *rtp_c;
3249

    
3250
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3251
    if (!rtp_c) {
3252
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3253
        return;
3254
    }
3255

    
3256
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3257
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3258
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3259
        return;
3260
    }
3261

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

    
3271
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3272
{
3273
    HTTPContext *rtp_c;
3274
    char session_id[32];
3275

    
3276
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3277
    if (!rtp_c) {
3278
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3279
        return;
3280
    }
3281

    
3282
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3283

    
3284
    /* abort the session */
3285
    close_connection(rtp_c);
3286

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

    
3294

    
3295
/********************************************************************/
3296
/* RTP handling */
3297

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

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

    
3310
    /* add a new connection */
3311
    c = av_mallocz(sizeof(HTTPContext));
3312
    if (!c)
3313
        goto fail;
3314

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

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

    
3347
    current_bandwidth += stream->bandwidth;
3348

    
3349
    c->next = first_http_ctx;
3350
    first_http_ctx = c;
3351
    return c;
3352

    
3353
 fail:
3354
    if (c) {
3355
        av_free(c->buffer);
3356
        av_free(c);
3357
    }
3358
    return NULL;
3359
}
3360

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

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

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

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

    
3396
    /* build destination RTP address */
3397
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3398

    
3399
    switch(c->rtp_protocol) {
3400
    case RTSP_LOWER_TRANSPORT_UDP:
3401
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3402
        /* RTP/UDP case */
3403

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

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

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

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

    
3452
    c->rtp_ctx[stream_index] = ctx;
3453
    return 0;
3454
}
3455

    
3456
/********************************************************************/
3457
/* ffserver initialization */
3458

    
3459
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3460
{
3461
    AVStream *fst;
3462

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

    
3475
/* return the stream number in the feed */
3476
static int add_av_stream(FFStream *feed, AVStream *st)
3477
{
3478
    AVStream *fst;
3479
    AVCodecContext *av, *av1;
3480
    int i;
3481

    
3482
    av = st->codec;
3483
    for(i=0;i<feed->nb_streams;i++) {
3484
        st = feed->streams[i];
3485
        av1 = st->codec;
3486
        if (av1->codec_id == av->codec_id &&
3487
            av1->codec_type == av->codec_type &&
3488
            av1->bit_rate == av->bit_rate) {
3489

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

    
3510
    fst = add_av_stream1(feed, av);
3511
    if (!fst)
3512
        return -1;
3513
    return feed->nb_streams - 1;
3514
 found:
3515
    return i;
3516
}
3517

    
3518
static void remove_stream(FFStream *stream)
3519
{
3520
    FFStream **ps;
3521
    ps = &first_stream;
3522
    while (*ps != NULL) {
3523
        if (*ps == stream)
3524
            *ps = (*ps)->next;
3525
        else
3526
            ps = &(*ps)->next;
3527
    }
3528
}
3529

    
3530
/* specific mpeg4 handling : we extract the raw parameters */
3531
static void extract_mpeg4_header(AVFormatContext *infile)
3532
{
3533
    int mpeg4_count, i, size;
3534
    AVPacket pkt;
3535
    AVStream *st;
3536
    const uint8_t *p;
3537

    
3538
    mpeg4_count = 0;
3539
    for(i=0;i<infile->nb_streams;i++) {
3540
        st = infile->streams[i];
3541
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3542
            st->codec->extradata_size == 0) {
3543
            mpeg4_count++;
3544
        }
3545
    }
3546
    if (!mpeg4_count)
3547
        return;
3548

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

    
3579
/* compute the needed AVStream for each file */
3580
static void build_file_streams(void)
3581
{
3582
    FFStream *stream, *stream_next;
3583
    AVFormatContext *infile;
3584
    int i, ret;
3585

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

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

    
3620
                for(i=0;i<infile->nb_streams;i++)
3621
                    add_av_stream1(stream, infile->streams[i]->codec);
3622

    
3623
                av_close_input_file(infile);
3624
            }
3625
        }
3626
    }
3627
}
3628

    
3629
/* compute the needed AVStream for each feed */
3630
static void build_feed_streams(void)
3631
{
3632
    FFStream *stream, *feed;
3633
    int i;
3634

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

    
3647
    /* gather all streams */
3648
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3649
        feed = stream->feed;
3650
        if (feed) {
3651
            if (stream->is_feed) {
3652
                for(i=0;i<stream->nb_streams;i++)
3653
                    stream->feed_streams[i] = i;
3654
            }
3655
        }
3656
    }
3657

    
3658
    /* create feed files if needed */
3659
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3660
        int fd;
3661

    
3662
        if (url_exist(feed->feed_filename)) {
3663
            /* See if it matches */
3664
            AVFormatContext *s;
3665
            int matches = 0;
3666

    
3667
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3668
                /* Now see if it matches */
3669
                if (s->nb_streams == feed->nb_streams) {
3670
                    matches = 1;
3671
                    for(i=0;i<s->nb_streams;i++) {
3672
                        AVStream *sf, *ss;
3673
                        sf = feed->streams[i];
3674
                        ss = s->streams[i];
3675

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

    
3684
                            ccf = sf->codec;
3685
                            ccs = ss->codec;
3686
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3687

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

    
3721
                av_close_input_file(s);
3722
            } else
3723
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3724
                        feed->feed_filename);
3725

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

    
3738
            if (feed->readonly) {
3739
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3740
                    feed->feed_filename);
3741
                exit(1);
3742
            }
3743

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

    
3774
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3775
        feed->feed_size = lseek(fd, 0, SEEK_END);
3776
        /* ensure that we do not wrap before the end of file */
3777
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3778
            feed->feed_max_size = feed->feed_size;
3779

    
3780
        close(fd);
3781
    }
3782
}
3783

    
3784
/* compute the bandwidth used by each stream */
3785
static void compute_bandwidth(void)
3786
{
3787
    unsigned bandwidth;
3788
    int i;
3789
    FFStream *stream;
3790

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

    
3808
/* add a codec and set the default parameters */
3809
static void add_codec(FFStream *stream, AVCodecContext *av)
3810
{
3811
    AVStream *st;
3812

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

    
3847
        if (!av->nsse_weight)
3848
            av->nsse_weight = 8;
3849

    
3850
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3851
        if (!av->me_method)
3852
            av->me_method = ME_EPZS;
3853
        av->rc_buffer_aggressivity = 1.0;
3854

    
3855
        if (!av->rc_eq)
3856
            av->rc_eq = "tex^qComp";
3857
        if (!av->i_quant_factor)
3858
            av->i_quant_factor = -0.8;
3859
        if (!av->b_quant_factor)
3860
            av->b_quant_factor = 1.25;
3861
        if (!av->b_quant_offset)
3862
            av->b_quant_offset = 1.25;
3863
        if (!av->rc_max_rate)
3864
            av->rc_max_rate = av->bit_rate * 2;
3865

    
3866
        if (av->rc_max_rate && !av->rc_buffer_size) {
3867
            av->rc_buffer_size = av->rc_max_rate;
3868
        }
3869

    
3870

    
3871
        break;
3872
    default:
3873
        abort();
3874
    }
3875

    
3876
    st = av_mallocz(sizeof(AVStream));
3877
    if (!st)
3878
        return;
3879
    st->codec = avcodec_alloc_context();
3880
    stream->streams[stream->nb_streams++] = st;
3881
    memcpy(st->codec, av, sizeof(AVCodecContext));
3882
}
3883

    
3884
static enum CodecID opt_audio_codec(const char *arg)
3885
{
3886
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3887

    
3888
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3889
        return CODEC_ID_NONE;
3890

    
3891
    return p->id;
3892
}
3893

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

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

    
3901
    return p->id;
3902
}
3903

    
3904
/* simplistic plugin support */
3905

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

    
3918
    init_func = dlsym(dll, "ffserver_module_init");
3919
    if (!init_func) {
3920
        fprintf(stderr,
3921
                "%s: init function 'ffserver_module_init()' not found\n",
3922
                filename);
3923
        dlclose(dll);
3924
    }
3925

    
3926
    init_func();
3927
}
3928
#endif
3929

    
3930
static int ffserver_opt_default(const char *opt, const char *arg,
3931
                       AVCodecContext *avctx, int type)
3932
{
3933
    int ret = 0;
3934
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3935
    if(o)
3936
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3937
    return ret;
3938
}
3939

    
3940
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3941
                                             const char *mime_type)
3942
{
3943
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3944

    
3945
    if (fmt) {
3946
        AVOutputFormat *stream_fmt;
3947
        char stream_format_name[64];
3948

    
3949
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3950
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3951

    
3952
        if (stream_fmt)
3953
            fmt = stream_fmt;
3954
    }
3955

    
3956
    return fmt;
3957
}
3958

    
3959
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3960
{
3961
    va_list vl;
3962
    va_start(vl, fmt);
3963
    fprintf(stderr, "%s:%d: ", filename, line_num);
3964
    vfprintf(stderr, fmt, vl);
3965
    va_end(vl);
3966

    
3967
    (*errors)++;
3968
}
3969

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

    
3983
    f = fopen(filename, "r");
3984
    if (!f) {
3985
        perror(filename);
3986
        return -1;
3987
    }
3988

    
3989
    errors = 0;
3990
    line_num = 0;
3991
    first_stream = NULL;
3992
    last_stream = &first_stream;
3993
    first_feed = NULL;
3994
    last_feed = &first_feed;
3995
    stream = NULL;
3996
    feed = NULL;
3997
    redirect = NULL;
3998
    audio_id = CODEC_ID_NONE;
3999
    video_id = CODEC_ID_NONE;
4000

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

    
4012
        get_arg(cmd, sizeof(cmd), &p);
4013

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

    
4079
                for (s = first_feed; s; s = s->next) {
4080
                    if (!strcmp(feed->filename, s->filename)) {
4081
                        ERROR("Feed '%s' already registered\n", s->filename);
4082
                    }
4083
                }
4084

    
4085
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4086
                /* defaut feed file */
4087
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4088
                         "/tmp/%s.ffm", feed->filename);
4089
                feed->feed_max_size = 5 * 1024 * 1024;
4090
                feed->is_feed = 1;
4091
                feed->feed = feed; /* self feeding :-) */
4092

    
4093
                /* add in stream list */
4094
                *last_stream = feed;
4095
                last_stream = &feed->next;
4096
                /* add in feed list */
4097
                *last_feed = feed;
4098
                last_feed = &feed->next_feed;
4099
            }
4100
        } else if (!strcasecmp(cmd, "Launch")) {
4101
            if (feed) {
4102
                int i;
4103

    
4104
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4105

    
4106
                for (i = 0; i < 62; i++) {
4107
                    get_arg(arg, sizeof(arg), &p);
4108
                    if (!arg[0])
4109
                        break;
4110

    
4111
                    feed->child_argv[i] = av_strdup(arg);
4112
                }
4113

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

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

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

    
4182
                for (s = first_stream; s; s = s->next) {
4183
                    if (!strcmp(stream->filename, s->filename)) {
4184
                        ERROR("Stream '%s' already registered\n", s->filename);
4185
                    }
4186
                }
4187

    
4188
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4189
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4190
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4191
                audio_id = CODEC_ID_NONE;
4192
                video_id = CODEC_ID_NONE;
4193
                if (stream->fmt) {
4194
                    audio_id = stream->fmt->audio_codec;
4195
                    video_id = stream->fmt->video_codec;
4196
                }
4197

    
4198
                *last_stream = stream;
4199
                last_stream = &stream->next;
4200
            }
4201
        } else if (!strcasecmp(cmd, "Feed")) {
4202
            get_arg(arg, sizeof(arg), &p);
4203
            if (stream) {
4204
                FFStream *sfeed;
4205

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

    
4308
                get_arg(arg, sizeof(arg), &p);
4309

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

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

    
4548
    fclose(f);
4549
    if (errors)
4550
        return -1;
4551
    else
4552
        return 0;
4553
}
4554

    
4555
static void handle_child_exit(int sig)
4556
{
4557
    pid_t pid;
4558
    int status;
4559

    
4560
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4561
        FFStream *feed;
4562

    
4563
        for (feed = first_feed; feed; feed = feed->next) {
4564
            if (feed->pid == pid) {
4565
                int uptime = time(0) - feed->pid_start;
4566

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

    
4570
                if (uptime < 30)
4571
                    /* Turn off any more restarts */
4572
                    feed->child_argv = 0;
4573
            }
4574
        }
4575
    }
4576

    
4577
    need_to_start_children = 1;
4578
}
4579

    
4580
static void opt_debug(void)
4581
{
4582
    ffserver_debug = 1;
4583
    ffserver_daemon = 0;
4584
    logfilename[0] = '-';
4585
}
4586

    
4587
static void show_help(void)
4588
{
4589
    printf("usage: ffserver [options]\n"
4590
           "Hyper fast multi format Audio/Video streaming server\n");
4591
    printf("\n");
4592
    show_help_options(options, "Main options:\n", 0, 0);
4593
}
4594

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

    
4603
int main(int argc, char **argv)
4604
{
4605
    struct sigaction sigact;
4606

    
4607
    av_register_all();
4608

    
4609
    show_banner();
4610

    
4611
    my_program_name = argv[0];
4612
    my_program_dir = getcwd(0, 0);
4613
    ffserver_daemon = 1;
4614

    
4615
    parse_options(argc, argv, options, NULL);
4616

    
4617
    unsetenv("http_proxy");             /* Kill the http_proxy */
4618

    
4619
    av_lfg_init(&random_state, av_get_random_seed());
4620

    
4621
    memset(&sigact, 0, sizeof(sigact));
4622
    sigact.sa_handler = handle_child_exit;
4623
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4624
    sigaction(SIGCHLD, &sigact, 0);
4625

    
4626
    if (parse_ffconfig(config_filename) < 0) {
4627
        fprintf(stderr, "Incorrect config file - exiting.\n");
4628
        exit(1);
4629
    }
4630

    
4631
    /* open log file if needed */
4632
    if (logfilename[0] != '\0') {
4633
        if (!strcmp(logfilename, "-"))
4634
            logfile = stdout;
4635
        else
4636
            logfile = fopen(logfilename, "a");
4637
        av_log_set_callback(http_av_log);
4638
    }
4639

    
4640
    build_file_streams();
4641

    
4642
    build_feed_streams();
4643

    
4644
    compute_bandwidth();
4645

    
4646
    /* put the process in background and detach it from its TTY */
4647
    if (ffserver_daemon) {
4648
        int pid;
4649

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

    
4671
    /* signal init */
4672
    signal(SIGPIPE, SIG_IGN);
4673

    
4674
    if (ffserver_daemon)
4675
        chdir("/");
4676

    
4677
    if (http_server() < 0) {
4678
        http_log("Could not start server\n");
4679
        exit(1);
4680
    }
4681

    
4682
    return 0;
4683
}