Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 77223c53

History | View | Annotate | Download (155 KB)

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

    
22
#define _XOPEN_SOURCE 600
23

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

    
57
#include "cmdutils.h"
58

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

    
62
static const OptionDef options[];
63

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

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

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

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

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

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

    
99
#define IOBUFFER_INIT_SIZE 8192
100

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

    
105
#define SYNC_TIMEOUT (10 * 1000)
106

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
318
static AVLFG random_state;
319

    
320
static FILE *logfile = NULL;
321

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

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

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

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

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

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

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

    
407
static void log_connection(HTTPContext *c)
408
{
409
    if (c->suppress_log)
410
        return;
411

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

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

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

    
436
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
437
}
438

    
439

    
440
static void start_children(FFStream *feed)
441
{
442
    if (no_launch)
443
        return;
444

    
445
    for (; feed; feed = feed->next) {
446
        if (feed->child_argv && !feed->pid) {
447
            feed->pid_start = time(0);
448

    
449
            feed->pid = fork();
450

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

    
461
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
462

    
463
                slash = strrchr(pathname, '/');
464
                if (!slash)
465
                    slash = pathname;
466
                else
467
                    slash++;
468
                strcpy(slash, "ffmpeg");
469

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

    
476
                for (i = 3; i < 256; i++)
477
                    close(i);
478

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

    
489
                /* This is needed to make relative pathnames work */
490
                chdir(my_program_dir);
491

    
492
                signal(SIGPIPE, SIG_DFL);
493

    
494
                execvp(pathname, feed->child_argv);
495

    
496
                _exit(1);
497
            }
498
        }
499
    }
500
}
501

    
502
/* open a listening socket */
503
static int socket_open_listen(struct sockaddr_in *my_addr)
504
{
505
    int server_fd, tmp;
506

    
507
    server_fd = socket(AF_INET,SOCK_STREAM,0);
508
    if (server_fd < 0) {
509
        perror ("socket");
510
        return -1;
511
    }
512

    
513
    tmp = 1;
514
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
515

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

    
524
    if (listen (server_fd, 5) < 0) {
525
        perror ("listen");
526
        closesocket(server_fd);
527
        return -1;
528
    }
529
    ff_socket_nonblock(server_fd, 1);
530

    
531
    return server_fd;
532
}
533

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

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

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

    
556
            dest_addr.sin_family = AF_INET;
557
            dest_addr.sin_addr = stream->multicast_ip;
558
            dest_addr.sin_port = htons(stream->multicast_port);
559

    
560
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
561
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
562
            if (!rtp_c)
563
                continue;
564

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

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

    
583
            /* change state to send data */
584
            rtp_c->state = HTTPSTATE_SEND_DATA;
585
        }
586
    }
587
}
588

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

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

    
602
    if (my_http_addr.sin_port) {
603
        server_fd = socket_open_listen(&my_http_addr);
604
        if (server_fd < 0)
605
            return -1;
606
    }
607

    
608
    if (my_rtsp_addr.sin_port) {
609
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
610
        if (rtsp_server_fd < 0)
611
            return -1;
612
    }
613

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

    
619
    http_log("FFserver started.\n");
620

    
621
    start_children(first_feed);
622

    
623
    start_multicast();
624

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

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

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

    
697
        cur_time = av_gettime() / 1000;
698

    
699
        if (need_to_start_children) {
700
            need_to_start_children = 0;
701
            start_children(first_feed);
702
        }
703

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

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

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

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

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

    
759

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

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

    
775
    if (nb_connections >= nb_max_connections) {
776
        http_send_too_busy_reply(fd);
777
        goto fail;
778
    }
779

    
780
    /* add a new connection */
781
    c = av_mallocz(sizeof(HTTPContext));
782
    if (!c)
783
        goto fail;
784

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

    
793
    c->next = first_http_ctx;
794
    first_http_ctx = c;
795
    nb_connections++;
796

    
797
    start_wait_request(c, is_rtsp);
798

    
799
    return;
800

    
801
 fail:
802
    if (c) {
803
        av_free(c->buffer);
804
        av_free(c);
805
    }
806
    closesocket(fd);
807
}
808

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

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

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

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

    
846
    /* free RTP output streams if any */
847
    nb_streams = 0;
848
    if (c->stream)
849
        nb_streams = c->stream->nb_streams;
850

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

    
864
    ctx = &c->fmt_ctx;
865

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

    
877
    for(i=0; i<ctx->nb_streams; i++)
878
        av_free(ctx->streams[i]);
879

    
880
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
881
        current_bandwidth -= c->stream->bandwidth;
882

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

    
889
    av_freep(&c->pb_buffer);
890
    av_freep(&c->packet_buffer);
891
    av_free(c->buffer);
892
    av_free(c);
893
    nb_connections--;
894
}
895

    
896
static int handle_connection(HTTPContext *c)
897
{
898
    int len, ret;
899

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

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

    
943
    case HTTPSTATE_SEND_HEADER:
944
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
945
            return -1;
946

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

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

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

    
1009
        /* nothing to do, we'll be waken up by incoming feed packets */
1010
        break;
1011

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

    
1073
static int extract_rates(char *rates, int ratelen, const char *request)
1074
{
1075
    const char *p;
1076

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

    
1081
            while (*q && *q != '\n' && isspace(*q))
1082
                q++;
1083

    
1084
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1085
                int stream_no;
1086
                int rate_no;
1087

    
1088
                q += 20;
1089

    
1090
                memset(rates, 0xff, ratelen);
1091

    
1092
                while (1) {
1093
                    while (*q && *q != '\n' && *q != ':')
1094
                        q++;
1095

    
1096
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1097
                        break;
1098

    
1099
                    stream_no--;
1100
                    if (stream_no < ratelen && stream_no >= 0)
1101
                        rates[stream_no] = rate_no;
1102

    
1103
                    while (*q && *q != '\n' && !isspace(*q))
1104
                        q++;
1105
                }
1106

    
1107
                return 1;
1108
            }
1109
        }
1110
        p = strchr(p, '\n');
1111
        if (!p)
1112
            break;
1113

    
1114
        p++;
1115
    }
1116

    
1117
    return 0;
1118
}
1119

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

    
1126
    for (i = 0; i < feed->nb_streams; i++) {
1127
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1128

    
1129
        if (feed_codec->codec_id != codec->codec_id ||
1130
            feed_codec->sample_rate != codec->sample_rate ||
1131
            feed_codec->width != codec->width ||
1132
            feed_codec->height != codec->height)
1133
            continue;
1134

    
1135
        /* Potential stream */
1136

    
1137
        /* We want the fastest stream less than bit_rate, or the slowest
1138
         * faster than bit_rate
1139
         */
1140

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

    
1154
    return best;
1155
}
1156

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

    
1163
    /* Not much we can do for a feed */
1164
    if (!req->feed)
1165
        return 0;
1166

    
1167
    for (i = 0; i < req->nb_streams; i++) {
1168
        AVCodecContext *codec = req->streams[i]->codec;
1169

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

    
1188
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1189
            action_required = 1;
1190
    }
1191

    
1192
    return action_required;
1193
}
1194

    
1195

    
1196
static void do_switch_stream(HTTPContext *c, int i)
1197
{
1198
    if (c->switch_feed_streams[i] >= 0) {
1199
#ifdef PHILIP
1200
        c->feed_streams[i] = c->switch_feed_streams[i];
1201
#endif
1202

    
1203
        /* Now update the stream */
1204
    }
1205
    c->switch_feed_streams[i] = -1;
1206
}
1207

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

    
1219
static void get_word(char *buf, int buf_size, const char **pp)
1220
{
1221
    const char *p;
1222
    char *q;
1223

    
1224
    p = *pp;
1225
    skip_spaces(&p);
1226
    q = buf;
1227
    while (!isspace(*p) && *p != '\0') {
1228
        if ((q - buf) < buf_size - 1)
1229
            *q++ = *p;
1230
        p++;
1231
    }
1232
    if (buf_size > 0)
1233
        *q = '\0';
1234
    *pp = p;
1235
}
1236

    
1237
static void get_arg(char *buf, int buf_size, const char **pp)
1238
{
1239
    const char *p;
1240
    char *q;
1241
    int quote;
1242

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

    
1269
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1270
                         const char *p, const char *filename, int line_num)
1271
{
1272
    char arg[1024];
1273
    IPAddressACL acl;
1274
    int errors = 0;
1275

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

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

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

    
1296
    get_arg(arg, sizeof(arg), &p);
1297

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

    
1306
    if (!errors) {
1307
        IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1308
        IPAddressACL **naclp = 0;
1309

    
1310
        acl.next = 0;
1311
        *nacl = acl;
1312

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

    
1325
        if (naclp) {
1326
            while (*naclp)
1327
                naclp = &(*naclp)->next;
1328

    
1329
            *naclp = nacl;
1330
        }
1331
    }
1332
}
1333

    
1334

    
1335
static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1336
{
1337
    FILE* f;
1338
    char line[1024];
1339
    char  cmd[1024];
1340
    IPAddressACL *acl = NULL;
1341
    int line_num = 0;
1342
    const char *p;
1343

    
1344
    f = fopen(stream->dynamic_acl, "r");
1345
    if (!f) {
1346
        perror(stream->dynamic_acl);
1347
        return NULL;
1348
    }
1349

    
1350
    acl = av_mallocz(sizeof(IPAddressACL));
1351

    
1352
    /* Build ACL */
1353
    for(;;) {
1354
        if (fgets(line, sizeof(line), f) == NULL)
1355
            break;
1356
        line_num++;
1357
        p = line;
1358
        while (isspace(*p))
1359
            p++;
1360
        if (*p == '\0' || *p == '#')
1361
            continue;
1362
        get_arg(cmd, sizeof(cmd), &p);
1363

    
1364
        if (!strcasecmp(cmd, "ACL"))
1365
            parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1366
    }
1367
    fclose(f);
1368
    return acl;
1369
}
1370

    
1371

    
1372
static void free_acl_list(IPAddressACL *in_acl)
1373
{
1374
    IPAddressACL *pacl,*pacl2;
1375

    
1376
    pacl = in_acl;
1377
    while(pacl) {
1378
        pacl2 = pacl;
1379
        pacl = pacl->next;
1380
        av_freep(pacl2);
1381
    }
1382
}
1383

    
1384
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1385
{
1386
    enum IPAddressAction last_action = IP_DENY;
1387
    IPAddressACL *acl;
1388
    struct in_addr *src = &c->from_addr.sin_addr;
1389
    unsigned long src_addr = src->s_addr;
1390

    
1391
    for (acl = in_acl; acl; acl = acl->next) {
1392
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1393
            return (acl->action == IP_ALLOW) ? 1 : 0;
1394
        last_action = acl->action;
1395
    }
1396

    
1397
    /* Nothing matched, so return not the last action */
1398
    return (last_action == IP_DENY) ? 1 : 0;
1399
}
1400

    
1401
static int validate_acl(FFStream *stream, HTTPContext *c)
1402
{
1403
    int ret = 0;
1404
    IPAddressACL *acl;
1405

    
1406

    
1407
    /* if stream->acl is null validate_acl_list will return 1 */
1408
    ret = validate_acl_list(stream->acl, c);
1409

    
1410
    if (stream->dynamic_acl[0]) {
1411
        acl = parse_dynamic_acl(stream, c);
1412

    
1413
        ret = validate_acl_list(acl, c);
1414

    
1415
        free_acl_list(acl);
1416
    }
1417

    
1418
    return ret;
1419
}
1420

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

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

    
1447
enum RedirType {
1448
    REDIR_NONE,
1449
    REDIR_ASX,
1450
    REDIR_RAM,
1451
    REDIR_ASF,
1452
    REDIR_RTSP,
1453
    REDIR_SDP,
1454
};
1455

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

    
1472
    p = c->buffer;
1473
    get_word(cmd, sizeof(cmd), (const char **)&p);
1474
    av_strlcpy(c->method, cmd, sizeof(c->method));
1475

    
1476
    if (!strcmp(cmd, "GET"))
1477
        c->post = 0;
1478
    else if (!strcmp(cmd, "POST"))
1479
        c->post = 1;
1480
    else
1481
        return -1;
1482

    
1483
    get_word(url, sizeof(url), (const char **)&p);
1484
    av_strlcpy(c->url, url, sizeof(c->url));
1485

    
1486
    get_word(protocol, sizeof(protocol), (const char **)&p);
1487
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1488
        return -1;
1489

    
1490
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1491

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

    
1495
    /* find the filename and the optional info string in the request */
1496
    p = strchr(url, '?');
1497
    if (p) {
1498
        av_strlcpy(info, p, sizeof(info));
1499
        *p = '\0';
1500
    } else
1501
        info[0] = '\0';
1502

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

    
1505
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1506
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1507
            useragent = p + 11;
1508
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1509
                useragent++;
1510
            break;
1511
        }
1512
        p = strchr(p, '\n');
1513
        if (!p)
1514
            break;
1515

    
1516
        p++;
1517
    }
1518

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

    
1538
    // "redirect" / request to index.html
1539
    if (!strlen(filename))
1540
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1541

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

    
1554
    c->stream = stream;
1555
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1556
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1557

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

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

    
1586
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1587
        current_bandwidth += stream->bandwidth;
1588

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

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

    
1615
    if (redir_type != REDIR_NONE) {
1616
        char *hostinfo = 0;
1617

    
1618
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1619
            if (strncasecmp(p, "Host:", 5) == 0) {
1620
                hostinfo = p + 5;
1621
                break;
1622
            }
1623
            p = strchr(p, '\n');
1624
            if (!p)
1625
                break;
1626

    
1627
            p++;
1628
        }
1629

    
1630
        if (hostinfo) {
1631
            char *eoh;
1632
            char hostbuf[260];
1633

    
1634
            while (isspace(*hostinfo))
1635
                hostinfo++;
1636

    
1637
            eoh = strchr(hostinfo, '\n');
1638
            if (eoh) {
1639
                if (eoh[-1] == '\r')
1640
                    eoh--;
1641

    
1642
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1643
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1644
                    hostbuf[eoh - hostinfo] = 0;
1645

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

    
1697
                            q += snprintf(q, c->buffer_size,
1698
                                          "HTTP/1.0 200 OK\r\n"
1699
                                          "Content-type: application/sdp\r\n"
1700
                                          "\r\n");
1701

    
1702
                            len = sizeof(my_addr);
1703
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1704

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

    
1722
                    /* prepare output buffer */
1723
                    c->buffer_ptr = c->buffer;
1724
                    c->buffer_end = q;
1725
                    c->state = HTTPSTATE_SEND_HEADER;
1726
                    return 0;
1727
                }
1728
            }
1729
        }
1730

    
1731
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1732
        goto send_error;
1733
    }
1734

    
1735
    stream->conns_served++;
1736

    
1737
    /* XXX: add there authenticate and IP match */
1738

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

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

    
1758
                p++;
1759
            }
1760

    
1761
            if (logline) {
1762
                char *eol = strchr(logline, '\n');
1763

    
1764
                logline += 17;
1765

    
1766
                if (eol) {
1767
                    if (eol[-1] == '\r')
1768
                        eol--;
1769
                    http_log("%.*s\n", (int) (eol - logline), logline);
1770
                    c->suppress_log = 1;
1771
                }
1772
            }
1773

    
1774
#ifdef DEBUG_WMP
1775
            http_log("\nGot request:\n%s\n", c->buffer);
1776
#endif
1777

    
1778
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1779
                HTTPContext *wmpc;
1780

    
1781
                /* Now we have to find the client_id */
1782
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1783
                    if (wmpc->wmp_client_id == client_id)
1784
                        break;
1785
                }
1786

    
1787
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1788
                    wmpc->switch_pending = 1;
1789
            }
1790

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

    
1804
#ifdef DEBUG_WMP
1805
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1806
        http_log("\nGot request:\n%s\n", c->buffer);
1807
#endif
1808

    
1809
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1810
        goto send_status;
1811

    
1812
    /* open input stream */
1813
    if (open_input_stream(c, info) < 0) {
1814
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1815
        goto send_error;
1816
    }
1817

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

    
1826
    /* for asf, we need extra headers */
1827
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1828
        /* Need to allocate a client id */
1829

    
1830
        c->wmp_client_id = av_lfg_get(&random_state);
1831

    
1832
        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);
1833
    }
1834
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1835
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1836

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

    
1867
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1868
{
1869
    static const char *suffix = " kMGTP";
1870
    const char *s;
1871

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

    
1874
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1875
}
1876

    
1877
static void compute_status(HTTPContext *c)
1878
{
1879
    HTTPContext *c1;
1880
    FFStream *stream;
1881
    char *p;
1882
    time_t ti;
1883
    int i, len;
1884
    ByteIOContext *pb;
1885

    
1886
    if (url_open_dyn_buf(&pb) < 0) {
1887
        /* XXX: return an error ? */
1888
        c->buffer_ptr = c->buffer;
1889
        c->buffer_end = c->buffer;
1890
        return;
1891
    }
1892

    
1893
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1894
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1895
    url_fprintf(pb, "Pragma: no-cache\r\n");
1896
    url_fprintf(pb, "\r\n");
1897

    
1898
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1899
    if (c->stream->feed_filename[0])
1900
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1901
    url_fprintf(pb, "</head>\n<body>");
1902
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1903
    /* format status */
1904
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1905
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1906
    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");
1907
    stream = first_stream;
1908
    while (stream != NULL) {
1909
        char sfilename[1024];
1910
        char *eosf;
1911

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

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

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

    
1996
    stream = first_stream;
1997
    while (stream != NULL) {
1998
        if (stream->feed == stream) {
1999
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
2000
            if (stream->pid) {
2001
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
2002

    
2003
#if defined(linux) && !defined(CONFIG_NOCUTILS)
2004
                {
2005
                    FILE *pid_stat;
2006
                    char ps_cmd[64];
2007

    
2008
                    /* This is somewhat linux specific I guess */
2009
                    snprintf(ps_cmd, sizeof(ps_cmd),
2010
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
2011
                             stream->pid);
2012

    
2013
                    pid_stat = popen(ps_cmd, "r");
2014
                    if (pid_stat) {
2015
                        char cpuperc[10];
2016
                        char cpuused[64];
2017

    
2018
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
2019
                                   cpuused) == 2) {
2020
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2021
                                         cpuperc, cpuused);
2022
                        }
2023
                        fclose(pid_stat);
2024
                    }
2025
                }
2026
#endif
2027

    
2028
                url_fprintf(pb, "<p>");
2029
            }
2030
            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");
2031

    
2032
            for (i = 0; i < stream->nb_streams; i++) {
2033
                AVStream *st = stream->streams[i];
2034
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2035
                const char *type = "unknown";
2036
                char parameters[64];
2037

    
2038
                parameters[0] = 0;
2039

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

    
2058
        }
2059
        stream = stream->next;
2060
    }
2061

    
2062
    /* connection status */
2063
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
2064

    
2065
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
2066
                 nb_connections, nb_max_connections);
2067

    
2068
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2069
                 current_bandwidth, max_bandwidth);
2070

    
2071
    url_fprintf(pb, "<table>\n");
2072
    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");
2073
    c1 = first_http_ctx;
2074
    i = 0;
2075
    while (c1 != NULL) {
2076
        int bitrate;
2077
        int j;
2078

    
2079
        bitrate = 0;
2080
        if (c1->stream) {
2081
            for (j = 0; j < c1->stream->nb_streams; j++) {
2082
                if (!c1->stream->feed)
2083
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
2084
                else if (c1->feed_streams[j] >= 0)
2085
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2086
            }
2087
        }
2088

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

    
2108
    /* date */
2109
    ti = time(NULL);
2110
    p = ctime(&ti);
2111
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
2112
    url_fprintf(pb, "</body>\n</html>\n");
2113

    
2114
    len = url_close_dyn_buf(pb, &c->pb_buffer);
2115
    c->buffer_ptr = c->pb_buffer;
2116
    c->buffer_end = c->pb_buffer + len;
2117
}
2118

    
2119
/* check if the parser needs to be opened for stream i */
2120
static void open_parser(AVFormatContext *s, int i)
2121
{
2122
    AVStream *st = s->streams[i];
2123
    AVCodec *codec;
2124

    
2125
    if (!st->codec->codec) {
2126
        codec = avcodec_find_decoder(st->codec->codec_id);
2127
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2128
            st->codec->parse_only = 1;
2129
            if (avcodec_open(st->codec, codec) < 0)
2130
                st->codec->parse_only = 0;
2131
        }
2132
    }
2133
}
2134

    
2135
static int open_input_stream(HTTPContext *c, const char *info)
2136
{
2137
    char buf[128];
2138
    char input_filename[1024];
2139
    AVFormatContext *s;
2140
    int buf_size, i, ret;
2141
    int64_t stream_pos;
2142

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

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

    
2185
    /* open each parser */
2186
    for(i=0;i<s->nb_streams;i++)
2187
        open_parser(s, i);
2188

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

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

    
2209
/* return the server clock (in us) */
2210
static int64_t get_server_clock(HTTPContext *c)
2211
{
2212
    /* compute current pts value from system time */
2213
    return (cur_time - c->start_time) * 1000;
2214
}
2215

    
2216
/* return the estimated time at which the current packet must be sent
2217
   (in us) */
2218
static int64_t get_packet_send_clock(HTTPContext *c)
2219
{
2220
    int bytes_left, bytes_sent, frame_bytes;
2221

    
2222
    frame_bytes = c->cur_frame_bytes;
2223
    if (frame_bytes <= 0)
2224
        return c->cur_pts;
2225
    else {
2226
        bytes_left = c->buffer_end - c->buffer_ptr;
2227
        bytes_sent = frame_bytes - bytes_left;
2228
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2229
    }
2230
}
2231

    
2232

    
2233
static int http_prepare_data(HTTPContext *c)
2234
{
2235
    int i, len, ret;
2236
    AVFormatContext *ctx;
2237

    
2238
    av_freep(&c->pb_buffer);
2239
    switch(c->state) {
2240
    case HTTPSTATE_SEND_DATA_HEADER:
2241
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2242
        av_metadata_set2(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0);
2243
        av_metadata_set2(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0);
2244
        av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2245
        av_metadata_set2(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0);
2246

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

    
2259
            *st = *src;
2260
            st->priv_data = 0;
2261
            st->codec->frame_number = 0; /* XXX: should be done in
2262
                                           AVStream, not in codec */
2263
        }
2264
        /* set output format parameters */
2265
        c->fmt_ctx.oformat = c->stream->fmt;
2266
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2267

    
2268
        c->got_key_frame = 0;
2269

    
2270
        /* prepare header and save header data in a stream */
2271
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2272
            /* XXX: potential leak */
2273
            return -1;
2274
        }
2275
        c->fmt_ctx.pb->is_streamed = 1;
2276

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

    
2285
        av_set_parameters(&c->fmt_ctx, NULL);
2286
        if (av_write_header(&c->fmt_ctx) < 0) {
2287
            http_log("Error writing output header\n");
2288
            return -1;
2289
        }
2290
        av_metadata_free(&c->fmt_ctx.metadata);
2291

    
2292
        len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2293
        c->buffer_ptr = c->pb_buffer;
2294
        c->buffer_end = c->pb_buffer + len;
2295

    
2296
        c->state = HTTPSTATE_SEND_DATA;
2297
        c->last_packet_sent = 0;
2298
        break;
2299
    case HTTPSTATE_SEND_DATA:
2300
        /* find a new packet */
2301
        /* read a packet from the input stream */
2302
        if (c->stream->feed)
2303
            ffm_set_write_index(c->fmt_in,
2304
                                c->stream->feed->feed_write_index,
2305
                                c->stream->feed->feed_size);
2306

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

    
2398
                    if (c->is_packetized) {
2399
                        int max_packet_size;
2400
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2401
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2402
                        else
2403
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2404
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2405
                    } else {
2406
                        ret = url_open_dyn_buf(&ctx->pb);
2407
                    }
2408
                    if (ret < 0) {
2409
                        /* XXX: potential leak */
2410
                        return -1;
2411
                    }
2412
                    ost = ctx->streams[pkt.stream_index];
2413

    
2414
                    ctx->pb->is_streamed = 1;
2415
                    if (pkt.dts != AV_NOPTS_VALUE)
2416
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2417
                    if (pkt.pts != AV_NOPTS_VALUE)
2418
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2419
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2420
                    if (av_write_frame(ctx, &pkt) < 0) {
2421
                        http_log("Error writing frame to output\n");
2422
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2423
                    }
2424

    
2425
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2426
                    c->cur_frame_bytes = len;
2427
                    c->buffer_ptr = c->pb_buffer;
2428
                    c->buffer_end = c->pb_buffer + len;
2429

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

    
2457
        c->last_packet_sent = 1;
2458
        break;
2459
    }
2460
    return 0;
2461
}
2462

    
2463
/* should convert the format at the same time */
2464
/* send data starting at c->buffer_ptr to the output connection
2465
   (either UDP or TCP connection) */
2466
static int http_send_data(HTTPContext *c)
2467
{
2468
    int len, ret;
2469

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

    
2499
                c->data_count += len;
2500
                update_datarate(&c->datarate, c->data_count);
2501
                if (c->stream)
2502
                    c->stream->bytes_served += len;
2503

    
2504
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2505
                    /* RTP packets are sent inside the RTSP TCP connection */
2506
                    ByteIOContext *pb;
2507
                    int interleaved_index, size;
2508
                    uint8_t header[4];
2509
                    HTTPContext *rtsp_c;
2510

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

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

    
2574
                c->data_count += len;
2575
                update_datarate(&c->datarate, c->data_count);
2576
                if (c->stream)
2577
                    c->stream->bytes_served += len;
2578
                break;
2579
            }
2580
        }
2581
    } /* for(;;) */
2582
    return 0;
2583
}
2584

    
2585
static int http_start_receive_data(HTTPContext *c)
2586
{
2587
    int fd;
2588

    
2589
    if (c->stream->feed_opened)
2590
        return -1;
2591

    
2592
    /* Don't permit writing to this one */
2593
    if (c->stream->readonly)
2594
        return -1;
2595

    
2596
    /* open feed */
2597
    fd = open(c->stream->feed_filename, O_RDWR);
2598
    if (fd < 0) {
2599
        http_log("Error opening feeder file: %s\n", strerror(errno));
2600
        return -1;
2601
    }
2602
    c->feed_fd = fd;
2603

    
2604
    if (c->stream->truncate) {
2605
        /* truncate feed file */
2606
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2607
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2608
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2609
    } else {
2610
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2611
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2612
            return -1;
2613
        }
2614
    }
2615

    
2616
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2617
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2618
    lseek(fd, 0, SEEK_SET);
2619

    
2620
    /* init buffer input */
2621
    c->buffer_ptr = c->buffer;
2622
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2623
    c->stream->feed_opened = 1;
2624
    c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2625
    return 0;
2626
}
2627

    
2628
static int http_receive_data(HTTPContext *c)
2629
{
2630
    HTTPContext *c1;
2631
    int len, loop_run = 0;
2632

    
2633
    while (c->chunked_encoding && !c->chunk_size &&
2634
           c->buffer_end > c->buffer_ptr) {
2635
        /* read chunk header, if present */
2636
        len = recv(c->fd, c->buffer_ptr, 1, 0);
2637

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

    
2662
    if (c->buffer_end > c->buffer_ptr) {
2663
        len = recv(c->fd, c->buffer_ptr,
2664
                   FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2665
        if (len < 0) {
2666
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2667
                ff_neterrno() != FF_NETERROR(EINTR))
2668
                /* error : close connection */
2669
                goto fail;
2670
        } else if (len == 0)
2671
            /* end of connection : close it */
2672
            goto fail;
2673
        else {
2674
            c->chunk_size -= len;
2675
            c->buffer_ptr += len;
2676
            c->data_count += len;
2677
            update_datarate(&c->datarate, c->data_count);
2678
        }
2679
    }
2680

    
2681
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2682
        if (c->buffer[0] != 'f' ||
2683
            c->buffer[1] != 'm') {
2684
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2685
            goto fail;
2686
        }
2687
    }
2688

    
2689
    if (c->buffer_ptr >= c->buffer_end) {
2690
        FFStream *feed = c->stream;
2691
        /* a packet has been received : write it in the store, except
2692
           if header */
2693
        if (c->data_count > FFM_PACKET_SIZE) {
2694

    
2695
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2696
            /* XXX: use llseek or url_seek */
2697
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2698
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2699
                http_log("Error writing to feed file: %s\n", strerror(errno));
2700
                goto fail;
2701
            }
2702

    
2703
            feed->feed_write_index += FFM_PACKET_SIZE;
2704
            /* update file size */
2705
            if (feed->feed_write_index > c->stream->feed_size)
2706
                feed->feed_size = feed->feed_write_index;
2707

    
2708
            /* handle wrap around if max file size reached */
2709
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2710
                feed->feed_write_index = FFM_PACKET_SIZE;
2711

    
2712
            /* write index */
2713
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2714
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2715
                goto fail;
2716
            }
2717

    
2718
            /* wake up any waiting connections */
2719
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2720
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2721
                    c1->stream->feed == c->stream->feed)
2722
                    c1->state = HTTPSTATE_SEND_DATA;
2723
            }
2724
        } else {
2725
            /* We have a header in our hands that contains useful data */
2726
            AVFormatContext *s = NULL;
2727
            ByteIOContext *pb;
2728
            AVInputFormat *fmt_in;
2729
            int i;
2730

    
2731
            /* use feed output format name to find corresponding input format */
2732
            fmt_in = av_find_input_format(feed->fmt->name);
2733
            if (!fmt_in)
2734
                goto fail;
2735

    
2736
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2737
            pb->is_streamed = 1;
2738

    
2739
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2740
                av_free(pb);
2741
                goto fail;
2742
            }
2743

    
2744
            /* Now we have the actual streams */
2745
            if (s->nb_streams != feed->nb_streams) {
2746
                av_close_input_stream(s);
2747
                av_free(pb);
2748
                http_log("Feed '%s' stream number does not match registered feed\n",
2749
                         c->stream->feed_filename);
2750
                goto fail;
2751
            }
2752

    
2753
            for (i = 0; i < s->nb_streams; i++) {
2754
                AVStream *fst = feed->streams[i];
2755
                AVStream *st = s->streams[i];
2756
                avcodec_copy_context(fst->codec, st->codec);
2757
            }
2758

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

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

    
2778
/********************************************************************/
2779
/* RTSP handling */
2780

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2933
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2934
                                   struct in_addr my_ip)
2935
{
2936
    AVFormatContext *avc;
2937
    AVStream *avs = NULL;
2938
    int i;
2939

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

    
2955
#if !FF_API_MAX_STREAMS
2956
    if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2957
        !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2958
        goto sdp_done;
2959
#endif
2960
    if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2961
        !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2962
        goto sdp_done;
2963

    
2964
    for(i = 0; i < stream->nb_streams; i++) {
2965
        avc->streams[i] = &avs[i];
2966
        avc->streams[i]->codec = stream->streams[i]->codec;
2967
    }
2968
    *pbuffer = av_mallocz(2048);
2969
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2970

    
2971
 sdp_done:
2972
#if !FF_API_MAX_STREAMS
2973
    av_free(avc->streams);
2974
#endif
2975
    av_metadata_free(&avc->metadata);
2976
    av_free(avc);
2977
    av_free(avs);
2978

    
2979
    return strlen(*pbuffer);
2980
}
2981

    
2982
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2983
{
2984
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2985
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2986
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2987
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2988
    url_fprintf(c->pb, "\r\n");
2989
}
2990

    
2991
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2992
{
2993
    FFStream *stream;
2994
    char path1[1024];
2995
    const char *path;
2996
    uint8_t *content;
2997
    int content_length, len;
2998
    struct sockaddr_in my_addr;
2999

    
3000
    /* find which url is asked */
3001
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3002
    path = path1;
3003
    if (*path == '/')
3004
        path++;
3005

    
3006
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3007
        if (!stream->is_feed &&
3008
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3009
            !strcmp(path, stream->filename)) {
3010
            goto found;
3011
        }
3012
    }
3013
    /* no stream found */
3014
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3015
    return;
3016

    
3017
 found:
3018
    /* prepare the media description in sdp format */
3019

    
3020
    /* get the host IP */
3021
    len = sizeof(my_addr);
3022
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3023
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3024
    if (content_length < 0) {
3025
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3026
        return;
3027
    }
3028
    rtsp_reply_header(c, RTSP_STATUS_OK);
3029
    url_fprintf(c->pb, "Content-Base: %s/\r\n", url);
3030
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
3031
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
3032
    url_fprintf(c->pb, "\r\n");
3033
    put_buffer(c->pb, content, content_length);
3034
    av_free(content);
3035
}
3036

    
3037
static HTTPContext *find_rtp_session(const char *session_id)
3038
{
3039
    HTTPContext *c;
3040

    
3041
    if (session_id[0] == '\0')
3042
        return NULL;
3043

    
3044
    for(c = first_http_ctx; c != NULL; c = c->next) {
3045
        if (!strcmp(c->session_id, session_id))
3046
            return c;
3047
    }
3048
    return NULL;
3049
}
3050

    
3051
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3052
{
3053
    RTSPTransportField *th;
3054
    int i;
3055

    
3056
    for(i=0;i<h->nb_transports;i++) {
3057
        th = &h->transports[i];
3058
        if (th->lower_transport == lower_transport)
3059
            return th;
3060
    }
3061
    return NULL;
3062
}
3063

    
3064
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3065
                           RTSPMessageHeader *h)
3066
{
3067
    FFStream *stream;
3068
    int stream_index, rtp_port, rtcp_port;
3069
    char buf[1024];
3070
    char path1[1024];
3071
    const char *path;
3072
    HTTPContext *rtp_c;
3073
    RTSPTransportField *th;
3074
    struct sockaddr_in dest_addr;
3075
    RTSPActionServerSetup setup;
3076

    
3077
    /* find which url is asked */
3078
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3079
    path = path1;
3080
    if (*path == '/')
3081
        path++;
3082

    
3083
    /* now check each stream */
3084
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3085
        if (!stream->is_feed &&
3086
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3087
            /* accept aggregate filenames only if single stream */
3088
            if (!strcmp(path, stream->filename)) {
3089
                if (stream->nb_streams != 1) {
3090
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3091
                    return;
3092
                }
3093
                stream_index = 0;
3094
                goto found;
3095
            }
3096

    
3097
            for(stream_index = 0; stream_index < stream->nb_streams;
3098
                stream_index++) {
3099
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
3100
                         stream->filename, stream_index);
3101
                if (!strcmp(path, buf))
3102
                    goto found;
3103
            }
3104
        }
3105
    }
3106
    /* no stream found */
3107
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3108
    return;
3109
 found:
3110

    
3111
    /* generate session id if needed */
3112
    if (h->session_id[0] == '\0')
3113
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3114
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
3115

    
3116
    /* find rtp session, and create it if none found */
3117
    rtp_c = find_rtp_session(h->session_id);
3118
    if (!rtp_c) {
3119
        /* always prefer UDP */
3120
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3121
        if (!th) {
3122
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3123
            if (!th) {
3124
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3125
                return;
3126
            }
3127
        }
3128

    
3129
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3130
                                   th->lower_transport);
3131
        if (!rtp_c) {
3132
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3133
            return;
3134
        }
3135

    
3136
        /* open input stream */
3137
        if (open_input_stream(rtp_c, "") < 0) {
3138
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3139
            return;
3140
        }
3141
    }
3142

    
3143
    /* test if stream is OK (test needed because several SETUP needs
3144
       to be done for a given file) */
3145
    if (rtp_c->stream != stream) {
3146
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3147
        return;
3148
    }
3149

    
3150
    /* test if stream is already set up */
3151
    if (rtp_c->rtp_ctx[stream_index]) {
3152
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3153
        return;
3154
    }
3155

    
3156
    /* check transport */
3157
    th = find_transport(h, rtp_c->rtp_protocol);
3158
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3159
                th->client_port_min <= 0)) {
3160
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3161
        return;
3162
    }
3163

    
3164
    /* setup default options */
3165
    setup.transport_option[0] = '\0';
3166
    dest_addr = rtp_c->from_addr;
3167
    dest_addr.sin_port = htons(th->client_port_min);
3168

    
3169
    /* setup stream */
3170
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3171
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3172
        return;
3173
    }
3174

    
3175
    /* now everything is OK, so we can send the connection parameters */
3176
    rtsp_reply_header(c, RTSP_STATUS_OK);
3177
    /* session ID */
3178
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3179

    
3180
    switch(rtp_c->rtp_protocol) {
3181
    case RTSP_LOWER_TRANSPORT_UDP:
3182
        rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3183
        rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3184
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3185
                    "client_port=%d-%d;server_port=%d-%d",
3186
                    th->client_port_min, th->client_port_max,
3187
                    rtp_port, rtcp_port);
3188
        break;
3189
    case RTSP_LOWER_TRANSPORT_TCP:
3190
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3191
                    stream_index * 2, stream_index * 2 + 1);
3192
        break;
3193
    default:
3194
        break;
3195
    }
3196
    if (setup.transport_option[0] != '\0')
3197
        url_fprintf(c->pb, ";%s", setup.transport_option);
3198
    url_fprintf(c->pb, "\r\n");
3199

    
3200

    
3201
    url_fprintf(c->pb, "\r\n");
3202
}
3203

    
3204

    
3205
/* find an rtp connection by using the session ID. Check consistency
3206
   with filename */
3207
static HTTPContext *find_rtp_session_with_url(const char *url,
3208
                                              const char *session_id)
3209
{
3210
    HTTPContext *rtp_c;
3211
    char path1[1024];
3212
    const char *path;
3213
    char buf[1024];
3214
    int s;
3215

    
3216
    rtp_c = find_rtp_session(session_id);
3217
    if (!rtp_c)
3218
        return NULL;
3219

    
3220
    /* find which url is asked */
3221
    av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3222
    path = path1;
3223
    if (*path == '/')
3224
        path++;
3225
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3226
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3227
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3228
        rtp_c->stream->filename, s);
3229
      if(!strncmp(path, buf, sizeof(buf))) {
3230
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3231
        return rtp_c;
3232
      }
3233
    }
3234
    return NULL;
3235
}
3236

    
3237
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3238
{
3239
    HTTPContext *rtp_c;
3240

    
3241
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3242
    if (!rtp_c) {
3243
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3244
        return;
3245
    }
3246

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

    
3254
    rtp_c->state = HTTPSTATE_SEND_DATA;
3255

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

    
3263
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3264
{
3265
    HTTPContext *rtp_c;
3266

    
3267
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3268
    if (!rtp_c) {
3269
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3270
        return;
3271
    }
3272

    
3273
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3274
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3275
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3276
        return;
3277
    }
3278

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

    
3288
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3289
{
3290
    HTTPContext *rtp_c;
3291
    char session_id[32];
3292

    
3293
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3294
    if (!rtp_c) {
3295
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3296
        return;
3297
    }
3298

    
3299
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3300

    
3301
    /* abort the session */
3302
    close_connection(rtp_c);
3303

    
3304
    /* now everything is OK, so we can send the connection parameters */
3305
    rtsp_reply_header(c, RTSP_STATUS_OK);
3306
    /* session ID */
3307
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3308
    url_fprintf(c->pb, "\r\n");
3309
}
3310

    
3311

    
3312
/********************************************************************/
3313
/* RTP handling */
3314

    
3315
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3316
                                       FFStream *stream, const char *session_id,
3317
                                       enum RTSPLowerTransport rtp_protocol)
3318
{
3319
    HTTPContext *c = NULL;
3320
    const char *proto_str;
3321

    
3322
    /* XXX: should output a warning page when coming
3323
       close to the connection limit */
3324
    if (nb_connections >= nb_max_connections)
3325
        goto fail;
3326

    
3327
    /* add a new connection */
3328
    c = av_mallocz(sizeof(HTTPContext));
3329
    if (!c)
3330
        goto fail;
3331

    
3332
    c->fd = -1;
3333
    c->poll_entry = NULL;
3334
    c->from_addr = *from_addr;
3335
    c->buffer_size = IOBUFFER_INIT_SIZE;
3336
    c->buffer = av_malloc(c->buffer_size);
3337
    if (!c->buffer)
3338
        goto fail;
3339
    nb_connections++;
3340
    c->stream = stream;
3341
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3342
    c->state = HTTPSTATE_READY;
3343
    c->is_packetized = 1;
3344
    c->rtp_protocol = rtp_protocol;
3345

    
3346
    /* protocol is shown in statistics */
3347
    switch(c->rtp_protocol) {
3348
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3349
        proto_str = "MCAST";
3350
        break;
3351
    case RTSP_LOWER_TRANSPORT_UDP:
3352
        proto_str = "UDP";
3353
        break;
3354
    case RTSP_LOWER_TRANSPORT_TCP:
3355
        proto_str = "TCP";
3356
        break;
3357
    default:
3358
        proto_str = "???";
3359
        break;
3360
    }
3361
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3362
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3363

    
3364
    current_bandwidth += stream->bandwidth;
3365

    
3366
    c->next = first_http_ctx;
3367
    first_http_ctx = c;
3368
    return c;
3369

    
3370
 fail:
3371
    if (c) {
3372
        av_free(c->buffer);
3373
        av_free(c);
3374
    }
3375
    return NULL;
3376
}
3377

    
3378
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3379
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3380
   used. */
3381
static int rtp_new_av_stream(HTTPContext *c,
3382
                             int stream_index, struct sockaddr_in *dest_addr,
3383
                             HTTPContext *rtsp_c)
3384
{
3385
    AVFormatContext *ctx;
3386
    AVStream *st;
3387
    char *ipaddr;
3388
    URLContext *h = NULL;
3389
    uint8_t *dummy_buf;
3390
    int max_packet_size;
3391

    
3392
    /* now we can open the relevant output stream */
3393
    ctx = avformat_alloc_context();
3394
    if (!ctx)
3395
        return -1;
3396
    ctx->oformat = av_guess_format("rtp", NULL, NULL);
3397

    
3398
    st = av_mallocz(sizeof(AVStream));
3399
    if (!st)
3400
        goto fail;
3401
    ctx->nb_streams = 1;
3402
    ctx->streams[0] = st;
3403

    
3404
    if (!c->stream->feed ||
3405
        c->stream->feed == c->stream)
3406
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3407
    else
3408
        memcpy(st,
3409
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3410
               sizeof(AVStream));
3411
    st->priv_data = NULL;
3412

    
3413
    /* build destination RTP address */
3414
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3415

    
3416
    switch(c->rtp_protocol) {
3417
    case RTSP_LOWER_TRANSPORT_UDP:
3418
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3419
        /* RTP/UDP case */
3420

    
3421
        /* XXX: also pass as parameter to function ? */
3422
        if (c->stream->is_multicast) {
3423
            int ttl;
3424
            ttl = c->stream->multicast_ttl;
3425
            if (!ttl)
3426
                ttl = 16;
3427
            snprintf(ctx->filename, sizeof(ctx->filename),
3428
                     "rtp://%s:%d?multicast=1&ttl=%d",
3429
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3430
        } else {
3431
            snprintf(ctx->filename, sizeof(ctx->filename),
3432
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3433
        }
3434

    
3435
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3436
            goto fail;
3437
        c->rtp_handles[stream_index] = h;
3438
        max_packet_size = url_get_max_packet_size(h);
3439
        break;
3440
    case RTSP_LOWER_TRANSPORT_TCP:
3441
        /* RTP/TCP case */
3442
        c->rtsp_c = rtsp_c;
3443
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3444
        break;
3445
    default:
3446
        goto fail;
3447
    }
3448

    
3449
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3450
             ipaddr, ntohs(dest_addr->sin_port),
3451
             c->stream->filename, stream_index, c->protocol);
3452

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

    
3469
    c->rtp_ctx[stream_index] = ctx;
3470
    return 0;
3471
}
3472

    
3473
/********************************************************************/
3474
/* ffserver initialization */
3475

    
3476
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3477
{
3478
    AVStream *fst;
3479

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

    
3504
/* return the stream number in the feed */
3505
static int add_av_stream(FFStream *feed, AVStream *st)
3506
{
3507
    AVStream *fst;
3508
    AVCodecContext *av, *av1;
3509
    int i;
3510

    
3511
    av = st->codec;
3512
    for(i=0;i<feed->nb_streams;i++) {
3513
        st = feed->streams[i];
3514
        av1 = st->codec;
3515
        if (av1->codec_id == av->codec_id &&
3516
            av1->codec_type == av->codec_type &&
3517
            av1->bit_rate == av->bit_rate) {
3518

    
3519
            switch(av->codec_type) {
3520
            case AVMEDIA_TYPE_AUDIO:
3521
                if (av1->channels == av->channels &&
3522
                    av1->sample_rate == av->sample_rate)
3523
                    goto found;
3524
                break;
3525
            case AVMEDIA_TYPE_VIDEO:
3526
                if (av1->width == av->width &&
3527
                    av1->height == av->height &&
3528
                    av1->time_base.den == av->time_base.den &&
3529
                    av1->time_base.num == av->time_base.num &&
3530
                    av1->gop_size == av->gop_size)
3531
                    goto found;
3532
                break;
3533
            default:
3534
                abort();
3535
            }
3536
        }
3537
    }
3538

    
3539
    fst = add_av_stream1(feed, av, 0);
3540
    if (!fst)
3541
        return -1;
3542
    return feed->nb_streams - 1;
3543
 found:
3544
    return i;
3545
}
3546

    
3547
static void remove_stream(FFStream *stream)
3548
{
3549
    FFStream **ps;
3550
    ps = &first_stream;
3551
    while (*ps != NULL) {
3552
        if (*ps == stream)
3553
            *ps = (*ps)->next;
3554
        else
3555
            ps = &(*ps)->next;
3556
    }
3557
}
3558

    
3559
/* specific mpeg4 handling : we extract the raw parameters */
3560
static void extract_mpeg4_header(AVFormatContext *infile)
3561
{
3562
    int mpeg4_count, i, size;
3563
    AVPacket pkt;
3564
    AVStream *st;
3565
    const uint8_t *p;
3566

    
3567
    mpeg4_count = 0;
3568
    for(i=0;i<infile->nb_streams;i++) {
3569
        st = infile->streams[i];
3570
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3571
            st->codec->extradata_size == 0) {
3572
            mpeg4_count++;
3573
        }
3574
    }
3575
    if (!mpeg4_count)
3576
        return;
3577

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

    
3608
/* compute the needed AVStream for each file */
3609
static void build_file_streams(void)
3610
{
3611
    FFStream *stream, *stream_next;
3612
    AVFormatContext *infile;
3613
    int i, ret;
3614

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

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

    
3649
                for(i=0;i<infile->nb_streams;i++)
3650
                    add_av_stream1(stream, infile->streams[i]->codec, 1);
3651

    
3652
                av_close_input_file(infile);
3653
            }
3654
        }
3655
    }
3656
}
3657

    
3658
/* compute the needed AVStream for each feed */
3659
static void build_feed_streams(void)
3660
{
3661
    FFStream *stream, *feed;
3662
    int i;
3663

    
3664
    /* gather all streams */
3665
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3666
        feed = stream->feed;
3667
        if (feed) {
3668
            if (!stream->is_feed) {
3669
                /* we handle a stream coming from a feed */
3670
                for(i=0;i<stream->nb_streams;i++)
3671
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3672
            }
3673
        }
3674
    }
3675

    
3676
    /* gather all streams */
3677
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3678
        feed = stream->feed;
3679
        if (feed) {
3680
            if (stream->is_feed) {
3681
                for(i=0;i<stream->nb_streams;i++)
3682
                    stream->feed_streams[i] = i;
3683
            }
3684
        }
3685
    }
3686

    
3687
    /* create feed files if needed */
3688
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3689
        int fd;
3690

    
3691
        if (url_exist(feed->feed_filename)) {
3692
            /* See if it matches */
3693
            AVFormatContext *s;
3694
            int matches = 0;
3695

    
3696
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3697
                /* Now see if it matches */
3698
                if (s->nb_streams == feed->nb_streams) {
3699
                    matches = 1;
3700
                    for(i=0;i<s->nb_streams;i++) {
3701
                        AVStream *sf, *ss;
3702
                        sf = feed->streams[i];
3703
                        ss = s->streams[i];
3704

    
3705
                        if (sf->index != ss->index ||
3706
                            sf->id != ss->id) {
3707
                            http_log("Index & Id do not match for stream %d (%s)\n",
3708
                                   i, feed->feed_filename);
3709
                            matches = 0;
3710
                        } else {
3711
                            AVCodecContext *ccf, *ccs;
3712

    
3713
                            ccf = sf->codec;
3714
                            ccs = ss->codec;
3715
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3716

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

    
3750
                av_close_input_file(s);
3751
            } else
3752
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3753
                        feed->feed_filename);
3754

    
3755
            if (!matches) {
3756
                if (feed->readonly) {
3757
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3758
                        feed->feed_filename);
3759
                    exit(1);
3760
                }
3761
                unlink(feed->feed_filename);
3762
            }
3763
        }
3764
        if (!url_exist(feed->feed_filename)) {
3765
            AVFormatContext s1 = {0}, *s = &s1;
3766

    
3767
            if (feed->readonly) {
3768
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3769
                    feed->feed_filename);
3770
                exit(1);
3771
            }
3772

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

    
3803
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3804
        feed->feed_size = lseek(fd, 0, SEEK_END);
3805
        /* ensure that we do not wrap before the end of file */
3806
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3807
            feed->feed_max_size = feed->feed_size;
3808

    
3809
        close(fd);
3810
    }
3811
}
3812

    
3813
/* compute the bandwidth used by each stream */
3814
static void compute_bandwidth(void)
3815
{
3816
    unsigned bandwidth;
3817
    int i;
3818
    FFStream *stream;
3819

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

    
3837
/* add a codec and set the default parameters */
3838
static void add_codec(FFStream *stream, AVCodecContext *av)
3839
{
3840
    AVStream *st;
3841

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

    
3876
        if (!av->nsse_weight)
3877
            av->nsse_weight = 8;
3878

    
3879
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3880
        if (!av->me_method)
3881
            av->me_method = ME_EPZS;
3882
        av->rc_buffer_aggressivity = 1.0;
3883

    
3884
        if (!av->rc_eq)
3885
            av->rc_eq = "tex^qComp";
3886
        if (!av->i_quant_factor)
3887
            av->i_quant_factor = -0.8;
3888
        if (!av->b_quant_factor)
3889
            av->b_quant_factor = 1.25;
3890
        if (!av->b_quant_offset)
3891
            av->b_quant_offset = 1.25;
3892
        if (!av->rc_max_rate)
3893
            av->rc_max_rate = av->bit_rate * 2;
3894

    
3895
        if (av->rc_max_rate && !av->rc_buffer_size) {
3896
            av->rc_buffer_size = av->rc_max_rate;
3897
        }
3898

    
3899

    
3900
        break;
3901
    default:
3902
        abort();
3903
    }
3904

    
3905
    st = av_mallocz(sizeof(AVStream));
3906
    if (!st)
3907
        return;
3908
    st->codec = avcodec_alloc_context();
3909
    stream->streams[stream->nb_streams++] = st;
3910
    memcpy(st->codec, av, sizeof(AVCodecContext));
3911
}
3912

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

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

    
3920
    return p->id;
3921
}
3922

    
3923
static enum CodecID opt_video_codec(const char *arg)
3924
{
3925
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3926

    
3927
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3928
        return CODEC_ID_NONE;
3929

    
3930
    return p->id;
3931
}
3932

    
3933
/* simplistic plugin support */
3934

    
3935
#if HAVE_DLOPEN
3936
static void load_module(const char *filename)
3937
{
3938
    void *dll;
3939
    void (*init_func)(void);
3940
    dll = dlopen(filename, RTLD_NOW);
3941
    if (!dll) {
3942
        fprintf(stderr, "Could not load module '%s' - %s\n",
3943
                filename, dlerror());
3944
        return;
3945
    }
3946

    
3947
    init_func = dlsym(dll, "ffserver_module_init");
3948
    if (!init_func) {
3949
        fprintf(stderr,
3950
                "%s: init function 'ffserver_module_init()' not found\n",
3951
                filename);
3952
        dlclose(dll);
3953
    }
3954

    
3955
    init_func();
3956
}
3957
#endif
3958

    
3959
static int ffserver_opt_default(const char *opt, const char *arg,
3960
                       AVCodecContext *avctx, int type)
3961
{
3962
    int ret = 0;
3963
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3964
    if(o)
3965
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3966
    return ret;
3967
}
3968

    
3969
static int ffserver_opt_preset(const char *arg,
3970
                       AVCodecContext *avctx, int type,
3971
                       enum CodecID *audio_id, enum CodecID *video_id)
3972
{
3973
    FILE *f=NULL;
3974
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
3975
    int ret = 0;
3976
    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3977

    
3978
    if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3979
                              codec ? codec->name : NULL))) {
3980
        fprintf(stderr, "File for preset '%s' not found\n", arg);
3981
        return 1;
3982
    }
3983

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

    
4007
    fclose(f);
4008

    
4009
    return ret;
4010
}
4011

    
4012
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4013
                                             const char *mime_type)
4014
{
4015
    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4016

    
4017
    if (fmt) {
4018
        AVOutputFormat *stream_fmt;
4019
        char stream_format_name[64];
4020

    
4021
        snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4022
        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4023

    
4024
        if (stream_fmt)
4025
            fmt = stream_fmt;
4026
    }
4027

    
4028
    return fmt;
4029
}
4030

    
4031
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4032
{
4033
    va_list vl;
4034
    va_start(vl, fmt);
4035
    fprintf(stderr, "%s:%d: ", filename, line_num);
4036
    vfprintf(stderr, fmt, vl);
4037
    va_end(vl);
4038

    
4039
    (*errors)++;
4040
}
4041

    
4042
static int parse_ffconfig(const char *filename)
4043
{
4044
    FILE *f;
4045
    char line[1024];
4046
    char cmd[64];
4047
    char arg[1024];
4048
    const char *p;
4049
    int val, errors, line_num;
4050
    FFStream **last_stream, *stream, *redirect;
4051
    FFStream **last_feed, *feed, *s;
4052
    AVCodecContext audio_enc, video_enc;
4053
    enum CodecID audio_id, video_id;
4054

    
4055
    f = fopen(filename, "r");
4056
    if (!f) {
4057
        perror(filename);
4058
        return -1;
4059
    }
4060

    
4061
    errors = 0;
4062
    line_num = 0;
4063
    first_stream = NULL;
4064
    last_stream = &first_stream;
4065
    first_feed = NULL;
4066
    last_feed = &first_feed;
4067
    stream = NULL;
4068
    feed = NULL;
4069
    redirect = NULL;
4070
    audio_id = CODEC_ID_NONE;
4071
    video_id = CODEC_ID_NONE;
4072

    
4073
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4074
    for(;;) {
4075
        if (fgets(line, sizeof(line), f) == NULL)
4076
            break;
4077
        line_num++;
4078
        p = line;
4079
        while (isspace(*p))
4080
            p++;
4081
        if (*p == '\0' || *p == '#')
4082
            continue;
4083

    
4084
        get_arg(cmd, sizeof(cmd), &p);
4085

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

    
4151
                for (s = first_feed; s; s = s->next) {
4152
                    if (!strcmp(feed->filename, s->filename)) {
4153
                        ERROR("Feed '%s' already registered\n", s->filename);
4154
                    }
4155
                }
4156

    
4157
                feed->fmt = av_guess_format("ffm", NULL, NULL);
4158
                /* defaut feed file */
4159
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4160
                         "/tmp/%s.ffm", feed->filename);
4161
                feed->feed_max_size = 5 * 1024 * 1024;
4162
                feed->is_feed = 1;
4163
                feed->feed = feed; /* self feeding :-) */
4164

    
4165
                /* add in stream list */
4166
                *last_stream = feed;
4167
                last_stream = &feed->next;
4168
                /* add in feed list */
4169
                *last_feed = feed;
4170
                last_feed = &feed->next_feed;
4171
            }
4172
        } else if (!strcasecmp(cmd, "Launch")) {
4173
            if (feed) {
4174
                int i;
4175

    
4176
                feed->child_argv = av_mallocz(64 * sizeof(char *));
4177

    
4178
                for (i = 0; i < 62; i++) {
4179
                    get_arg(arg, sizeof(arg), &p);
4180
                    if (!arg[0])
4181
                        break;
4182

    
4183
                    feed->child_argv[i] = av_strdup(arg);
4184
                }
4185

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

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

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

    
4254
                for (s = first_stream; s; s = s->next) {
4255
                    if (!strcmp(stream->filename, s->filename)) {
4256
                        ERROR("Stream '%s' already registered\n", s->filename);
4257
                    }
4258
                }
4259

    
4260
                stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4261
                avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4262
                avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4263
                audio_id = CODEC_ID_NONE;
4264
                video_id = CODEC_ID_NONE;
4265
                if (stream->fmt) {
4266
                    audio_id = stream->fmt->audio_codec;
4267
                    video_id = stream->fmt->video_codec;
4268
                }
4269

    
4270
                *last_stream = stream;
4271
                last_stream = &stream->next;
4272
            }
4273
        } else if (!strcasecmp(cmd, "Feed")) {
4274
            get_arg(arg, sizeof(arg), &p);
4275
            if (stream) {
4276
                FFStream *sfeed;
4277

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

    
4380
                get_arg(arg, sizeof(arg), &p);
4381

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

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

    
4637
    fclose(f);
4638
    if (errors)
4639
        return -1;
4640
    else
4641
        return 0;
4642
}
4643

    
4644
static void handle_child_exit(int sig)
4645
{
4646
    pid_t pid;
4647
    int status;
4648

    
4649
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4650
        FFStream *feed;
4651

    
4652
        for (feed = first_feed; feed; feed = feed->next) {
4653
            if (feed->pid == pid) {
4654
                int uptime = time(0) - feed->pid_start;
4655

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

    
4659
                if (uptime < 30)
4660
                    /* Turn off any more restarts */
4661
                    feed->child_argv = 0;
4662
            }
4663
        }
4664
    }
4665

    
4666
    need_to_start_children = 1;
4667
}
4668

    
4669
static void opt_debug(void)
4670
{
4671
    ffserver_debug = 1;
4672
    ffserver_daemon = 0;
4673
    logfilename[0] = '-';
4674
}
4675

    
4676
static void show_help(void)
4677
{
4678
    printf("usage: ffserver [options]\n"
4679
           "Hyper fast multi format Audio/Video streaming server\n");
4680
    printf("\n");
4681
    show_help_options(options, "Main options:\n", 0, 0);
4682
}
4683

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

    
4692
int main(int argc, char **argv)
4693
{
4694
    struct sigaction sigact;
4695

    
4696
    av_register_all();
4697

    
4698
    show_banner();
4699

    
4700
    my_program_name = argv[0];
4701
    my_program_dir = getcwd(0, 0);
4702
    ffserver_daemon = 1;
4703

    
4704
    parse_options(argc, argv, options, NULL);
4705

    
4706
    unsetenv("http_proxy");             /* Kill the http_proxy */
4707

    
4708
    av_lfg_init(&random_state, av_get_random_seed());
4709

    
4710
    memset(&sigact, 0, sizeof(sigact));
4711
    sigact.sa_handler = handle_child_exit;
4712
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4713
    sigaction(SIGCHLD, &sigact, 0);
4714

    
4715
    if (parse_ffconfig(config_filename) < 0) {
4716
        fprintf(stderr, "Incorrect config file - exiting.\n");
4717
        exit(1);
4718
    }
4719

    
4720
    /* open log file if needed */
4721
    if (logfilename[0] != '\0') {
4722
        if (!strcmp(logfilename, "-"))
4723
            logfile = stdout;
4724
        else
4725
            logfile = fopen(logfilename, "