Statistics
| Branch: | Revision:

ffmpeg / ffserver.c @ 0eb4ff9e

History | View | Annotate | Download (151 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
/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32
#include "libavformat/avformat.h"
33
#include "libavformat/network.h"
34
#include "libavformat/os_support.h"
35
#include "libavformat/rtpdec.h"
36
#include "libavformat/rtsp.h"
37
#include "libavutil/avstring.h"
38
#include "libavutil/lfg.h"
39
#include "libavutil/random_seed.h"
40
#include "libavutil/intreadwrite.h"
41
#include "libavcodec/opt.h"
42
#include <stdarg.h>
43
#include <unistd.h>
44
#include <fcntl.h>
45
#include <sys/ioctl.h>
46
#if HAVE_POLL_H
47
#include <poll.h>
48
#endif
49
#include <errno.h>
50
#include <sys/time.h>
51
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
52
#include <time.h>
53
#include <sys/wait.h>
54
#include <signal.h>
55
#if HAVE_DLFCN_H
56
#include <dlfcn.h>
57
#endif
58

    
59
#include "cmdutils.h"
60

    
61
#undef exit
62

    
63
const char program_name[] = "FFserver";
64
const int program_birth_year = 2000;
65

    
66
static const OptionDef options[];
67

    
68
enum HTTPState {
69
    HTTPSTATE_WAIT_REQUEST,
70
    HTTPSTATE_SEND_HEADER,
71
    HTTPSTATE_SEND_DATA_HEADER,
72
    HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */
73
    HTTPSTATE_SEND_DATA_TRAILER,
74
    HTTPSTATE_RECEIVE_DATA,
75
    HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */
76
    HTTPSTATE_READY,
77

    
78
    RTSPSTATE_WAIT_REQUEST,
79
    RTSPSTATE_SEND_REPLY,
80
    RTSPSTATE_SEND_PACKET,
81
};
82

    
83
static const char *http_state[] = {
84
    "HTTP_WAIT_REQUEST",
85
    "HTTP_SEND_HEADER",
86

    
87
    "SEND_DATA_HEADER",
88
    "SEND_DATA",
89
    "SEND_DATA_TRAILER",
90
    "RECEIVE_DATA",
91
    "WAIT_FEED",
92
    "READY",
93

    
94
    "RTSP_WAIT_REQUEST",
95
    "RTSP_SEND_REPLY",
96
    "RTSP_SEND_PACKET",
97
};
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
    struct HTTPContext *next;
128
    int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
129
    int64_t data_count;
130
    /* feed input */
131
    int feed_fd;
132
    /* input format handling */
133
    AVFormatContext *fmt_in;
134
    int64_t start_time;            /* In milliseconds - this wraps fairly often */
135
    int64_t first_pts;            /* initial pts value */
136
    int64_t cur_pts;             /* current pts value from the stream in us */
137
    int64_t cur_frame_duration;  /* duration of the current frame in us */
138
    int cur_frame_bytes;       /* output frame size, needed to compute
139
                                  the time at which we send each
140
                                  packet */
141
    int pts_stream_index;        /* stream we choose as clock reference */
142
    int64_t cur_clock;           /* current clock reference value in us */
143
    /* output format handling */
144
    struct FFStream *stream;
145
    /* -1 is invalid stream */
146
    int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
147
    int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
148
    int switch_pending;
149
    AVFormatContext fmt_ctx; /* instance of FFStream for one user */
150
    int last_packet_sent; /* true if last data packet was sent */
151
    int suppress_log;
152
    DataRateData datarate;
153
    int wmp_client_id;
154
    char protocol[16];
155
    char method[16];
156
    char url[128];
157
    int buffer_size;
158
    uint8_t *buffer;
159
    int is_packetized; /* if true, the stream is packetized */
160
    int packet_stream_index; /* current stream for output in state machine */
161

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

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

    
172
    /* RTP/UDP specific */
173
    URLContext *rtp_handles[MAX_STREAMS];
174

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

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

    
187
enum IPAddressAction {
188
    IP_ALLOW = 1,
189
    IP_DENY,
190
};
191

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

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

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

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

    
254
static struct sockaddr_in my_http_addr;
255
static struct sockaddr_in my_rtsp_addr;
256

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

    
262
static void new_connection(int server_fd, int is_rtsp);
263
static void close_connection(HTTPContext *c);
264

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

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

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

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

    
295
static const char *my_program_name;
296
static const char *my_program_dir;
297

    
298
static const char *config_filename;
299
static int ffserver_debug;
300
static int ffserver_daemon;
301
static int no_launch;
302
static int need_to_start_children;
303

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

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

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

    
314
static AVLFG random_state;
315

    
316
static FILE *logfile = NULL;
317

    
318
static char *ctime1(char *buf2)
319
{
320
    time_t ti;
321
    char *p;
322

    
323
    ti = time(NULL);
324
    p = ctime(&ti);
325
    strcpy(buf2, p);
326
    p = buf2 + strlen(p) - 1;
327
    if (*p == '\n')
328
        *p = '\0';
329
    return buf2;
330
}
331

    
332
static void http_vlog(const char *fmt, va_list vargs)
333
{
334
    static int print_prefix = 1;
335
    if (logfile) {
336
        if (print_prefix) {
337
            char buf[32];
338
            ctime1(buf);
339
            fprintf(logfile, "%s ", buf);
340
        }
341
        print_prefix = strstr(fmt, "\n") != NULL;
342
        vfprintf(logfile, fmt, vargs);
343
        fflush(logfile);
344
    }
345
}
346

    
347
void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
348
{
349
    va_list vargs;
350
    va_start(vargs, fmt);
351
    http_vlog(fmt, vargs);
352
    va_end(vargs);
353
}
354

    
355
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
356
{
357
    static int print_prefix = 1;
358
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
359
    if (level > av_log_get_level())
360
        return;
361
    if (print_prefix && avc)
362
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
363
    print_prefix = strstr(fmt, "\n") != NULL;
364
    http_vlog(fmt, vargs);
365
}
366

    
367
static void log_connection(HTTPContext *c)
368
{
369
    if (c->suppress_log)
370
        return;
371

    
372
    http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
373
             inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
374
             c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
375
}
376

    
377
static void update_datarate(DataRateData *drd, int64_t count)
378
{
379
    if (!drd->time1 && !drd->count1) {
380
        drd->time1 = drd->time2 = cur_time;
381
        drd->count1 = drd->count2 = count;
382
    } else if (cur_time - drd->time2 > 5000) {
383
        drd->time1 = drd->time2;
384
        drd->count1 = drd->count2;
385
        drd->time2 = cur_time;
386
        drd->count2 = count;
387
    }
388
}
389

    
390
/* In bytes per second */
391
static int compute_datarate(DataRateData *drd, int64_t count)
392
{
393
    if (cur_time == drd->time1)
394
        return 0;
395

    
396
    return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
397
}
398

    
399

    
400
static void start_children(FFStream *feed)
401
{
402
    if (no_launch)
403
        return;
404

    
405
    for (; feed; feed = feed->next) {
406
        if (feed->child_argv && !feed->pid) {
407
            feed->pid_start = time(0);
408

    
409
            feed->pid = fork();
410

    
411
            if (feed->pid < 0) {
412
                http_log("Unable to create children\n");
413
                exit(1);
414
            }
415
            if (!feed->pid) {
416
                /* In child */
417
                char pathname[1024];
418
                char *slash;
419
                int i;
420

    
421
                av_strlcpy(pathname, my_program_name, sizeof(pathname));
422

    
423
                slash = strrchr(pathname, '/');
424
                if (!slash)
425
                    slash = pathname;
426
                else
427
                    slash++;
428
                strcpy(slash, "ffmpeg");
429

    
430
                http_log("Launch commandline: ");
431
                http_log("%s ", pathname);
432
                for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
433
                    http_log("%s ", feed->child_argv[i]);
434
                http_log("\n");
435

    
436
                for (i = 3; i < 256; i++)
437
                    close(i);
438

    
439
                if (!ffserver_debug) {
440
                    i = open("/dev/null", O_RDWR);
441
                    if (i != -1) {
442
                        dup2(i, 0);
443
                        dup2(i, 1);
444
                        dup2(i, 2);
445
                        close(i);
446
                    }
447
                }
448

    
449
                /* This is needed to make relative pathnames work */
450
                chdir(my_program_dir);
451

    
452
                signal(SIGPIPE, SIG_DFL);
453

    
454
                execvp(pathname, feed->child_argv);
455

    
456
                _exit(1);
457
            }
458
        }
459
    }
460
}
461

    
462
/* open a listening socket */
463
static int socket_open_listen(struct sockaddr_in *my_addr)
464
{
465
    int server_fd, tmp;
466

    
467
    server_fd = socket(AF_INET,SOCK_STREAM,0);
468
    if (server_fd < 0) {
469
        perror ("socket");
470
        return -1;
471
    }
472

    
473
    tmp = 1;
474
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
475

    
476
    if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
477
        char bindmsg[32];
478
        snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
479
        perror (bindmsg);
480
        closesocket(server_fd);
481
        return -1;
482
    }
483

    
484
    if (listen (server_fd, 5) < 0) {
485
        perror ("listen");
486
        closesocket(server_fd);
487
        return -1;
488
    }
489
    ff_socket_nonblock(server_fd, 1);
490

    
491
    return server_fd;
492
}
493

    
494
/* start all multicast streams */
495
static void start_multicast(void)
496
{
497
    FFStream *stream;
498
    char session_id[32];
499
    HTTPContext *rtp_c;
500
    struct sockaddr_in dest_addr;
501
    int default_port, stream_index;
502

    
503
    default_port = 6000;
504
    for(stream = first_stream; stream != NULL; stream = stream->next) {
505
        if (stream->is_multicast) {
506
            /* open the RTP connection */
507
            snprintf(session_id, sizeof(session_id), "%08x%08x",
508
                     av_lfg_get(&random_state), av_lfg_get(&random_state));
509

    
510
            /* choose a port if none given */
511
            if (stream->multicast_port == 0) {
512
                stream->multicast_port = default_port;
513
                default_port += 100;
514
            }
515

    
516
            dest_addr.sin_family = AF_INET;
517
            dest_addr.sin_addr = stream->multicast_ip;
518
            dest_addr.sin_port = htons(stream->multicast_port);
519

    
520
            rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
521
                                       RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
522
            if (!rtp_c)
523
                continue;
524

    
525
            if (open_input_stream(rtp_c, "") < 0) {
526
                http_log("Could not open input stream for stream '%s'\n",
527
                         stream->filename);
528
                continue;
529
            }
530

    
531
            /* open each RTP stream */
532
            for(stream_index = 0; stream_index < stream->nb_streams;
533
                stream_index++) {
534
                dest_addr.sin_port = htons(stream->multicast_port +
535
                                           2 * stream_index);
536
                if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
537
                    http_log("Could not open output stream '%s/streamid=%d'\n",
538
                             stream->filename, stream_index);
539
                    exit(1);
540
                }
541
            }
542

    
543
            /* change state to send data */
544
            rtp_c->state = HTTPSTATE_SEND_DATA;
545
        }
546
    }
547
}
548

    
549
/* main loop of the http server */
550
static int http_server(void)
551
{
552
    int server_fd = 0, rtsp_server_fd = 0;
553
    int ret, delay, delay1;
554
    struct pollfd *poll_table, *poll_entry;
555
    HTTPContext *c, *c_next;
556

    
557
    if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
558
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
559
        return -1;
560
    }
561

    
562
    if (my_http_addr.sin_port) {
563
        server_fd = socket_open_listen(&my_http_addr);
564
        if (server_fd < 0)
565
            return -1;
566
    }
567

    
568
    if (my_rtsp_addr.sin_port) {
569
        rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
570
        if (rtsp_server_fd < 0)
571
            return -1;
572
    }
573

    
574
    if (!rtsp_server_fd && !server_fd) {
575
        http_log("HTTP and RTSP disabled.\n");
576
        return -1;
577
    }
578

    
579
    http_log("FFserver started.\n");
580

    
581
    start_children(first_feed);
582

    
583
    start_multicast();
584

    
585
    for(;;) {
586
        poll_entry = poll_table;
587
        if (server_fd) {
588
            poll_entry->fd = server_fd;
589
            poll_entry->events = POLLIN;
590
            poll_entry++;
591
        }
592
        if (rtsp_server_fd) {
593
            poll_entry->fd = rtsp_server_fd;
594
            poll_entry->events = POLLIN;
595
            poll_entry++;
596
        }
597

    
598
        /* wait for events on each HTTP handle */
599
        c = first_http_ctx;
600
        delay = 1000;
601
        while (c != NULL) {
602
            int fd;
603
            fd = c->fd;
604
            switch(c->state) {
605
            case HTTPSTATE_SEND_HEADER:
606
            case RTSPSTATE_SEND_REPLY:
607
            case RTSPSTATE_SEND_PACKET:
608
                c->poll_entry = poll_entry;
609
                poll_entry->fd = fd;
610
                poll_entry->events = POLLOUT;
611
                poll_entry++;
612
                break;
613
            case HTTPSTATE_SEND_DATA_HEADER:
614
            case HTTPSTATE_SEND_DATA:
615
            case HTTPSTATE_SEND_DATA_TRAILER:
616
                if (!c->is_packetized) {
617
                    /* for TCP, we output as much as we can (may need to put a limit) */
618
                    c->poll_entry = poll_entry;
619
                    poll_entry->fd = fd;
620
                    poll_entry->events = POLLOUT;
621
                    poll_entry++;
622
                } else {
623
                    /* when ffserver is doing the timing, we work by
624
                       looking at which packet need to be sent every
625
                       10 ms */
626
                    delay1 = 10; /* one tick wait XXX: 10 ms assumed */
627
                    if (delay1 < delay)
628
                        delay = delay1;
629
                }
630
                break;
631
            case HTTPSTATE_WAIT_REQUEST:
632
            case HTTPSTATE_RECEIVE_DATA:
633
            case HTTPSTATE_WAIT_FEED:
634
            case RTSPSTATE_WAIT_REQUEST:
635
                /* need to catch errors */
636
                c->poll_entry = poll_entry;
637
                poll_entry->fd = fd;
638
                poll_entry->events = POLLIN;/* Maybe this will work */
639
                poll_entry++;
640
                break;
641
            default:
642
                c->poll_entry = NULL;
643
                break;
644
            }
645
            c = c->next;
646
        }
647

    
648
        /* wait for an event on one connection. We poll at least every
649
           second to handle timeouts */
650
        do {
651
            ret = poll(poll_table, poll_entry - poll_table, delay);
652
            if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
653
                ff_neterrno() != FF_NETERROR(EINTR))
654
                return -1;
655
        } while (ret < 0);
656

    
657
        cur_time = av_gettime() / 1000;
658

    
659
        if (need_to_start_children) {
660
            need_to_start_children = 0;
661
            start_children(first_feed);
662
        }
663

    
664
        /* now handle the events */
665
        for(c = first_http_ctx; c != NULL; c = c_next) {
666
            c_next = c->next;
667
            if (handle_connection(c) < 0) {
668
                /* close and free the connection */
669
                log_connection(c);
670
                close_connection(c);
671
            }
672
        }
673

    
674
        poll_entry = poll_table;
675
        if (server_fd) {
676
            /* new HTTP connection request ? */
677
            if (poll_entry->revents & POLLIN)
678
                new_connection(server_fd, 0);
679
            poll_entry++;
680
        }
681
        if (rtsp_server_fd) {
682
            /* new RTSP connection request ? */
683
            if (poll_entry->revents & POLLIN)
684
                new_connection(rtsp_server_fd, 1);
685
        }
686
    }
687
}
688

    
689
/* start waiting for a new HTTP/RTSP request */
690
static void start_wait_request(HTTPContext *c, int is_rtsp)
691
{
692
    c->buffer_ptr = c->buffer;
693
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
694

    
695
    if (is_rtsp) {
696
        c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
697
        c->state = RTSPSTATE_WAIT_REQUEST;
698
    } else {
699
        c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
700
        c->state = HTTPSTATE_WAIT_REQUEST;
701
    }
702
}
703

    
704
static void http_send_too_busy_reply(int fd)
705
{
706
    char buffer[300];
707
    int len = snprintf(buffer, sizeof(buffer),
708
                       "HTTP/1.0 200 Server too busy\r\n"
709
                       "Content-type: text/html\r\n"
710
                       "\r\n"
711
                       "<html><head><title>Too busy</title></head><body>\r\n"
712
                       "<p>The server is too busy to serve your request at this time.</p>\r\n"
713
                       "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
714
                       "</body></html>\r\n",
715
                       nb_connections, nb_max_connections);
716
    send(fd, buffer, len, 0);
717
}
718

    
719

    
720
static void new_connection(int server_fd, int is_rtsp)
721
{
722
    struct sockaddr_in from_addr;
723
    int fd, len;
724
    HTTPContext *c = NULL;
725

    
726
    len = sizeof(from_addr);
727
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
728
                &len);
729
    if (fd < 0) {
730
        http_log("error during accept %s\n", strerror(errno));
731
        return;
732
    }
733
    ff_socket_nonblock(fd, 1);
734

    
735
    if (nb_connections >= nb_max_connections) {
736
        http_send_too_busy_reply(fd);
737
        goto fail;
738
    }
739

    
740
    /* add a new connection */
741
    c = av_mallocz(sizeof(HTTPContext));
742
    if (!c)
743
        goto fail;
744

    
745
    c->fd = fd;
746
    c->poll_entry = NULL;
747
    c->from_addr = from_addr;
748
    c->buffer_size = IOBUFFER_INIT_SIZE;
749
    c->buffer = av_malloc(c->buffer_size);
750
    if (!c->buffer)
751
        goto fail;
752

    
753
    c->next = first_http_ctx;
754
    first_http_ctx = c;
755
    nb_connections++;
756

    
757
    start_wait_request(c, is_rtsp);
758

    
759
    return;
760

    
761
 fail:
762
    if (c) {
763
        av_free(c->buffer);
764
        av_free(c);
765
    }
766
    closesocket(fd);
767
}
768

    
769
static void close_connection(HTTPContext *c)
770
{
771
    HTTPContext **cp, *c1;
772
    int i, nb_streams;
773
    AVFormatContext *ctx;
774
    URLContext *h;
775
    AVStream *st;
776

    
777
    /* remove connection from list */
778
    cp = &first_http_ctx;
779
    while ((*cp) != NULL) {
780
        c1 = *cp;
781
        if (c1 == c)
782
            *cp = c->next;
783
        else
784
            cp = &c1->next;
785
    }
786

    
787
    /* remove references, if any (XXX: do it faster) */
788
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
789
        if (c1->rtsp_c == c)
790
            c1->rtsp_c = NULL;
791
    }
792

    
793
    /* remove connection associated resources */
794
    if (c->fd >= 0)
795
        closesocket(c->fd);
796
    if (c->fmt_in) {
797
        /* close each frame parser */
798
        for(i=0;i<c->fmt_in->nb_streams;i++) {
799
            st = c->fmt_in->streams[i];
800
            if (st->codec->codec)
801
                avcodec_close(st->codec);
802
        }
803
        av_close_input_file(c->fmt_in);
804
    }
805

    
806
    /* free RTP output streams if any */
807
    nb_streams = 0;
808
    if (c->stream)
809
        nb_streams = c->stream->nb_streams;
810

    
811
    for(i=0;i<nb_streams;i++) {
812
        ctx = c->rtp_ctx[i];
813
        if (ctx) {
814
            av_write_trailer(ctx);
815
            av_free(ctx);
816
        }
817
        h = c->rtp_handles[i];
818
        if (h)
819
            url_close(h);
820
    }
821

    
822
    ctx = &c->fmt_ctx;
823

    
824
    if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
825
        if (ctx->oformat) {
826
            /* prepare header */
827
            if (url_open_dyn_buf(&ctx->pb) >= 0) {
828
                av_write_trailer(ctx);
829
                av_freep(&c->pb_buffer);
830
                url_close_dyn_buf(ctx->pb, &c->pb_buffer);
831
            }
832
        }
833
    }
834

    
835
    for(i=0; i<ctx->nb_streams; i++)
836
        av_free(ctx->streams[i]);
837

    
838
    if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
839
        current_bandwidth -= c->stream->bandwidth;
840

    
841
    /* signal that there is no feed if we are the feeder socket */
842
    if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
843
        c->stream->feed_opened = 0;
844
        close(c->feed_fd);
845
    }
846

    
847
    av_freep(&c->pb_buffer);
848
    av_freep(&c->packet_buffer);
849
    av_free(c->buffer);
850
    av_free(c);
851
    nb_connections--;
852
}
853

    
854
static int handle_connection(HTTPContext *c)
855
{
856
    int len, ret;
857

    
858
    switch(c->state) {
859
    case HTTPSTATE_WAIT_REQUEST:
860
    case RTSPSTATE_WAIT_REQUEST:
861
        /* timeout ? */
862
        if ((c->timeout - cur_time) < 0)
863
            return -1;
864
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
865
            return -1;
866

    
867
        /* no need to read if no events */
868
        if (!(c->poll_entry->revents & POLLIN))
869
            return 0;
870
        /* read the data */
871
    read_loop:
872
        len = recv(c->fd, c->buffer_ptr, 1, 0);
873
        if (len < 0) {
874
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
875
                ff_neterrno() != FF_NETERROR(EINTR))
876
                return -1;
877
        } else if (len == 0) {
878
            return -1;
879
        } else {
880
            /* search for end of request. */
881
            uint8_t *ptr;
882
            c->buffer_ptr += len;
883
            ptr = c->buffer_ptr;
884
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
885
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
886
                /* request found : parse it and reply */
887
                if (c->state == HTTPSTATE_WAIT_REQUEST) {
888
                    ret = http_parse_request(c);
889
                } else {
890
                    ret = rtsp_parse_request(c);
891
                }
892
                if (ret < 0)
893
                    return -1;
894
            } else if (ptr >= c->buffer_end) {
895
                /* request too long: cannot do anything */
896
                return -1;
897
            } else goto read_loop;
898
        }
899
        break;
900

    
901
    case HTTPSTATE_SEND_HEADER:
902
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
903
            return -1;
904

    
905
        /* no need to write if no events */
906
        if (!(c->poll_entry->revents & POLLOUT))
907
            return 0;
908
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
909
        if (len < 0) {
910
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
911
                ff_neterrno() != FF_NETERROR(EINTR)) {
912
                /* error : close connection */
913
                av_freep(&c->pb_buffer);
914
                return -1;
915
            }
916
        } else {
917
            c->buffer_ptr += len;
918
            if (c->stream)
919
                c->stream->bytes_served += len;
920
            c->data_count += len;
921
            if (c->buffer_ptr >= c->buffer_end) {
922
                av_freep(&c->pb_buffer);
923
                /* if error, exit */
924
                if (c->http_error)
925
                    return -1;
926
                /* all the buffer was sent : synchronize to the incoming stream */
927
                c->state = HTTPSTATE_SEND_DATA_HEADER;
928
                c->buffer_ptr = c->buffer_end = c->buffer;
929
            }
930
        }
931
        break;
932

    
933
    case HTTPSTATE_SEND_DATA:
934
    case HTTPSTATE_SEND_DATA_HEADER:
935
    case HTTPSTATE_SEND_DATA_TRAILER:
936
        /* for packetized output, we consider we can always write (the
937
           input streams sets the speed). It may be better to verify
938
           that we do not rely too much on the kernel queues */
939
        if (!c->is_packetized) {
940
            if (c->poll_entry->revents & (POLLERR | POLLHUP))
941
                return -1;
942

    
943
            /* no need to read if no events */
944
            if (!(c->poll_entry->revents & POLLOUT))
945
                return 0;
946
        }
947
        if (http_send_data(c) < 0)
948
            return -1;
949
        /* close connection if trailer sent */
950
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
951
            return -1;
952
        break;
953
    case HTTPSTATE_RECEIVE_DATA:
954
        /* no need to read if no events */
955
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
956
            return -1;
957
        if (!(c->poll_entry->revents & POLLIN))
958
            return 0;
959
        if (http_receive_data(c) < 0)
960
            return -1;
961
        break;
962
    case HTTPSTATE_WAIT_FEED:
963
        /* no need to read if no events */
964
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
965
            return -1;
966

    
967
        /* nothing to do, we'll be waken up by incoming feed packets */
968
        break;
969

    
970
    case RTSPSTATE_SEND_REPLY:
971
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
972
            av_freep(&c->pb_buffer);
973
            return -1;
974
        }
975
        /* no need to write if no events */
976
        if (!(c->poll_entry->revents & POLLOUT))
977
            return 0;
978
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
979
        if (len < 0) {
980
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
981
                ff_neterrno() != FF_NETERROR(EINTR)) {
982
                /* error : close connection */
983
                av_freep(&c->pb_buffer);
984
                return -1;
985
            }
986
        } else {
987
            c->buffer_ptr += len;
988
            c->data_count += len;
989
            if (c->buffer_ptr >= c->buffer_end) {
990
                /* all the buffer was sent : wait for a new request */
991
                av_freep(&c->pb_buffer);
992
                start_wait_request(c, 1);
993
            }
994
        }
995
        break;
996
    case RTSPSTATE_SEND_PACKET:
997
        if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
998
            av_freep(&c->packet_buffer);
999
            return -1;
1000
        }
1001
        /* no need to write if no events */
1002
        if (!(c->poll_entry->revents & POLLOUT))
1003
            return 0;
1004
        len = send(c->fd, c->packet_buffer_ptr,
1005
                    c->packet_buffer_end - c->packet_buffer_ptr, 0);
1006
        if (len < 0) {
1007
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
1008
                ff_neterrno() != FF_NETERROR(EINTR)) {
1009
                /* error : close connection */
1010
                av_freep(&c->packet_buffer);
1011
                return -1;
1012
            }
1013
        } else {
1014
            c->packet_buffer_ptr += len;
1015
            if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1016
                /* all the buffer was sent : wait for a new request */
1017
                av_freep(&c->packet_buffer);
1018
                c->state = RTSPSTATE_WAIT_REQUEST;
1019
            }
1020
        }
1021
        break;
1022
    case HTTPSTATE_READY:
1023
        /* nothing to do */
1024
        break;
1025
    default:
1026
        return -1;
1027
    }
1028
    return 0;
1029
}
1030

    
1031
static int extract_rates(char *rates, int ratelen, const char *request)
1032
{
1033
    const char *p;
1034

    
1035
    for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1036
        if (strncasecmp(p, "Pragma:", 7) == 0) {
1037
            const char *q = p + 7;
1038

    
1039
            while (*q && *q != '\n' && isspace(*q))
1040
                q++;
1041

    
1042
            if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1043
                int stream_no;
1044
                int rate_no;
1045

    
1046
                q += 20;
1047

    
1048
                memset(rates, 0xff, ratelen);
1049

    
1050
                while (1) {
1051
                    while (*q && *q != '\n' && *q != ':')
1052
                        q++;
1053

    
1054
                    if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1055
                        break;
1056

    
1057
                    stream_no--;
1058
                    if (stream_no < ratelen && stream_no >= 0)
1059
                        rates[stream_no] = rate_no;
1060

    
1061
                    while (*q && *q != '\n' && !isspace(*q))
1062
                        q++;
1063
                }
1064

    
1065
                return 1;
1066
            }
1067
        }
1068
        p = strchr(p, '\n');
1069
        if (!p)
1070
            break;
1071

    
1072
        p++;
1073
    }
1074

    
1075
    return 0;
1076
}
1077

    
1078
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1079
{
1080
    int i;
1081
    int best_bitrate = 100000000;
1082
    int best = -1;
1083

    
1084
    for (i = 0; i < feed->nb_streams; i++) {
1085
        AVCodecContext *feed_codec = feed->streams[i]->codec;
1086

    
1087
        if (feed_codec->codec_id != codec->codec_id ||
1088
            feed_codec->sample_rate != codec->sample_rate ||
1089
            feed_codec->width != codec->width ||
1090
            feed_codec->height != codec->height)
1091
            continue;
1092

    
1093
        /* Potential stream */
1094

    
1095
        /* We want the fastest stream less than bit_rate, or the slowest
1096
         * faster than bit_rate
1097
         */
1098

    
1099
        if (feed_codec->bit_rate <= bit_rate) {
1100
            if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1101
                best_bitrate = feed_codec->bit_rate;
1102
                best = i;
1103
            }
1104
        } else {
1105
            if (feed_codec->bit_rate < best_bitrate) {
1106
                best_bitrate = feed_codec->bit_rate;
1107
                best = i;
1108
            }
1109
        }
1110
    }
1111

    
1112
    return best;
1113
}
1114

    
1115
static int modify_current_stream(HTTPContext *c, char *rates)
1116
{
1117
    int i;
1118
    FFStream *req = c->stream;
1119
    int action_required = 0;
1120

    
1121
    /* Not much we can do for a feed */
1122
    if (!req->feed)
1123
        return 0;
1124

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

    
1128
        switch(rates[i]) {
1129
            case 0:
1130
                c->switch_feed_streams[i] = req->feed_streams[i];
1131
                break;
1132
            case 1:
1133
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1134
                break;
1135
            case 2:
1136
                /* Wants off or slow */
1137
                c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1138
#ifdef WANTS_OFF
1139
                /* This doesn't work well when it turns off the only stream! */
1140
                c->switch_feed_streams[i] = -2;
1141
                c->feed_streams[i] = -2;
1142
#endif
1143
                break;
1144
        }
1145

    
1146
        if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1147
            action_required = 1;
1148
    }
1149

    
1150
    return action_required;
1151
}
1152

    
1153

    
1154
static void do_switch_stream(HTTPContext *c, int i)
1155
{
1156
    if (c->switch_feed_streams[i] >= 0) {
1157
#ifdef PHILIP
1158
        c->feed_streams[i] = c->switch_feed_streams[i];
1159
#endif
1160

    
1161
        /* Now update the stream */
1162
    }
1163
    c->switch_feed_streams[i] = -1;
1164
}
1165

    
1166
/* XXX: factorize in utils.c ? */
1167
/* XXX: take care with different space meaning */
1168
static void skip_spaces(const char **pp)
1169
{
1170
    const char *p;
1171
    p = *pp;
1172
    while (*p == ' ' || *p == '\t')
1173
        p++;
1174
    *pp = p;
1175
}
1176

    
1177
static void get_word(char *buf, int buf_size, const char **pp)
1178
{
1179
    const char *p;
1180
    char *q;
1181

    
1182
    p = *pp;
1183
    skip_spaces(&p);
1184
    q = buf;
1185
    while (!isspace(*p) && *p != '\0') {
1186
        if ((q - buf) < buf_size - 1)
1187
            *q++ = *p;
1188
        p++;
1189
    }
1190
    if (buf_size > 0)
1191
        *q = '\0';
1192
    *pp = p;
1193
}
1194

    
1195
static void get_arg(char *buf, int buf_size, const char **pp)
1196
{
1197
    const char *p;
1198
    char *q;
1199
    int quote;
1200

    
1201
    p = *pp;
1202
    while (isspace(*p)) p++;
1203
    q = buf;
1204
    quote = 0;
1205
    if (*p == '\"' || *p == '\'')
1206
        quote = *p++;
1207
    for(;;) {
1208
        if (quote) {
1209
            if (*p == quote)
1210
                break;
1211
        } else {
1212
            if (isspace(*p))
1213
                break;
1214
        }
1215
        if (*p == '\0')
1216
            break;
1217
        if ((q - buf) < buf_size - 1)
1218
            *q++ = *p;
1219
        p++;
1220
    }
1221
    *q = '\0';
1222
    if (quote && *p == quote)
1223
        p++;
1224
    *pp = p;
1225
}
1226

    
1227
static int validate_acl(FFStream *stream, HTTPContext *c)
1228
{
1229
    enum IPAddressAction last_action = IP_DENY;
1230
    IPAddressACL *acl;
1231
    struct in_addr *src = &c->from_addr.sin_addr;
1232
    unsigned long src_addr = src->s_addr;
1233

    
1234
    for (acl = stream->acl; acl; acl = acl->next) {
1235
        if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1236
            return (acl->action == IP_ALLOW) ? 1 : 0;
1237
        last_action = acl->action;
1238
    }
1239

    
1240
    /* Nothing matched, so return not the last action */
1241
    return (last_action == IP_DENY) ? 1 : 0;
1242
}
1243

    
1244
/* compute the real filename of a file by matching it without its
1245
   extensions to all the stream filenames */
1246
static void compute_real_filename(char *filename, int max_size)
1247
{
1248
    char file1[1024];
1249
    char file2[1024];
1250
    char *p;
1251
    FFStream *stream;
1252

    
1253
    /* compute filename by matching without the file extensions */
1254
    av_strlcpy(file1, filename, sizeof(file1));
1255
    p = strrchr(file1, '.');
1256
    if (p)
1257
        *p = '\0';
1258
    for(stream = first_stream; stream != NULL; stream = stream->next) {
1259
        av_strlcpy(file2, stream->filename, sizeof(file2));
1260
        p = strrchr(file2, '.');
1261
        if (p)
1262
            *p = '\0';
1263
        if (!strcmp(file1, file2)) {
1264
            av_strlcpy(filename, stream->filename, max_size);
1265
            break;
1266
        }
1267
    }
1268
}
1269

    
1270
enum RedirType {
1271
    REDIR_NONE,
1272
    REDIR_ASX,
1273
    REDIR_RAM,
1274
    REDIR_ASF,
1275
    REDIR_RTSP,
1276
    REDIR_SDP,
1277
};
1278

    
1279
/* parse http request and prepare header */
1280
static int http_parse_request(HTTPContext *c)
1281
{
1282
    char *p;
1283
    enum RedirType redir_type;
1284
    char cmd[32];
1285
    char info[1024], filename[1024];
1286
    char url[1024], *q;
1287
    char protocol[32];
1288
    char msg[1024];
1289
    const char *mime_type;
1290
    FFStream *stream;
1291
    int i;
1292
    char ratebuf[32];
1293
    char *useragent = 0;
1294

    
1295
    p = c->buffer;
1296
    get_word(cmd, sizeof(cmd), (const char **)&p);
1297
    av_strlcpy(c->method, cmd, sizeof(c->method));
1298

    
1299
    if (!strcmp(cmd, "GET"))
1300
        c->post = 0;
1301
    else if (!strcmp(cmd, "POST"))
1302
        c->post = 1;
1303
    else
1304
        return -1;
1305

    
1306
    get_word(url, sizeof(url), (const char **)&p);
1307
    av_strlcpy(c->url, url, sizeof(c->url));
1308

    
1309
    get_word(protocol, sizeof(protocol), (const char **)&p);
1310
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1311
        return -1;
1312

    
1313
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1314

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

    
1318
    /* find the filename and the optional info string in the request */
1319
    p = strchr(url, '?');
1320
    if (p) {
1321
        av_strlcpy(info, p, sizeof(info));
1322
        *p = '\0';
1323
    } else
1324
        info[0] = '\0';
1325

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

    
1328
    for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1329
        if (strncasecmp(p, "User-Agent:", 11) == 0) {
1330
            useragent = p + 11;
1331
            if (*useragent && *useragent != '\n' && isspace(*useragent))
1332
                useragent++;
1333
            break;
1334
        }
1335
        p = strchr(p, '\n');
1336
        if (!p)
1337
            break;
1338

    
1339
        p++;
1340
    }
1341

    
1342
    redir_type = REDIR_NONE;
1343
    if (match_ext(filename, "asx")) {
1344
        redir_type = REDIR_ASX;
1345
        filename[strlen(filename)-1] = 'f';
1346
    } else if (match_ext(filename, "asf") &&
1347
        (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1348
        /* if this isn't WMP or lookalike, return the redirector file */
1349
        redir_type = REDIR_ASF;
1350
    } else if (match_ext(filename, "rpm,ram")) {
1351
        redir_type = REDIR_RAM;
1352
        strcpy(filename + strlen(filename)-2, "m");
1353
    } else if (match_ext(filename, "rtsp")) {
1354
        redir_type = REDIR_RTSP;
1355
        compute_real_filename(filename, sizeof(filename) - 1);
1356
    } else if (match_ext(filename, "sdp")) {
1357
        redir_type = REDIR_SDP;
1358
        compute_real_filename(filename, sizeof(filename) - 1);
1359
    }
1360

    
1361
    // "redirect" / request to index.html
1362
    if (!strlen(filename))
1363
        av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1364

    
1365
    stream = first_stream;
1366
    while (stream != NULL) {
1367
        if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1368
            break;
1369
        stream = stream->next;
1370
    }
1371
    if (stream == NULL) {
1372
        snprintf(msg, sizeof(msg), "File '%s' not found", url);
1373
        http_log("File '%s' not found\n", url);
1374
        goto send_error;
1375
    }
1376

    
1377
    c->stream = stream;
1378
    memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1379
    memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1380

    
1381
    if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1382
        c->http_error = 301;
1383
        q = c->buffer;
1384
        q += snprintf(q, c->buffer_size,
1385
                      "HTTP/1.0 301 Moved\r\n"
1386
                      "Location: %s\r\n"
1387
                      "Content-type: text/html\r\n"
1388
                      "\r\n"
1389
                      "<html><head><title>Moved</title></head><body>\r\n"
1390
                      "You should be <a href=\"%s\">redirected</a>.\r\n"
1391
                      "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1392
        /* prepare output buffer */
1393
        c->buffer_ptr = c->buffer;
1394
        c->buffer_end = q;
1395
        c->state = HTTPSTATE_SEND_HEADER;
1396
        return 0;
1397
    }
1398

    
1399
    /* If this is WMP, get the rate information */
1400
    if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1401
        if (modify_current_stream(c, ratebuf)) {
1402
            for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1403
                if (c->switch_feed_streams[i] >= 0)
1404
                    do_switch_stream(c, i);
1405
            }
1406
        }
1407
    }
1408

    
1409
    if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1410
        current_bandwidth += stream->bandwidth;
1411

    
1412
    /* If already streaming this feed, do not let start another feeder. */
1413
    if (stream->feed_opened) {
1414
        snprintf(msg, sizeof(msg), "This feed is already being received.");
1415
        http_log("Feed '%s' already being received\n", stream->feed_filename);
1416
        goto send_error;
1417
    }
1418

    
1419
    if (c->post == 0 && max_bandwidth < current_bandwidth) {
1420
        c->http_error = 200;
1421
        q = c->buffer;
1422
        q += snprintf(q, c->buffer_size,
1423
                      "HTTP/1.0 200 Server too busy\r\n"
1424
                      "Content-type: text/html\r\n"
1425
                      "\r\n"
1426
                      "<html><head><title>Too busy</title></head><body>\r\n"
1427
                      "<p>The server is too busy to serve your request at this time.</p>\r\n"
1428
                      "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1429
                      "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1430
                      "</body></html>\r\n", current_bandwidth, max_bandwidth);
1431
        /* prepare output buffer */
1432
        c->buffer_ptr = c->buffer;
1433
        c->buffer_end = q;
1434
        c->state = HTTPSTATE_SEND_HEADER;
1435
        return 0;
1436
    }
1437

    
1438
    if (redir_type != REDIR_NONE) {
1439
        char *hostinfo = 0;
1440

    
1441
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1442
            if (strncasecmp(p, "Host:", 5) == 0) {
1443
                hostinfo = p + 5;
1444
                break;
1445
            }
1446
            p = strchr(p, '\n');
1447
            if (!p)
1448
                break;
1449

    
1450
            p++;
1451
        }
1452

    
1453
        if (hostinfo) {
1454
            char *eoh;
1455
            char hostbuf[260];
1456

    
1457
            while (isspace(*hostinfo))
1458
                hostinfo++;
1459

    
1460
            eoh = strchr(hostinfo, '\n');
1461
            if (eoh) {
1462
                if (eoh[-1] == '\r')
1463
                    eoh--;
1464

    
1465
                if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1466
                    memcpy(hostbuf, hostinfo, eoh - hostinfo);
1467
                    hostbuf[eoh - hostinfo] = 0;
1468

    
1469
                    c->http_error = 200;
1470
                    q = c->buffer;
1471
                    switch(redir_type) {
1472
                    case REDIR_ASX:
1473
                        q += snprintf(q, c->buffer_size,
1474
                                      "HTTP/1.0 200 ASX Follows\r\n"
1475
                                      "Content-type: video/x-ms-asf\r\n"
1476
                                      "\r\n"
1477
                                      "<ASX Version=\"3\">\r\n"
1478
                                      //"<!-- Autogenerated by ffserver -->\r\n"
1479
                                      "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1480
                                      "</ASX>\r\n", hostbuf, filename, info);
1481
                        break;
1482
                    case REDIR_RAM:
1483
                        q += snprintf(q, c->buffer_size,
1484
                                      "HTTP/1.0 200 RAM Follows\r\n"
1485
                                      "Content-type: audio/x-pn-realaudio\r\n"
1486
                                      "\r\n"
1487
                                      "# Autogenerated by ffserver\r\n"
1488
                                      "http://%s/%s%s\r\n", hostbuf, filename, info);
1489
                        break;
1490
                    case REDIR_ASF:
1491
                        q += snprintf(q, c->buffer_size,
1492
                                      "HTTP/1.0 200 ASF Redirect follows\r\n"
1493
                                      "Content-type: video/x-ms-asf\r\n"
1494
                                      "\r\n"
1495
                                      "[Reference]\r\n"
1496
                                      "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1497
                        break;
1498
                    case REDIR_RTSP:
1499
                        {
1500
                            char hostname[256], *p;
1501
                            /* extract only hostname */
1502
                            av_strlcpy(hostname, hostbuf, sizeof(hostname));
1503
                            p = strrchr(hostname, ':');
1504
                            if (p)
1505
                                *p = '\0';
1506
                            q += snprintf(q, c->buffer_size,
1507
                                          "HTTP/1.0 200 RTSP Redirect follows\r\n"
1508
                                          /* XXX: incorrect mime type ? */
1509
                                          "Content-type: application/x-rtsp\r\n"
1510
                                          "\r\n"
1511
                                          "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1512
                        }
1513
                        break;
1514
                    case REDIR_SDP:
1515
                        {
1516
                            uint8_t *sdp_data;
1517
                            int sdp_data_size, len;
1518
                            struct sockaddr_in my_addr;
1519

    
1520
                            q += snprintf(q, c->buffer_size,
1521
                                          "HTTP/1.0 200 OK\r\n"
1522
                                          "Content-type: application/sdp\r\n"
1523
                                          "\r\n");
1524

    
1525
                            len = sizeof(my_addr);
1526
                            getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1527

    
1528
                            /* XXX: should use a dynamic buffer */
1529
                            sdp_data_size = prepare_sdp_description(stream,
1530
                                                                    &sdp_data,
1531
                                                                    my_addr.sin_addr);
1532
                            if (sdp_data_size > 0) {
1533
                                memcpy(q, sdp_data, sdp_data_size);
1534
                                q += sdp_data_size;
1535
                                *q = '\0';
1536
                                av_free(sdp_data);
1537
                            }
1538
                        }
1539
                        break;
1540
                    default:
1541
                        abort();
1542
                        break;
1543
                    }
1544

    
1545
                    /* prepare output buffer */
1546
                    c->buffer_ptr = c->buffer;
1547
                    c->buffer_end = q;
1548
                    c->state = HTTPSTATE_SEND_HEADER;
1549
                    return 0;
1550
                }
1551
            }
1552
        }
1553

    
1554
        snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1555
        goto send_error;
1556
    }
1557

    
1558
    stream->conns_served++;
1559

    
1560
    /* XXX: add there authenticate and IP match */
1561

    
1562
    if (c->post) {
1563
        /* if post, it means a feed is being sent */
1564
        if (!stream->is_feed) {
1565
            /* However it might be a status report from WMP! Let us log the
1566
             * data as it might come in handy one day. */
1567
            char *logline = 0;
1568
            int client_id = 0;
1569

    
1570
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1571
                if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1572
                    logline = p;
1573
                    break;
1574
                }
1575
                if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1576
                    client_id = strtol(p + 18, 0, 10);
1577
                p = strchr(p, '\n');
1578
                if (!p)
1579
                    break;
1580

    
1581
                p++;
1582
            }
1583

    
1584
            if (logline) {
1585
                char *eol = strchr(logline, '\n');
1586

    
1587
                logline += 17;
1588

    
1589
                if (eol) {
1590
                    if (eol[-1] == '\r')
1591
                        eol--;
1592
                    http_log("%.*s\n", (int) (eol - logline), logline);
1593
                    c->suppress_log = 1;
1594
                }
1595
            }
1596

    
1597
#ifdef DEBUG_WMP
1598
            http_log("\nGot request:\n%s\n", c->buffer);
1599
#endif
1600

    
1601
            if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1602
                HTTPContext *wmpc;
1603

    
1604
                /* Now we have to find the client_id */
1605
                for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1606
                    if (wmpc->wmp_client_id == client_id)
1607
                        break;
1608
                }
1609

    
1610
                if (wmpc && modify_current_stream(wmpc, ratebuf))
1611
                    wmpc->switch_pending = 1;
1612
            }
1613

    
1614
            snprintf(msg, sizeof(msg), "POST command not handled");
1615
            c->stream = 0;
1616
            goto send_error;
1617
        }
1618
        if (http_start_receive_data(c) < 0) {
1619
            snprintf(msg, sizeof(msg), "could not open feed");
1620
            goto send_error;
1621
        }
1622
        c->http_error = 0;
1623
        c->state = HTTPSTATE_RECEIVE_DATA;
1624
        return 0;
1625
    }
1626

    
1627
#ifdef DEBUG_WMP
1628
    if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1629
        http_log("\nGot request:\n%s\n", c->buffer);
1630
#endif
1631

    
1632
    if (c->stream->stream_type == STREAM_TYPE_STATUS)
1633
        goto send_status;
1634

    
1635
    /* open input stream */
1636
    if (open_input_stream(c, info) < 0) {
1637
        snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1638
        goto send_error;
1639
    }
1640

    
1641
    /* prepare http header */
1642
    q = c->buffer;
1643
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1644
    mime_type = c->stream->fmt->mime_type;
1645
    if (!mime_type)
1646
        mime_type = "application/x-octet-stream";
1647
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1648

    
1649
    /* for asf, we need extra headers */
1650
    if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1651
        /* Need to allocate a client id */
1652

    
1653
        c->wmp_client_id = av_lfg_get(&random_state);
1654

    
1655
        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);
1656
    }
1657
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1658
    q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1659

    
1660
    /* prepare output buffer */
1661
    c->http_error = 0;
1662
    c->buffer_ptr = c->buffer;
1663
    c->buffer_end = q;
1664
    c->state = HTTPSTATE_SEND_HEADER;
1665
    return 0;
1666
 send_error:
1667
    c->http_error = 404;
1668
    q = c->buffer;
1669
    q += snprintf(q, c->buffer_size,
1670
                  "HTTP/1.0 404 Not Found\r\n"
1671
                  "Content-type: text/html\r\n"
1672
                  "\r\n"
1673
                  "<html>\n"
1674
                  "<head><title>404 Not Found</title></head>\n"
1675
                  "<body>%s</body>\n"
1676
                  "</html>\n", msg);
1677
    /* prepare output buffer */
1678
    c->buffer_ptr = c->buffer;
1679
    c->buffer_end = q;
1680
    c->state = HTTPSTATE_SEND_HEADER;
1681
    return 0;
1682
 send_status:
1683
    compute_status(c);
1684
    c->http_error = 200; /* horrible : we use this value to avoid
1685
                            going to the send data state */
1686
    c->state = HTTPSTATE_SEND_HEADER;
1687
    return 0;
1688
}
1689

    
1690
static void fmt_bytecount(ByteIOContext *pb, int64_t count)
1691
{
1692
    static const char *suffix = " kMGTP";
1693
    const char *s;
1694

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

    
1697
    url_fprintf(pb, "%"PRId64"%c", count, *s);
1698
}
1699

    
1700
static void compute_status(HTTPContext *c)
1701
{
1702
    HTTPContext *c1;
1703
    FFStream *stream;
1704
    char *p;
1705
    time_t ti;
1706
    int i, len;
1707
    ByteIOContext *pb;
1708

    
1709
    if (url_open_dyn_buf(&pb) < 0) {
1710
        /* XXX: return an error ? */
1711
        c->buffer_ptr = c->buffer;
1712
        c->buffer_end = c->buffer;
1713
        return;
1714
    }
1715

    
1716
    url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1717
    url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1718
    url_fprintf(pb, "Pragma: no-cache\r\n");
1719
    url_fprintf(pb, "\r\n");
1720

    
1721
    url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
1722
    if (c->stream->feed_filename[0])
1723
        url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1724
    url_fprintf(pb, "</head>\n<body>");
1725
    url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
1726
    /* format status */
1727
    url_fprintf(pb, "<h2>Available Streams</h2>\n");
1728
    url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
1729
    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");
1730
    stream = first_stream;
1731
    while (stream != NULL) {
1732
        char sfilename[1024];
1733
        char *eosf;
1734

    
1735
        if (stream->feed != stream) {
1736
            av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1737
            eosf = sfilename + strlen(sfilename);
1738
            if (eosf - sfilename >= 4) {
1739
                if (strcmp(eosf - 4, ".asf") == 0)
1740
                    strcpy(eosf - 4, ".asx");
1741
                else if (strcmp(eosf - 3, ".rm") == 0)
1742
                    strcpy(eosf - 3, ".ram");
1743
                else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1744
                    /* generate a sample RTSP director if
1745
                       unicast. Generate an SDP redirector if
1746
                       multicast */
1747
                    eosf = strrchr(sfilename, '.');
1748
                    if (!eosf)
1749
                        eosf = sfilename + strlen(sfilename);
1750
                    if (stream->is_multicast)
1751
                        strcpy(eosf, ".sdp");
1752
                    else
1753
                        strcpy(eosf, ".rtsp");
1754
                }
1755
            }
1756

    
1757
            url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1758
                         sfilename, stream->filename);
1759
            url_fprintf(pb, "<td align=right> %d <td align=right> ",
1760
                        stream->conns_served);
1761
            fmt_bytecount(pb, stream->bytes_served);
1762
            switch(stream->stream_type) {
1763
            case STREAM_TYPE_LIVE: {
1764
                    int audio_bit_rate = 0;
1765
                    int video_bit_rate = 0;
1766
                    const char *audio_codec_name = "";
1767
                    const char *video_codec_name = "";
1768
                    const char *audio_codec_name_extra = "";
1769
                    const char *video_codec_name_extra = "";
1770

    
1771
                    for(i=0;i<stream->nb_streams;i++) {
1772
                        AVStream *st = stream->streams[i];
1773
                        AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1774
                        switch(st->codec->codec_type) {
1775
                        case CODEC_TYPE_AUDIO:
1776
                            audio_bit_rate += st->codec->bit_rate;
1777
                            if (codec) {
1778
                                if (*audio_codec_name)
1779
                                    audio_codec_name_extra = "...";
1780
                                audio_codec_name = codec->name;
1781
                            }
1782
                            break;
1783
                        case CODEC_TYPE_VIDEO:
1784
                            video_bit_rate += st->codec->bit_rate;
1785
                            if (codec) {
1786
                                if (*video_codec_name)
1787
                                    video_codec_name_extra = "...";
1788
                                video_codec_name = codec->name;
1789
                            }
1790
                            break;
1791
                        case CODEC_TYPE_DATA:
1792
                            video_bit_rate += st->codec->bit_rate;
1793
                            break;
1794
                        default:
1795
                            abort();
1796
                        }
1797
                    }
1798
                    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",
1799
                                 stream->fmt->name,
1800
                                 stream->bandwidth,
1801
                                 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1802
                                 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1803
                    if (stream->feed)
1804
                        url_fprintf(pb, "<td>%s", stream->feed->filename);
1805
                    else
1806
                        url_fprintf(pb, "<td>%s", stream->feed_filename);
1807
                    url_fprintf(pb, "\n");
1808
                }
1809
                break;
1810
            default:
1811
                url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1812
                break;
1813
            }
1814
        }
1815
        stream = stream->next;
1816
    }
1817
    url_fprintf(pb, "</table>\n");
1818

    
1819
    stream = first_stream;
1820
    while (stream != NULL) {
1821
        if (stream->feed == stream) {
1822
            url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
1823
            if (stream->pid) {
1824
                url_fprintf(pb, "Running as pid %d.\n", stream->pid);
1825

    
1826
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1827
                {
1828
                    FILE *pid_stat;
1829
                    char ps_cmd[64];
1830

    
1831
                    /* This is somewhat linux specific I guess */
1832
                    snprintf(ps_cmd, sizeof(ps_cmd),
1833
                             "ps -o \"%%cpu,cputime\" --no-headers %d",
1834
                             stream->pid);
1835

    
1836
                    pid_stat = popen(ps_cmd, "r");
1837
                    if (pid_stat) {
1838
                        char cpuperc[10];
1839
                        char cpuused[64];
1840

    
1841
                        if (fscanf(pid_stat, "%10s %64s", cpuperc,
1842
                                   cpuused) == 2) {
1843
                            url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1844
                                         cpuperc, cpuused);
1845
                        }
1846
                        fclose(pid_stat);
1847
                    }
1848
                }
1849
#endif
1850

    
1851
                url_fprintf(pb, "<p>");
1852
            }
1853
            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");
1854

    
1855
            for (i = 0; i < stream->nb_streams; i++) {
1856
                AVStream *st = stream->streams[i];
1857
                AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1858
                const char *type = "unknown";
1859
                char parameters[64];
1860

    
1861
                parameters[0] = 0;
1862

    
1863
                switch(st->codec->codec_type) {
1864
                case CODEC_TYPE_AUDIO:
1865
                    type = "audio";
1866
                    snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1867
                    break;
1868
                case CODEC_TYPE_VIDEO:
1869
                    type = "video";
1870
                    snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1871
                                st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1872
                    break;
1873
                default:
1874
                    abort();
1875
                }
1876
                url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1877
                        i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1878
            }
1879
            url_fprintf(pb, "</table>\n");
1880

    
1881
        }
1882
        stream = stream->next;
1883
    }
1884

    
1885
    /* connection status */
1886
    url_fprintf(pb, "<h2>Connection Status</h2>\n");
1887

    
1888
    url_fprintf(pb, "Number of connections: %d / %d<br>\n",
1889
                 nb_connections, nb_max_connections);
1890

    
1891
    url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1892
                 current_bandwidth, max_bandwidth);
1893

    
1894
    url_fprintf(pb, "<table>\n");
1895
    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");
1896
    c1 = first_http_ctx;
1897
    i = 0;
1898
    while (c1 != NULL) {
1899
        int bitrate;
1900
        int j;
1901

    
1902
        bitrate = 0;
1903
        if (c1->stream) {
1904
            for (j = 0; j < c1->stream->nb_streams; j++) {
1905
                if (!c1->stream->feed)
1906
                    bitrate += c1->stream->streams[j]->codec->bit_rate;
1907
                else if (c1->feed_streams[j] >= 0)
1908
                    bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1909
            }
1910
        }
1911

    
1912
        i++;
1913
        p = inet_ntoa(c1->from_addr.sin_addr);
1914
        url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1915
                    i,
1916
                    c1->stream ? c1->stream->filename : "",
1917
                    c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1918
                    p,
1919
                    c1->protocol,
1920
                    http_state[c1->state]);
1921
        fmt_bytecount(pb, bitrate);
1922
        url_fprintf(pb, "<td align=right>");
1923
        fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1924
        url_fprintf(pb, "<td align=right>");
1925
        fmt_bytecount(pb, c1->data_count);
1926
        url_fprintf(pb, "\n");
1927
        c1 = c1->next;
1928
    }
1929
    url_fprintf(pb, "</table>\n");
1930

    
1931
    /* date */
1932
    ti = time(NULL);
1933
    p = ctime(&ti);
1934
    url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
1935
    url_fprintf(pb, "</body>\n</html>\n");
1936

    
1937
    len = url_close_dyn_buf(pb, &c->pb_buffer);
1938
    c->buffer_ptr = c->pb_buffer;
1939
    c->buffer_end = c->pb_buffer + len;
1940
}
1941

    
1942
/* check if the parser needs to be opened for stream i */
1943
static void open_parser(AVFormatContext *s, int i)
1944
{
1945
    AVStream *st = s->streams[i];
1946
    AVCodec *codec;
1947

    
1948
    if (!st->codec->codec) {
1949
        codec = avcodec_find_decoder(st->codec->codec_id);
1950
        if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
1951
            st->codec->parse_only = 1;
1952
            if (avcodec_open(st->codec, codec) < 0)
1953
                st->codec->parse_only = 0;
1954
        }
1955
    }
1956
}
1957

    
1958
static int open_input_stream(HTTPContext *c, const char *info)
1959
{
1960
    char buf[128];
1961
    char input_filename[1024];
1962
    AVFormatContext *s;
1963
    int buf_size, i, ret;
1964
    int64_t stream_pos;
1965

    
1966
    /* find file name */
1967
    if (c->stream->feed) {
1968
        strcpy(input_filename, c->stream->feed->feed_filename);
1969
        buf_size = FFM_PACKET_SIZE;
1970
        /* compute position (absolute time) */
1971
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1972
            stream_pos = parse_date(buf, 0);
1973
            if (stream_pos == INT64_MIN)
1974
                return -1;
1975
        } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
1976
            int prebuffer = strtol(buf, 0, 10);
1977
            stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1978
        } else
1979
            stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1980
    } else {
1981
        strcpy(input_filename, c->stream->feed_filename);
1982
        buf_size = 0;
1983
        /* compute position (relative time) */
1984
        if (find_info_tag(buf, sizeof(buf), "date", info)) {
1985
            stream_pos = parse_date(buf, 1);
1986
            if (stream_pos == INT64_MIN)
1987
                return -1;
1988
        } else
1989
            stream_pos = 0;
1990
    }
1991
    if (input_filename[0] == '\0')
1992
        return -1;
1993

    
1994
    /* open stream */
1995
    if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1996
                                  buf_size, c->stream->ap_in)) < 0) {
1997
        http_log("could not open %s: %d\n", input_filename, ret);
1998
        return -1;
1999
    }
2000
    s->flags |= AVFMT_FLAG_GENPTS;
2001
    c->fmt_in = s;
2002
    if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2003
        http_log("Could not find stream info '%s'\n", input_filename);
2004
        av_close_input_file(s);
2005
        return -1;
2006
    }
2007

    
2008
    /* open each parser */
2009
    for(i=0;i<s->nb_streams;i++)
2010
        open_parser(s, i);
2011

    
2012
    /* choose stream as clock source (we favorize video stream if
2013
       present) for packet sending */
2014
    c->pts_stream_index = 0;
2015
    for(i=0;i<c->stream->nb_streams;i++) {
2016
        if (c->pts_stream_index == 0 &&
2017
            c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2018
            c->pts_stream_index = i;
2019
        }
2020
    }
2021

    
2022
#if 1
2023
    if (c->fmt_in->iformat->read_seek)
2024
        av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2025
#endif
2026
    /* set the start time (needed for maxtime and RTP packet timing) */
2027
    c->start_time = cur_time;
2028
    c->first_pts = AV_NOPTS_VALUE;
2029
    return 0;
2030
}
2031

    
2032
/* return the server clock (in us) */
2033
static int64_t get_server_clock(HTTPContext *c)
2034
{
2035
    /* compute current pts value from system time */
2036
    return (cur_time - c->start_time) * 1000;
2037
}
2038

    
2039
/* return the estimated time at which the current packet must be sent
2040
   (in us) */
2041
static int64_t get_packet_send_clock(HTTPContext *c)
2042
{
2043
    int bytes_left, bytes_sent, frame_bytes;
2044

    
2045
    frame_bytes = c->cur_frame_bytes;
2046
    if (frame_bytes <= 0)
2047
        return c->cur_pts;
2048
    else {
2049
        bytes_left = c->buffer_end - c->buffer_ptr;
2050
        bytes_sent = frame_bytes - bytes_left;
2051
        return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2052
    }
2053
}
2054

    
2055

    
2056
static int http_prepare_data(HTTPContext *c)
2057
{
2058
    int i, len, ret;
2059
    AVFormatContext *ctx;
2060

    
2061
    av_freep(&c->pb_buffer);
2062
    switch(c->state) {
2063
    case HTTPSTATE_SEND_DATA_HEADER:
2064
        memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2065
        av_metadata_set(&c->fmt_ctx.metadata, "author"   ,c->stream->author);
2066
        av_metadata_set(&c->fmt_ctx.metadata, "comment"  ,c->stream->comment);
2067
        av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
2068
        av_metadata_set(&c->fmt_ctx.metadata, "title"    ,c->stream->title);
2069

    
2070
        for(i=0;i<c->stream->nb_streams;i++) {
2071
            AVStream *st;
2072
            AVStream *src;
2073
            st = av_mallocz(sizeof(AVStream));
2074
            c->fmt_ctx.streams[i] = st;
2075
            /* if file or feed, then just take streams from FFStream struct */
2076
            if (!c->stream->feed ||
2077
                c->stream->feed == c->stream)
2078
                src = c->stream->streams[i];
2079
            else
2080
                src = c->stream->feed->streams[c->stream->feed_streams[i]];
2081

    
2082
            *st = *src;
2083
            st->priv_data = 0;
2084
            st->codec->frame_number = 0; /* XXX: should be done in
2085
                                           AVStream, not in codec */
2086
        }
2087
        /* set output format parameters */
2088
        c->fmt_ctx.oformat = c->stream->fmt;
2089
        c->fmt_ctx.nb_streams = c->stream->nb_streams;
2090

    
2091
        c->got_key_frame = 0;
2092

    
2093
        /* prepare header and save header data in a stream */
2094
        if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2095
            /* XXX: potential leak */
2096
            return -1;
2097
        }
2098
        c->fmt_ctx.pb->is_streamed = 1;
2099

    
2100
        /*
2101
         * HACK to avoid mpeg ps muxer to spit many underflow errors
2102
         * Default value from FFmpeg
2103
         * Try to set it use configuration option
2104
         */
2105
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2106
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2107

    
2108
        av_set_parameters(&c->fmt_ctx, NULL);
2109
        if (av_write_header(&c->fmt_ctx) < 0) {
2110
            http_log("Error writing output header\n");
2111
            return -1;
2112
        }
2113

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

    
2118
        c->state = HTTPSTATE_SEND_DATA;
2119
        c->last_packet_sent = 0;
2120
        break;
2121
    case HTTPSTATE_SEND_DATA:
2122
        /* find a new packet */
2123
        /* read a packet from the input stream */
2124
        if (c->stream->feed)
2125
            ffm_set_write_index(c->fmt_in,
2126
                                c->stream->feed->feed_write_index,
2127
                                c->stream->feed->feed_size);
2128

    
2129
        if (c->stream->max_time &&
2130
            c->stream->max_time + c->start_time - cur_time < 0)
2131
            /* We have timed out */
2132
            c->state = HTTPSTATE_SEND_DATA_TRAILER;
2133
        else {
2134
            AVPacket pkt;
2135
        redo:
2136
            if (av_read_frame(c->fmt_in, &pkt) < 0) {
2137
                if (c->stream->feed && c->stream->feed->feed_opened) {
2138
                    /* if coming from feed, it means we reached the end of the
2139
                       ffm file, so must wait for more data */
2140
                    c->state = HTTPSTATE_WAIT_FEED;
2141
                    return 1; /* state changed */
2142
                } else {
2143
                    if (c->stream->loop) {
2144
                        av_close_input_file(c->fmt_in);
2145
                        c->fmt_in = NULL;
2146
                        if (open_input_stream(c, "") < 0)
2147
                            goto no_loop;
2148
                        goto redo;
2149
                    } else {
2150
                    no_loop:
2151
                        /* must send trailer now because eof or error */
2152
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2153
                    }
2154
                }
2155
            } else {
2156
                int source_index = pkt.stream_index;
2157
                /* update first pts if needed */
2158
                if (c->first_pts == AV_NOPTS_VALUE) {
2159
                    c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2160
                    c->start_time = cur_time;
2161
                }
2162
                /* send it to the appropriate stream */
2163
                if (c->stream->feed) {
2164
                    /* if coming from a feed, select the right stream */
2165
                    if (c->switch_pending) {
2166
                        c->switch_pending = 0;
2167
                        for(i=0;i<c->stream->nb_streams;i++) {
2168
                            if (c->switch_feed_streams[i] == pkt.stream_index)
2169
                                if (pkt.flags & PKT_FLAG_KEY)
2170
                                    do_switch_stream(c, i);
2171
                            if (c->switch_feed_streams[i] >= 0)
2172
                                c->switch_pending = 1;
2173
                        }
2174
                    }
2175
                    for(i=0;i<c->stream->nb_streams;i++) {
2176
                        if (c->feed_streams[i] == pkt.stream_index) {
2177
                            AVStream *st = c->fmt_in->streams[source_index];
2178
                            pkt.stream_index = i;
2179
                            if (pkt.flags & PKT_FLAG_KEY &&
2180
                                (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2181
                                 c->stream->nb_streams == 1))
2182
                                c->got_key_frame = 1;
2183
                            if (!c->stream->send_on_key || c->got_key_frame)
2184
                                goto send_it;
2185
                        }
2186
                    }
2187
                } else {
2188
                    AVCodecContext *codec;
2189
                    AVStream *ist, *ost;
2190
                send_it:
2191
                    ist = c->fmt_in->streams[source_index];
2192
                    /* specific handling for RTP: we use several
2193
                       output stream (one for each RTP
2194
                       connection). XXX: need more abstract handling */
2195
                    if (c->is_packetized) {
2196
                        /* compute send time and duration */
2197
                        c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2198
                        if (ist->start_time != AV_NOPTS_VALUE)
2199
                            c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2200
                        c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2201
                        /* find RTP context */
2202
                        c->packet_stream_index = pkt.stream_index;
2203
                        ctx = c->rtp_ctx[c->packet_stream_index];
2204
                        if(!ctx) {
2205
                            av_free_packet(&pkt);
2206
                            break;
2207
                        }
2208
                        codec = ctx->streams[0]->codec;
2209
                        /* only one stream per RTP connection */
2210
                        pkt.stream_index = 0;
2211
                    } else {
2212
                        ctx = &c->fmt_ctx;
2213
                        /* Fudge here */
2214
                        codec = ctx->streams[pkt.stream_index]->codec;
2215
                    }
2216

    
2217
                    if (c->is_packetized) {
2218
                        int max_packet_size;
2219
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2220
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2221
                        else
2222
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2223
                        ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2224
                    } else {
2225
                        ret = url_open_dyn_buf(&ctx->pb);
2226
                    }
2227
                    if (ret < 0) {
2228
                        /* XXX: potential leak */
2229
                        return -1;
2230
                    }
2231
                    ost = ctx->streams[pkt.stream_index];
2232

    
2233
                    ctx->pb->is_streamed = 1;
2234
                    if (pkt.dts != AV_NOPTS_VALUE)
2235
                        pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2236
                    if (pkt.pts != AV_NOPTS_VALUE)
2237
                        pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2238
                    pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2239
                    if (av_write_frame(ctx, &pkt) < 0) {
2240
                        http_log("Error writing frame to output\n");
2241
                        c->state = HTTPSTATE_SEND_DATA_TRAILER;
2242
                    }
2243

    
2244
                    len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2245
                    c->cur_frame_bytes = len;
2246
                    c->buffer_ptr = c->pb_buffer;
2247
                    c->buffer_end = c->pb_buffer + len;
2248

    
2249
                    codec->frame_number++;
2250
                    if (len == 0) {
2251
                        av_free_packet(&pkt);
2252
                        goto redo;
2253
                    }
2254
                }
2255
                av_free_packet(&pkt);
2256
            }
2257
        }
2258
        break;
2259
    default:
2260
    case HTTPSTATE_SEND_DATA_TRAILER:
2261
        /* last packet test ? */
2262
        if (c->last_packet_sent || c->is_packetized)
2263
            return -1;
2264
        ctx = &c->fmt_ctx;
2265
        /* prepare header */
2266
        if (url_open_dyn_buf(&ctx->pb) < 0) {
2267
            /* XXX: potential leak */
2268
            return -1;
2269
        }
2270
        c->fmt_ctx.pb->is_streamed = 1;
2271
        av_write_trailer(ctx);
2272
        len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2273
        c->buffer_ptr = c->pb_buffer;
2274
        c->buffer_end = c->pb_buffer + len;
2275

    
2276
        c->last_packet_sent = 1;
2277
        break;
2278
    }
2279
    return 0;
2280
}
2281

    
2282
/* should convert the format at the same time */
2283
/* send data starting at c->buffer_ptr to the output connection
2284
   (either UDP or TCP connection) */
2285
static int http_send_data(HTTPContext *c)
2286
{
2287
    int len, ret;
2288

    
2289
    for(;;) {
2290
        if (c->buffer_ptr >= c->buffer_end) {
2291
            ret = http_prepare_data(c);
2292
            if (ret < 0)
2293
                return -1;
2294
            else if (ret != 0)
2295
                /* state change requested */
2296
                break;
2297
        } else {
2298
            if (c->is_packetized) {
2299
                /* RTP data output */
2300
                len = c->buffer_end - c->buffer_ptr;
2301
                if (len < 4) {
2302
                    /* fail safe - should never happen */
2303
                fail1:
2304
                    c->buffer_ptr = c->buffer_end;
2305
                    return 0;
2306
                }
2307
                len = (c->buffer_ptr[0] << 24) |
2308
                    (c->buffer_ptr[1] << 16) |
2309
                    (c->buffer_ptr[2] << 8) |
2310
                    (c->buffer_ptr[3]);
2311
                if (len > (c->buffer_end - c->buffer_ptr))
2312
                    goto fail1;
2313
                if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2314
                    /* nothing to send yet: we can wait */
2315
                    return 0;
2316
                }
2317

    
2318
                c->data_count += len;
2319
                update_datarate(&c->datarate, c->data_count);
2320
                if (c->stream)
2321
                    c->stream->bytes_served += len;
2322

    
2323
                if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2324
                    /* RTP packets are sent inside the RTSP TCP connection */
2325
                    ByteIOContext *pb;
2326
                    int interleaved_index, size;
2327
                    uint8_t header[4];
2328
                    HTTPContext *rtsp_c;
2329

    
2330
                    rtsp_c = c->rtsp_c;
2331
                    /* if no RTSP connection left, error */
2332
                    if (!rtsp_c)
2333
                        return -1;
2334
                    /* if already sending something, then wait. */
2335
                    if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2336
                        break;
2337
                    if (url_open_dyn_buf(&pb) < 0)
2338
                        goto fail1;
2339
                    interleaved_index = c->packet_stream_index * 2;
2340
                    /* RTCP packets are sent at odd indexes */
2341
                    if (c->buffer_ptr[1] == 200)
2342
                        interleaved_index++;
2343
                    /* write RTSP TCP header */
2344
                    header[0] = '$';
2345
                    header[1] = interleaved_index;
2346
                    header[2] = len >> 8;
2347
                    header[3] = len;
2348
                    put_buffer(pb, header, 4);
2349
                    /* write RTP packet data */
2350
                    c->buffer_ptr += 4;
2351
                    put_buffer(pb, c->buffer_ptr, len);
2352
                    size = url_close_dyn_buf(pb, &c->packet_buffer);
2353
                    /* prepare asynchronous TCP sending */
2354
                    rtsp_c->packet_buffer_ptr = c->packet_buffer;
2355
                    rtsp_c->packet_buffer_end = c->packet_buffer + size;
2356
                    c->buffer_ptr += len;
2357

    
2358
                    /* send everything we can NOW */
2359
                    len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2360
                                rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2361
                    if (len > 0)
2362
                        rtsp_c->packet_buffer_ptr += len;
2363
                    if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2364
                        /* if we could not send all the data, we will
2365
                           send it later, so a new state is needed to
2366
                           "lock" the RTSP TCP connection */
2367
                        rtsp_c->state = RTSPSTATE_SEND_PACKET;
2368
                        break;
2369
                    } else
2370
                        /* all data has been sent */
2371
                        av_freep(&c->packet_buffer);
2372
                } else {
2373
                    /* send RTP packet directly in UDP */
2374
                    c->buffer_ptr += 4;
2375
                    url_write(c->rtp_handles[c->packet_stream_index],
2376
                              c->buffer_ptr, len);
2377
                    c->buffer_ptr += len;
2378
                    /* here we continue as we can send several packets per 10 ms slot */
2379
                }
2380
            } else {
2381
                /* TCP data output */
2382
                len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2383
                if (len < 0) {
2384
                    if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2385
                        ff_neterrno() != FF_NETERROR(EINTR))
2386
                        /* error : close connection */
2387
                        return -1;
2388
                    else
2389
                        return 0;
2390
                } else
2391
                    c->buffer_ptr += len;
2392

    
2393
                c->data_count += len;
2394
                update_datarate(&c->datarate, c->data_count);
2395
                if (c->stream)
2396
                    c->stream->bytes_served += len;
2397
                break;
2398
            }
2399
        }
2400
    } /* for(;;) */
2401
    return 0;
2402
}
2403

    
2404
static int http_start_receive_data(HTTPContext *c)
2405
{
2406
    int fd;
2407

    
2408
    if (c->stream->feed_opened)
2409
        return -1;
2410

    
2411
    /* Don't permit writing to this one */
2412
    if (c->stream->readonly)
2413
        return -1;
2414

    
2415
    /* open feed */
2416
    fd = open(c->stream->feed_filename, O_RDWR);
2417
    if (fd < 0) {
2418
        http_log("Error opening feeder file: %s\n", strerror(errno));
2419
        return -1;
2420
    }
2421
    c->feed_fd = fd;
2422

    
2423
    if (c->stream->truncate) {
2424
        /* truncate feed file */
2425
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2426
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2427
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2428
    } else {
2429
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2430
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2431
            return -1;
2432
        }
2433
    }
2434

    
2435
    c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2436
    c->stream->feed_size = lseek(fd, 0, SEEK_END);
2437
    lseek(fd, 0, SEEK_SET);
2438

    
2439
    /* init buffer input */
2440
    c->buffer_ptr = c->buffer;
2441
    c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2442
    c->stream->feed_opened = 1;
2443
    return 0;
2444
}
2445

    
2446
static int http_receive_data(HTTPContext *c)
2447
{
2448
    HTTPContext *c1;
2449

    
2450
    if (c->buffer_end > c->buffer_ptr) {
2451
        int len;
2452

    
2453
        len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2454
        if (len < 0) {
2455
            if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
2456
                ff_neterrno() != FF_NETERROR(EINTR))
2457
                /* error : close connection */
2458
                goto fail;
2459
        } else if (len == 0)
2460
            /* end of connection : close it */
2461
            goto fail;
2462
        else {
2463
            c->buffer_ptr += len;
2464
            c->data_count += len;
2465
            update_datarate(&c->datarate, c->data_count);
2466
        }
2467
    }
2468

    
2469
    if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2470
        if (c->buffer[0] != 'f' ||
2471
            c->buffer[1] != 'm') {
2472
            http_log("Feed stream has become desynchronized -- disconnecting\n");
2473
            goto fail;
2474
        }
2475
    }
2476

    
2477
    if (c->buffer_ptr >= c->buffer_end) {
2478
        FFStream *feed = c->stream;
2479
        /* a packet has been received : write it in the store, except
2480
           if header */
2481
        if (c->data_count > FFM_PACKET_SIZE) {
2482

    
2483
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2484
            /* XXX: use llseek or url_seek */
2485
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2486
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2487
                http_log("Error writing to feed file: %s\n", strerror(errno));
2488
                goto fail;
2489
            }
2490

    
2491
            feed->feed_write_index += FFM_PACKET_SIZE;
2492
            /* update file size */
2493
            if (feed->feed_write_index > c->stream->feed_size)
2494
                feed->feed_size = feed->feed_write_index;
2495

    
2496
            /* handle wrap around if max file size reached */
2497
            if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2498
                feed->feed_write_index = FFM_PACKET_SIZE;
2499

    
2500
            /* write index */
2501
            if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2502
                http_log("Error writing index to feed file: %s\n", strerror(errno));
2503
                goto fail;
2504
            }
2505

    
2506
            /* wake up any waiting connections */
2507
            for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2508
                if (c1->state == HTTPSTATE_WAIT_FEED &&
2509
                    c1->stream->feed == c->stream->feed)
2510
                    c1->state = HTTPSTATE_SEND_DATA;
2511
            }
2512
        } else {
2513
            /* We have a header in our hands that contains useful data */
2514
            AVFormatContext *s = NULL;
2515
            ByteIOContext *pb;
2516
            AVInputFormat *fmt_in;
2517
            int i;
2518

    
2519
            /* use feed output format name to find corresponding input format */
2520
            fmt_in = av_find_input_format(feed->fmt->name);
2521
            if (!fmt_in)
2522
                goto fail;
2523

    
2524
            url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2525
            pb->is_streamed = 1;
2526

    
2527
            if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2528
                av_free(pb);
2529
                goto fail;
2530
            }
2531

    
2532
            /* Now we have the actual streams */
2533
            if (s->nb_streams != feed->nb_streams) {
2534
                av_close_input_stream(s);
2535
                av_free(pb);
2536
                http_log("Feed '%s' stream number does not match registered feed\n",
2537
                         c->stream->feed_filename);
2538
                goto fail;
2539
            }
2540

    
2541
            for (i = 0; i < s->nb_streams; i++) {
2542
                AVStream *fst = feed->streams[i];
2543
                AVStream *st = s->streams[i];
2544
                memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
2545
                if (fst->codec->extradata_size) {
2546
                    fst->codec->extradata = av_malloc(fst->codec->extradata_size);
2547
                    if (!fst->codec->extradata)
2548
                        goto fail;
2549
                    memcpy(fst->codec->extradata, st->codec->extradata,
2550
                           fst->codec->extradata_size);
2551
                }
2552
            }
2553

    
2554
            av_close_input_stream(s);
2555
            av_free(pb);
2556
        }
2557
        c->buffer_ptr = c->buffer;
2558
    }
2559

    
2560
    return 0;
2561
 fail:
2562
    c->stream->feed_opened = 0;
2563
    close(c->feed_fd);
2564
    /* wake up any waiting connections to stop waiting for feed */
2565
    for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2566
        if (c1->state == HTTPSTATE_WAIT_FEED &&
2567
            c1->stream->feed == c->stream->feed)
2568
            c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2569
    }
2570
    return -1;
2571
}
2572

    
2573
/********************************************************************/
2574
/* RTSP handling */
2575

    
2576
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2577
{
2578
    const char *str;
2579
    time_t ti;
2580
    char *p;
2581
    char buf2[32];
2582

    
2583
    switch(error_number) {
2584
    case RTSP_STATUS_OK:
2585
        str = "OK";
2586
        break;
2587
    case RTSP_STATUS_METHOD:
2588
        str = "Method Not Allowed";
2589
        break;
2590
    case RTSP_STATUS_BANDWIDTH:
2591
        str = "Not Enough Bandwidth";
2592
        break;
2593
    case RTSP_STATUS_SESSION:
2594
        str = "Session Not Found";
2595
        break;
2596
    case RTSP_STATUS_STATE:
2597
        str = "Method Not Valid in This State";
2598
        break;
2599
    case RTSP_STATUS_AGGREGATE:
2600
        str = "Aggregate operation not allowed";
2601
        break;
2602
    case RTSP_STATUS_ONLY_AGGREGATE:
2603
        str = "Only aggregate operation allowed";
2604
        break;
2605
    case RTSP_STATUS_TRANSPORT:
2606
        str = "Unsupported transport";
2607
        break;
2608
    case RTSP_STATUS_INTERNAL:
2609
        str = "Internal Server Error";
2610
        break;
2611
    case RTSP_STATUS_SERVICE:
2612
        str = "Service Unavailable";
2613
        break;
2614
    case RTSP_STATUS_VERSION:
2615
        str = "RTSP Version not supported";
2616
        break;
2617
    default:
2618
        str = "Unknown Error";
2619
        break;
2620
    }
2621

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

    
2625
    /* output GMT time */
2626
    ti = time(NULL);
2627
    p = ctime(&ti);
2628
    strcpy(buf2, p);
2629
    p = buf2 + strlen(p) - 1;
2630
    if (*p == '\n')
2631
        *p = '\0';
2632
    url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2633
}
2634

    
2635
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2636
{
2637
    rtsp_reply_header(c, error_number);
2638
    url_fprintf(c->pb, "\r\n");
2639
}
2640

    
2641
static int rtsp_parse_request(HTTPContext *c)
2642
{
2643
    const char *p, *p1, *p2;
2644
    char cmd[32];
2645
    char url[1024];
2646
    char protocol[32];
2647
    char line[1024];
2648
    int len;
2649
    RTSPMessageHeader header1, *header = &header1;
2650

    
2651
    c->buffer_ptr[0] = '\0';
2652
    p = c->buffer;
2653

    
2654
    get_word(cmd, sizeof(cmd), &p);
2655
    get_word(url, sizeof(url), &p);
2656
    get_word(protocol, sizeof(protocol), &p);
2657

    
2658
    av_strlcpy(c->method, cmd, sizeof(c->method));
2659
    av_strlcpy(c->url, url, sizeof(c->url));
2660
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2661

    
2662
    if (url_open_dyn_buf(&c->pb) < 0) {
2663
        /* XXX: cannot do more */
2664
        c->pb = NULL; /* safety */
2665
        return -1;
2666
    }
2667

    
2668
    /* check version name */
2669
    if (strcmp(protocol, "RTSP/1.0") != 0) {
2670
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
2671
        goto the_end;
2672
    }
2673

    
2674
    /* parse each header line */
2675
    memset(header, 0, sizeof(*header));
2676
    /* skip to next line */
2677
    while (*p != '\n' && *p != '\0')
2678
        p++;
2679
    if (*p == '\n')
2680
        p++;
2681
    while (*p != '\0') {
2682
        p1 = strchr(p, '\n');
2683
        if (!p1)
2684
            break;
2685
        p2 = p1;
2686
        if (p2 > p && p2[-1] == '\r')
2687
            p2--;
2688
        /* skip empty line */
2689
        if (p2 == p)
2690
            break;
2691
        len = p2 - p;
2692
        if (len > sizeof(line) - 1)
2693
            len = sizeof(line) - 1;
2694
        memcpy(line, p, len);
2695
        line[len] = '\0';
2696
        rtsp_parse_line(header, line);
2697
        p = p1 + 1;
2698
    }
2699

    
2700
    /* handle sequence number */
2701
    c->seq = header->seq;
2702

    
2703
    if (!strcmp(cmd, "DESCRIBE"))
2704
        rtsp_cmd_describe(c, url);
2705
    else if (!strcmp(cmd, "OPTIONS"))
2706
        rtsp_cmd_options(c, url);
2707
    else if (!strcmp(cmd, "SETUP"))
2708
        rtsp_cmd_setup(c, url, header);
2709
    else if (!strcmp(cmd, "PLAY"))
2710
        rtsp_cmd_play(c, url, header);
2711
    else if (!strcmp(cmd, "PAUSE"))
2712
        rtsp_cmd_pause(c, url, header);
2713
    else if (!strcmp(cmd, "TEARDOWN"))
2714
        rtsp_cmd_teardown(c, url, header);
2715
    else
2716
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
2717

    
2718
 the_end:
2719
    len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2720
    c->pb = NULL; /* safety */
2721
    if (len < 0) {
2722
        /* XXX: cannot do more */
2723
        return -1;
2724
    }
2725
    c->buffer_ptr = c->pb_buffer;
2726
    c->buffer_end = c->pb_buffer + len;
2727
    c->state = RTSPSTATE_SEND_REPLY;
2728
    return 0;
2729
}
2730

    
2731
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2732
                                   struct in_addr my_ip)
2733
{
2734
    AVFormatContext *avc;
2735
    AVStream avs[MAX_STREAMS];
2736
    int i;
2737

    
2738
    avc =  avformat_alloc_context();
2739
    if (avc == NULL) {
2740
        return -1;
2741
    }
2742
    av_metadata_set(&avc->metadata, "title",
2743
                    stream->title[0] ? stream->title : "No Title");
2744
    avc->nb_streams = stream->nb_streams;
2745
    if (stream->is_multicast) {
2746
        snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2747
                 inet_ntoa(stream->multicast_ip),
2748
                 stream->multicast_port, stream->multicast_ttl);
2749
    }
2750

    
2751
    for(i = 0; i < stream->nb_streams; i++) {
2752
        avc->streams[i] = &avs[i];
2753
        avc->streams[i]->codec = stream->streams[i]->codec;
2754
    }
2755
    *pbuffer = av_mallocz(2048);
2756
    avf_sdp_create(&avc, 1, *pbuffer, 2048);
2757
    av_free(avc);
2758

    
2759
    return strlen(*pbuffer);
2760
}
2761

    
2762
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2763
{
2764
//    rtsp_reply_header(c, RTSP_STATUS_OK);
2765
    url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2766
    url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2767
    url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2768
    url_fprintf(c->pb, "\r\n");
2769
}
2770

    
2771
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2772
{
2773
    FFStream *stream;
2774
    char path1[1024];
2775
    const char *path;
2776
    uint8_t *content;
2777
    int content_length, len;
2778
    struct sockaddr_in my_addr;
2779

    
2780
    /* find which url is asked */
2781
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2782
    path = path1;
2783
    if (*path == '/')
2784
        path++;
2785

    
2786
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2787
        if (!stream->is_feed &&
2788
            stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2789
            !strcmp(path, stream->filename)) {
2790
            goto found;
2791
        }
2792
    }
2793
    /* no stream found */
2794
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2795
    return;
2796

    
2797
 found:
2798
    /* prepare the media description in sdp format */
2799

    
2800
    /* get the host IP */
2801
    len = sizeof(my_addr);
2802
    getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2803
    content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2804
    if (content_length < 0) {
2805
        rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2806
        return;
2807
    }
2808
    rtsp_reply_header(c, RTSP_STATUS_OK);
2809
    url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2810
    url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2811
    url_fprintf(c->pb, "\r\n");
2812
    put_buffer(c->pb, content, content_length);
2813
}
2814

    
2815
static HTTPContext *find_rtp_session(const char *session_id)
2816
{
2817
    HTTPContext *c;
2818

    
2819
    if (session_id[0] == '\0')
2820
        return NULL;
2821

    
2822
    for(c = first_http_ctx; c != NULL; c = c->next) {
2823
        if (!strcmp(c->session_id, session_id))
2824
            return c;
2825
    }
2826
    return NULL;
2827
}
2828

    
2829
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2830
{
2831
    RTSPTransportField *th;
2832
    int i;
2833

    
2834
    for(i=0;i<h->nb_transports;i++) {
2835
        th = &h->transports[i];
2836
        if (th->lower_transport == lower_transport)
2837
            return th;
2838
    }
2839
    return NULL;
2840
}
2841

    
2842
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2843
                           RTSPMessageHeader *h)
2844
{
2845
    FFStream *stream;
2846
    int stream_index, port;
2847
    char buf[1024];
2848
    char path1[1024];
2849
    const char *path;
2850
    HTTPContext *rtp_c;
2851
    RTSPTransportField *th;
2852
    struct sockaddr_in dest_addr;
2853
    RTSPActionServerSetup setup;
2854

    
2855
    /* find which url is asked */
2856
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2857
    path = path1;
2858
    if (*path == '/')
2859
        path++;
2860

    
2861
    /* now check each stream */
2862
    for(stream = first_stream; stream != NULL; stream = stream->next) {
2863
        if (!stream->is_feed &&
2864
            stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2865
            /* accept aggregate filenames only if single stream */
2866
            if (!strcmp(path, stream->filename)) {
2867
                if (stream->nb_streams != 1) {
2868
                    rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2869
                    return;
2870
                }
2871
                stream_index = 0;
2872
                goto found;
2873
            }
2874

    
2875
            for(stream_index = 0; stream_index < stream->nb_streams;
2876
                stream_index++) {
2877
                snprintf(buf, sizeof(buf), "%s/streamid=%d",
2878
                         stream->filename, stream_index);
2879
                if (!strcmp(path, buf))
2880
                    goto found;
2881
            }
2882
        }
2883
    }
2884
    /* no stream found */
2885
    rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2886
    return;
2887
 found:
2888

    
2889
    /* generate session id if needed */
2890
    if (h->session_id[0] == '\0')
2891
        snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2892
                 av_lfg_get(&random_state), av_lfg_get(&random_state));
2893

    
2894
    /* find rtp session, and create it if none found */
2895
    rtp_c = find_rtp_session(h->session_id);
2896
    if (!rtp_c) {
2897
        /* always prefer UDP */
2898
        th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2899
        if (!th) {
2900
            th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2901
            if (!th) {
2902
                rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2903
                return;
2904
            }
2905
        }
2906

    
2907
        rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2908
                                   th->lower_transport);
2909
        if (!rtp_c) {
2910
            rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2911
            return;
2912
        }
2913

    
2914
        /* open input stream */
2915
        if (open_input_stream(rtp_c, "") < 0) {
2916
            rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2917
            return;
2918
        }
2919
    }
2920

    
2921
    /* test if stream is OK (test needed because several SETUP needs
2922
       to be done for a given file) */
2923
    if (rtp_c->stream != stream) {
2924
        rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2925
        return;
2926
    }
2927

    
2928
    /* test if stream is already set up */
2929
    if (rtp_c->rtp_ctx[stream_index]) {
2930
        rtsp_reply_error(c, RTSP_STATUS_STATE);
2931
        return;
2932
    }
2933

    
2934
    /* check transport */
2935
    th = find_transport(h, rtp_c->rtp_protocol);
2936
    if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2937
                th->client_port_min <= 0)) {
2938
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2939
        return;
2940
    }
2941

    
2942
    /* setup default options */
2943
    setup.transport_option[0] = '\0';
2944
    dest_addr = rtp_c->from_addr;
2945
    dest_addr.sin_port = htons(th->client_port_min);
2946

    
2947
    /* setup stream */
2948
    if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2949
        rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2950
        return;
2951
    }
2952

    
2953
    /* now everything is OK, so we can send the connection parameters */
2954
    rtsp_reply_header(c, RTSP_STATUS_OK);
2955
    /* session ID */
2956
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2957

    
2958
    switch(rtp_c->rtp_protocol) {
2959
    case RTSP_LOWER_TRANSPORT_UDP:
2960
        port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2961
        url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2962
                    "client_port=%d-%d;server_port=%d-%d",
2963
                    th->client_port_min, th->client_port_min + 1,
2964
                    port, port + 1);
2965
        break;
2966
    case RTSP_LOWER_TRANSPORT_TCP:
2967
        url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2968
                    stream_index * 2, stream_index * 2 + 1);
2969
        break;
2970
    default:
2971
        break;
2972
    }
2973
    if (setup.transport_option[0] != '\0')
2974
        url_fprintf(c->pb, ";%s", setup.transport_option);
2975
    url_fprintf(c->pb, "\r\n");
2976

    
2977

    
2978
    url_fprintf(c->pb, "\r\n");
2979
}
2980

    
2981

    
2982
/* find an rtp connection by using the session ID. Check consistency
2983
   with filename */
2984
static HTTPContext *find_rtp_session_with_url(const char *url,
2985
                                              const char *session_id)
2986
{
2987
    HTTPContext *rtp_c;
2988
    char path1[1024];
2989
    const char *path;
2990
    char buf[1024];
2991
    int s;
2992

    
2993
    rtp_c = find_rtp_session(session_id);
2994
    if (!rtp_c)
2995
        return NULL;
2996

    
2997
    /* find which url is asked */
2998
    url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2999
    path = path1;
3000
    if (*path == '/')
3001
        path++;
3002
    if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3003
    for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3004
      snprintf(buf, sizeof(buf), "%s/streamid=%d",
3005
        rtp_c->stream->filename, s);
3006
      if(!strncmp(path, buf, sizeof(buf))) {
3007
    // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3008
        return rtp_c;
3009
      }
3010
    }
3011
    return NULL;
3012
}
3013

    
3014
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3015
{
3016
    HTTPContext *rtp_c;
3017

    
3018
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3019
    if (!rtp_c) {
3020
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3021
        return;
3022
    }
3023

    
3024
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3025
        rtp_c->state != HTTPSTATE_WAIT_FEED &&
3026
        rtp_c->state != HTTPSTATE_READY) {
3027
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3028
        return;
3029
    }
3030

    
3031
    rtp_c->state = HTTPSTATE_SEND_DATA;
3032

    
3033
    /* now everything is OK, so we can send the connection parameters */
3034
    rtsp_reply_header(c, RTSP_STATUS_OK);
3035
    /* session ID */
3036
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3037
    url_fprintf(c->pb, "\r\n");
3038
}
3039

    
3040
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3041
{
3042
    HTTPContext *rtp_c;
3043

    
3044
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3045
    if (!rtp_c) {
3046
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3047
        return;
3048
    }
3049

    
3050
    if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3051
        rtp_c->state != HTTPSTATE_WAIT_FEED) {
3052
        rtsp_reply_error(c, RTSP_STATUS_STATE);
3053
        return;
3054
    }
3055

    
3056
    rtp_c->state = HTTPSTATE_READY;
3057
    rtp_c->first_pts = AV_NOPTS_VALUE;
3058
    /* now everything is OK, so we can send the connection parameters */
3059
    rtsp_reply_header(c, RTSP_STATUS_OK);
3060
    /* session ID */
3061
    url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3062
    url_fprintf(c->pb, "\r\n");
3063
}
3064

    
3065
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3066
{
3067
    HTTPContext *rtp_c;
3068
    char session_id[32];
3069

    
3070
    rtp_c = find_rtp_session_with_url(url, h->session_id);
3071
    if (!rtp_c) {
3072
        rtsp_reply_error(c, RTSP_STATUS_SESSION);
3073
        return;
3074
    }
3075

    
3076
    av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3077

    
3078
    /* abort the session */
3079
    close_connection(rtp_c);
3080

    
3081
    /* now everything is OK, so we can send the connection parameters */
3082
    rtsp_reply_header(c, RTSP_STATUS_OK);
3083
    /* session ID */
3084
    url_fprintf(c->pb, "Session: %s\r\n", session_id);
3085
    url_fprintf(c->pb, "\r\n");
3086
}
3087

    
3088

    
3089
/********************************************************************/
3090
/* RTP handling */
3091

    
3092
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3093
                                       FFStream *stream, const char *session_id,
3094
                                       enum RTSPLowerTransport rtp_protocol)
3095
{
3096
    HTTPContext *c = NULL;
3097
    const char *proto_str;
3098

    
3099
    /* XXX: should output a warning page when coming
3100
       close to the connection limit */
3101
    if (nb_connections >= nb_max_connections)
3102
        goto fail;
3103

    
3104
    /* add a new connection */
3105
    c = av_mallocz(sizeof(HTTPContext));
3106
    if (!c)
3107
        goto fail;
3108

    
3109
    c->fd = -1;
3110
    c->poll_entry = NULL;
3111
    c->from_addr = *from_addr;
3112
    c->buffer_size = IOBUFFER_INIT_SIZE;
3113
    c->buffer = av_malloc(c->buffer_size);
3114
    if (!c->buffer)
3115
        goto fail;
3116
    nb_connections++;
3117
    c->stream = stream;
3118
    av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3119
    c->state = HTTPSTATE_READY;
3120
    c->is_packetized = 1;
3121
    c->rtp_protocol = rtp_protocol;
3122

    
3123
    /* protocol is shown in statistics */
3124
    switch(c->rtp_protocol) {
3125
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3126
        proto_str = "MCAST";
3127
        break;
3128
    case RTSP_LOWER_TRANSPORT_UDP:
3129
        proto_str = "UDP";
3130
        break;
3131
    case RTSP_LOWER_TRANSPORT_TCP:
3132
        proto_str = "TCP";
3133
        break;
3134
    default:
3135
        proto_str = "???";
3136
        break;
3137
    }
3138
    av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3139
    av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3140

    
3141
    current_bandwidth += stream->bandwidth;
3142

    
3143
    c->next = first_http_ctx;
3144
    first_http_ctx = c;
3145
    return c;
3146

    
3147
 fail:
3148
    if (c) {
3149
        av_free(c->buffer);
3150
        av_free(c);
3151
    }
3152
    return NULL;
3153
}
3154

    
3155
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3156
   command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3157
   used. */
3158
static int rtp_new_av_stream(HTTPContext *c,
3159
                             int stream_index, struct sockaddr_in *dest_addr,
3160
                             HTTPContext *rtsp_c)
3161
{
3162
    AVFormatContext *ctx;
3163
    AVStream *st;
3164
    char *ipaddr;
3165
    URLContext *h = NULL;
3166
    uint8_t *dummy_buf;
3167
    int max_packet_size;
3168

    
3169
    /* now we can open the relevant output stream */
3170
    ctx = avformat_alloc_context();
3171
    if (!ctx)
3172
        return -1;
3173
    ctx->oformat = guess_format("rtp", NULL, NULL);
3174

    
3175
    st = av_mallocz(sizeof(AVStream));
3176
    if (!st)
3177
        goto fail;
3178
    st->codec= avcodec_alloc_context();
3179
    ctx->nb_streams = 1;
3180
    ctx->streams[0] = st;
3181

    
3182
    if (!c->stream->feed ||
3183
        c->stream->feed == c->stream)
3184
        memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3185
    else
3186
        memcpy(st,
3187
               c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3188
               sizeof(AVStream));
3189
    st->priv_data = NULL;
3190

    
3191
    /* build destination RTP address */
3192
    ipaddr = inet_ntoa(dest_addr->sin_addr);
3193

    
3194
    switch(c->rtp_protocol) {
3195
    case RTSP_LOWER_TRANSPORT_UDP:
3196
    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3197
        /* RTP/UDP case */
3198

    
3199
        /* XXX: also pass as parameter to function ? */
3200
        if (c->stream->is_multicast) {
3201
            int ttl;
3202
            ttl = c->stream->multicast_ttl;
3203
            if (!ttl)
3204
                ttl = 16;
3205
            snprintf(ctx->filename, sizeof(ctx->filename),
3206
                     "rtp://%s:%d?multicast=1&ttl=%d",
3207
                     ipaddr, ntohs(dest_addr->sin_port), ttl);
3208
        } else {
3209
            snprintf(ctx->filename, sizeof(ctx->filename),
3210
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3211
        }
3212

    
3213
        if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3214
            goto fail;
3215
        c->rtp_handles[stream_index] = h;
3216
        max_packet_size = url_get_max_packet_size(h);
3217
        break;
3218
    case RTSP_LOWER_TRANSPORT_TCP:
3219
        /* RTP/TCP case */
3220
        c->rtsp_c = rtsp_c;
3221
        max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3222
        break;
3223
    default:
3224
        goto fail;
3225
    }
3226

    
3227
    http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3228
             ipaddr, ntohs(dest_addr->sin_port),
3229
             c->stream->filename, stream_index, c->protocol);
3230

    
3231
    /* normally, no packets should be output here, but the packet size may be checked */
3232
    if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3233
        /* XXX: close stream */
3234
        goto fail;
3235
    }
3236
    av_set_parameters(ctx, NULL);
3237
    if (av_write_header(ctx) < 0) {
3238
    fail:
3239
        if (h)
3240
            url_close(h);
3241
        av_free(ctx);
3242
        return -1;
3243
    }
3244
    url_close_dyn_buf(ctx->pb, &dummy_buf);
3245
    av_free(dummy_buf);
3246

    
3247
    c->rtp_ctx[stream_index] = ctx;
3248
    return 0;
3249
}
3250

    
3251
/********************************************************************/
3252
/* ffserver initialization */
3253

    
3254
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
3255
{
3256
    AVStream *fst;
3257

    
3258
    fst = av_mallocz(sizeof(AVStream));
3259
    if (!fst)
3260
        return NULL;
3261
    fst->codec= avcodec_alloc_context();
3262
    fst->priv_data = av_mallocz(sizeof(FeedData));
3263
    memcpy(fst->codec, codec, sizeof(AVCodecContext));
3264
    fst->index = stream->nb_streams;
3265
    av_set_pts_info(fst, 33, 1, 90000);
3266
    stream->streams[stream->nb_streams++] = fst;
3267
    return fst;
3268
}
3269

    
3270
/* return the stream number in the feed */
3271
static int add_av_stream(FFStream *feed, AVStream *st)
3272
{
3273
    AVStream *fst;
3274
    AVCodecContext *av, *av1;
3275
    int i;
3276

    
3277
    av = st->codec;
3278
    for(i=0;i<feed->nb_streams;i++) {
3279
        st = feed->streams[i];
3280
        av1 = st->codec;
3281
        if (av1->codec_id == av->codec_id &&
3282
            av1->codec_type == av->codec_type &&
3283
            av1->bit_rate == av->bit_rate) {
3284

    
3285
            switch(av->codec_type) {
3286
            case CODEC_TYPE_AUDIO:
3287
                if (av1->channels == av->channels &&
3288
                    av1->sample_rate == av->sample_rate)
3289
                    goto found;
3290
                break;
3291
            case CODEC_TYPE_VIDEO:
3292
                if (av1->width == av->width &&
3293
                    av1->height == av->height &&
3294
                    av1->time_base.den == av->time_base.den &&
3295
                    av1->time_base.num == av->time_base.num &&
3296
                    av1->gop_size == av->gop_size)
3297
                    goto found;
3298
                break;
3299
            default:
3300
                abort();
3301
            }
3302
        }
3303
    }
3304

    
3305
    fst = add_av_stream1(feed, av);
3306
    if (!fst)
3307
        return -1;
3308
    return feed->nb_streams - 1;
3309
 found:
3310
    return i;
3311
}
3312

    
3313
static void remove_stream(FFStream *stream)
3314
{
3315
    FFStream **ps;
3316
    ps = &first_stream;
3317
    while (*ps != NULL) {
3318
        if (*ps == stream)
3319
            *ps = (*ps)->next;
3320
        else
3321
            ps = &(*ps)->next;
3322
    }
3323
}
3324

    
3325
/* specific mpeg4 handling : we extract the raw parameters */
3326
static void extract_mpeg4_header(AVFormatContext *infile)
3327
{
3328
    int mpeg4_count, i, size;
3329
    AVPacket pkt;
3330
    AVStream *st;
3331
    const uint8_t *p;
3332

    
3333
    mpeg4_count = 0;
3334
    for(i=0;i<infile->nb_streams;i++) {
3335
        st = infile->streams[i];
3336
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3337
            st->codec->extradata_size == 0) {
3338
            mpeg4_count++;
3339
        }
3340
    }
3341
    if (!mpeg4_count)
3342
        return;
3343

    
3344
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3345
    while (mpeg4_count > 0) {
3346
        if (av_read_packet(infile, &pkt) < 0)
3347
            break;
3348
        st = infile->streams[pkt.stream_index];
3349
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3350
            st->codec->extradata_size == 0) {
3351
            av_freep(&st->codec->extradata);
3352
            /* fill extradata with the header */
3353
            /* XXX: we make hard suppositions here ! */
3354
            p = pkt.data;
3355
            while (p < pkt.data + pkt.size - 4) {
3356
                /* stop when vop header is found */
3357
                if (p[0] == 0x00 && p[1] == 0x00 &&
3358
                    p[2] == 0x01 && p[3] == 0xb6) {
3359
                    size = p - pkt.data;
3360
                    //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3361
                    st->codec->extradata = av_malloc(size);
3362
                    st->codec->extradata_size = size;
3363
                    memcpy(st->codec->extradata, pkt.data, size);
3364
                    break;
3365
                }
3366
                p++;
3367
            }
3368
            mpeg4_count--;
3369
        }
3370
        av_free_packet(&pkt);
3371
    }
3372
}
3373

    
3374
/* compute the needed AVStream for each file */
3375
static void build_file_streams(void)
3376
{
3377
    FFStream *stream, *stream_next;
3378
    AVFormatContext *infile;
3379
    int i, ret;
3380

    
3381
    /* gather all streams */
3382
    for(stream = first_stream; stream != NULL; stream = stream_next) {
3383
        stream_next = stream->next;
3384
        if (stream->stream_type == STREAM_TYPE_LIVE &&
3385
            !stream->feed) {
3386
            /* the stream comes from a file */
3387
            /* try to open the file */
3388
            /* open stream */
3389
            stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3390
            if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3391
                /* specific case : if transport stream output to RTP,
3392
                   we use a raw transport stream reader */
3393
                stream->ap_in->mpeg2ts_raw = 1;
3394
                stream->ap_in->mpeg2ts_compute_pcr = 1;
3395
            }
3396

    
3397
            http_log("Opening file '%s'\n", stream->feed_filename);
3398
            if ((ret = av_open_input_file(&infile, stream->feed_filename,
3399
                                          stream->ifmt, 0, stream->ap_in)) < 0) {
3400
                http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3401
                /* remove stream (no need to spend more time on it) */
3402
            fail:
3403
                remove_stream(stream);
3404
            } else {
3405
                /* find all the AVStreams inside and reference them in
3406
                   'stream' */
3407
                if (av_find_stream_info(infile) < 0) {
3408
                    http_log("Could not find codec parameters from '%s'\n",
3409
                             stream->feed_filename);
3410
                    av_close_input_file(infile);
3411
                    goto fail;
3412
                }
3413
                extract_mpeg4_header(infile);
3414

    
3415
                for(i=0;i<infile->nb_streams;i++)
3416
                    add_av_stream1(stream, infile->streams[i]->codec);
3417

    
3418
                av_close_input_file(infile);
3419
            }
3420
        }
3421
    }
3422
}
3423

    
3424
/* compute the needed AVStream for each feed */
3425
static void build_feed_streams(void)
3426
{
3427
    FFStream *stream, *feed;
3428
    int i;
3429

    
3430
    /* gather all streams */
3431
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3432
        feed = stream->feed;
3433
        if (feed) {
3434
            if (!stream->is_feed) {
3435
                /* we handle a stream coming from a feed */
3436
                for(i=0;i<stream->nb_streams;i++)
3437
                    stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3438
            }
3439
        }
3440
    }
3441

    
3442
    /* gather all streams */
3443
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3444
        feed = stream->feed;
3445
        if (feed) {
3446
            if (stream->is_feed) {
3447
                for(i=0;i<stream->nb_streams;i++)
3448
                    stream->feed_streams[i] = i;
3449
            }
3450
        }
3451
    }
3452

    
3453
    /* create feed files if needed */
3454
    for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3455
        int fd;
3456

    
3457
        if (url_exist(feed->feed_filename)) {
3458
            /* See if it matches */
3459
            AVFormatContext *s;
3460
            int matches = 0;
3461

    
3462
            if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3463
                /* Now see if it matches */
3464
                if (s->nb_streams == feed->nb_streams) {
3465
                    matches = 1;
3466
                    for(i=0;i<s->nb_streams;i++) {
3467
                        AVStream *sf, *ss;
3468
                        sf = feed->streams[i];
3469
                        ss = s->streams[i];
3470

    
3471
                        if (sf->index != ss->index ||
3472
                            sf->id != ss->id) {
3473
                            http_log("Index & Id do not match for stream %d (%s)\n",
3474
                                   i, feed->feed_filename);
3475
                            matches = 0;
3476
                        } else {
3477
                            AVCodecContext *ccf, *ccs;
3478

    
3479
                            ccf = sf->codec;
3480
                            ccs = ss->codec;
3481
#define CHECK_CODEC(x)  (ccf->x != ccs->x)
3482

    
3483
                            if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
3484
                                http_log("Codecs do not match for stream %d\n", i);
3485
                                matches = 0;
3486
                            } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3487
                                http_log("Codec bitrates do not match for stream %d\n", i);
3488
                                matches = 0;
3489
                            } else if (ccf->codec_type == CODEC_TYPE_VIDEO) {
3490
                                if (CHECK_CODEC(time_base.den) ||
3491
                                    CHECK_CODEC(time_base.num) ||
3492
                                    CHECK_CODEC(width) ||
3493
                                    CHECK_CODEC(height)) {
3494
                                    http_log("Codec width, height and framerate do not match for stream %d\n", i);
3495
                                    matches = 0;
3496
                                }
3497
                            } else if (ccf->codec_type == CODEC_TYPE_AUDIO) {
3498
                                if (CHECK_CODEC(sample_rate) ||
3499
                                    CHECK_CODEC(channels) ||
3500
                                    CHECK_CODEC(frame_size)) {
3501
                                    http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3502
                                    matches = 0;
3503
                                }
3504
                            } else {
3505
                                http_log("Unknown codec type\n");
3506
                                matches = 0;
3507
                            }
3508
                        }
3509
                        if (!matches)
3510
                            break;
3511
                    }
3512
                } else
3513
                    http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3514
                        feed->feed_filename, s->nb_streams, feed->nb_streams);
3515

    
3516
                av_close_input_file(s);
3517
            } else
3518
                http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3519
                        feed->feed_filename);
3520

    
3521
            if (!matches) {
3522
                if (feed->readonly) {
3523
                    http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3524
                        feed->feed_filename);
3525
                    exit(1);
3526
                }
3527
                unlink(feed->feed_filename);
3528
            }
3529
        }
3530
        if (!url_exist(feed->feed_filename)) {
3531
            AVFormatContext s1 = {0}, *s = &s1;
3532

    
3533
            if (feed->readonly) {
3534
                http_log("Unable to create feed file '%s' as it is marked readonly\n",
3535
                    feed->feed_filename);
3536
                exit(1);
3537
            }
3538

    
3539
            /* only write the header of the ffm file */
3540
            if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
3541
                http_log("Could not open output feed file '%s'\n",
3542
                         feed->feed_filename);
3543
                exit(1);
3544
            }
3545
            s->oformat = feed->fmt;
3546
            s->nb_streams = feed->nb_streams;
3547
            for(i=0;i<s->nb_streams;i++) {
3548
                AVStream *st;
3549
                st = feed->streams[i];
3550
                s->streams[i] = st;
3551
            }
3552
            av_set_parameters(s, NULL);
3553
            if (av_write_header(s) < 0) {
3554
                http_log("Container doesn't supports the required parameters\n");
3555
                exit(1);
3556
            }
3557
            /* XXX: need better api */
3558
            av_freep(&s->priv_data);
3559
            url_fclose(s->pb);
3560
        }
3561
        /* get feed size and write index */
3562
        fd = open(feed->feed_filename, O_RDONLY);
3563
        if (fd < 0) {
3564
            http_log("Could not open output feed file '%s'\n",
3565
                    feed->feed_filename);
3566
            exit(1);
3567
        }
3568

    
3569
        feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3570
        feed->feed_size = lseek(fd, 0, SEEK_END);
3571
        /* ensure that we do not wrap before the end of file */
3572
        if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3573
            feed->feed_max_size = feed->feed_size;
3574

    
3575
        close(fd);
3576
    }
3577
}
3578

    
3579
/* compute the bandwidth used by each stream */
3580
static void compute_bandwidth(void)
3581
{
3582
    unsigned bandwidth;
3583
    int i;
3584
    FFStream *stream;
3585

    
3586
    for(stream = first_stream; stream != NULL; stream = stream->next) {
3587
        bandwidth = 0;
3588
        for(i=0;i<stream->nb_streams;i++) {
3589
            AVStream *st = stream->streams[i];
3590
            switch(st->codec->codec_type) {
3591
            case CODEC_TYPE_AUDIO:
3592
            case CODEC_TYPE_VIDEO:
3593
                bandwidth += st->codec->bit_rate;
3594
                break;
3595
            default:
3596
                break;
3597
            }
3598
        }
3599
        stream->bandwidth = (bandwidth + 999) / 1000;
3600
    }
3601
}
3602

    
3603
/* add a codec and set the default parameters */
3604
static void add_codec(FFStream *stream, AVCodecContext *av)
3605
{
3606
    AVStream *st;
3607

    
3608
    /* compute default parameters */
3609
    switch(av->codec_type) {
3610
    case CODEC_TYPE_AUDIO:
3611
        if (av->bit_rate == 0)
3612
            av->bit_rate = 64000;
3613
        if (av->sample_rate == 0)
3614
            av->sample_rate = 22050;
3615
        if (av->channels == 0)
3616
            av->channels = 1;
3617
        break;
3618
    case CODEC_TYPE_VIDEO:
3619
        if (av->bit_rate == 0)
3620
            av->bit_rate = 64000;
3621
        if (av->time_base.num == 0){
3622
            av->time_base.den = 5;
3623
            av->time_base.num = 1;
3624
        }
3625
        if (av->width == 0 || av->height == 0) {
3626
            av->width = 160;
3627
            av->height = 128;
3628
        }
3629
        /* Bitrate tolerance is less for streaming */
3630
        if (av->bit_rate_tolerance == 0)
3631
            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3632
                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3633
        if (av->qmin == 0)
3634
            av->qmin = 3;
3635
        if (av->qmax == 0)
3636
            av->qmax = 31;
3637
        if (av->max_qdiff == 0)
3638
            av->max_qdiff = 3;
3639
        av->qcompress = 0.5;
3640
        av->qblur = 0.5;
3641

    
3642
        if (!av->nsse_weight)
3643
            av->nsse_weight = 8;
3644

    
3645
        av->frame_skip_cmp = FF_CMP_DCTMAX;
3646
        av->me_method = ME_EPZS;
3647
        av->rc_buffer_aggressivity = 1.0;
3648

    
3649
        if (!av->rc_eq)
3650
            av->rc_eq = "tex^qComp";
3651
        if (!av->i_quant_factor)
3652
            av->i_quant_factor = -0.8;
3653
        if (!av->b_quant_factor)
3654
            av->b_quant_factor = 1.25;
3655
        if (!av->b_quant_offset)
3656
            av->b_quant_offset = 1.25;
3657
        if (!av->rc_max_rate)
3658
            av->rc_max_rate = av->bit_rate * 2;
3659

    
3660
        if (av->rc_max_rate && !av->rc_buffer_size) {
3661
            av->rc_buffer_size = av->rc_max_rate;
3662
        }
3663

    
3664

    
3665
        break;
3666
    default:
3667
        abort();
3668
    }
3669

    
3670
    st = av_mallocz(sizeof(AVStream));
3671
    if (!st)
3672
        return;
3673
    st->codec = avcodec_alloc_context();
3674
    stream->streams[stream->nb_streams++] = st;
3675
    memcpy(st->codec, av, sizeof(AVCodecContext));
3676
}
3677

    
3678
static enum CodecID opt_audio_codec(const char *arg)
3679
{
3680
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3681

    
3682
    if (p == NULL || p->type != CODEC_TYPE_AUDIO)
3683
        return CODEC_ID_NONE;
3684

    
3685
    return p->id;
3686
}
3687

    
3688
static enum CodecID opt_video_codec(const char *arg)
3689
{
3690
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3691

    
3692
    if (p == NULL || p->type != CODEC_TYPE_VIDEO)
3693
        return CODEC_ID_NONE;
3694

    
3695
    return p->id;
3696
}
3697

    
3698
/* simplistic plugin support */
3699

    
3700
#if HAVE_DLOPEN
3701
static void load_module(const char *filename)
3702
{
3703
    void *dll;
3704
    void (*init_func)(void);
3705
    dll = dlopen(filename, RTLD_NOW);
3706
    if (!dll) {
3707
        fprintf(stderr, "Could not load module '%s' - %s\n",
3708
                filename, dlerror());
3709
        return;
3710
    }
3711

    
3712
    init_func = dlsym(dll, "ffserver_module_init");
3713
    if (!init_func) {
3714
        fprintf(stderr,
3715
                "%s: init function 'ffserver_module_init()' not found\n",
3716
                filename);
3717
        dlclose(dll);
3718
    }
3719

    
3720
    init_func();
3721
}
3722
#endif
3723

    
3724
static int ffserver_opt_default(const char *opt, const char *arg,
3725
                       AVCodecContext *avctx, int type)
3726
{
3727
    int ret = 0;
3728
    const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3729
    if(o)
3730
        ret = av_set_string3(avctx, opt, arg, 1, NULL);
3731
    return ret;
3732
}
3733

    
3734
static int parse_ffconfig(const char *filename)
3735
{
3736
    FILE *f;
3737
    char line[1024];
3738
    char cmd[64];
3739
    char arg[1024];
3740
    const char *p;
3741
    int val, errors, line_num;
3742
    FFStream **last_stream, *stream, *redirect;
3743
    FFStream **last_feed, *feed, *s;
3744
    AVCodecContext audio_enc, video_enc;
3745
    enum CodecID audio_id, video_id;
3746

    
3747
    f = fopen(filename, "r");
3748
    if (!f) {
3749
        perror(filename);
3750
        return -1;
3751
    }
3752

    
3753
    errors = 0;
3754
    line_num = 0;
3755
    first_stream = NULL;
3756
    last_stream = &first_stream;
3757
    first_feed = NULL;
3758
    last_feed = &first_feed;
3759
    stream = NULL;
3760
    feed = NULL;
3761
    redirect = NULL;
3762
    audio_id = CODEC_ID_NONE;
3763
    video_id = CODEC_ID_NONE;
3764
    for(;;) {
3765
        if (fgets(line, sizeof(line), f) == NULL)
3766
            break;
3767
        line_num++;
3768
        p = line;
3769
        while (isspace(*p))
3770
            p++;
3771
        if (*p == '\0' || *p == '#')
3772
            continue;
3773

    
3774
        get_arg(cmd, sizeof(cmd), &p);
3775

    
3776
        if (!strcasecmp(cmd, "Port")) {
3777
            get_arg(arg, sizeof(arg), &p);
3778
            val = atoi(arg);
3779
            if (val < 1 || val > 65536) {
3780
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3781
                        filename, line_num, arg);
3782
                errors++;
3783
            }
3784
            my_http_addr.sin_port = htons(val);
3785
        } else if (!strcasecmp(cmd, "BindAddress")) {
3786
            get_arg(arg, sizeof(arg), &p);
3787
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
3788
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3789
                        filename, line_num, arg);
3790
                errors++;
3791
            }
3792
        } else if (!strcasecmp(cmd, "NoDaemon")) {
3793
            ffserver_daemon = 0;
3794
        } else if (!strcasecmp(cmd, "RTSPPort")) {
3795
            get_arg(arg, sizeof(arg), &p);
3796
            val = atoi(arg);
3797
            if (val < 1 || val > 65536) {
3798
                fprintf(stderr, "%s:%d: Invalid port: %s\n",
3799
                        filename, line_num, arg);
3800
                errors++;
3801
            }
3802
            my_rtsp_addr.sin_port = htons(atoi(arg));
3803
        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
3804
            get_arg(arg, sizeof(arg), &p);
3805
            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
3806
                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
3807
                        filename, line_num, arg);
3808
                errors++;
3809
            }
3810
        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
3811
            get_arg(arg, sizeof(arg), &p);
3812
            val = atoi(arg);
3813
            if (val < 1 || val > 65536) {
3814
                fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",
3815
                        filename, line_num, arg);
3816
                errors++;
3817
            }
3818
            nb_max_http_connections = val;
3819
        } else if (!strcasecmp(cmd, "MaxClients")) {
3820
            get_arg(arg, sizeof(arg), &p);
3821
            val = atoi(arg);
3822
            if (val < 1 || val > nb_max_http_connections) {
3823
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",
3824
                        filename, line_num, arg);
3825
                errors++;
3826
            } else {
3827
                nb_max_connections = val;
3828
            }
3829
        } else if (!strcasecmp(cmd, "MaxBandwidth")) {
3830
            int64_t llval;
3831
            get_arg(arg, sizeof(arg), &p);
3832
            llval = atoll(arg);
3833
            if (llval < 10 || llval > 10000000) {
3834
                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
3835
                        filename, line_num, arg);
3836
                errors++;
3837
            } else
3838
                max_bandwidth = llval;
3839
        } else if (!strcasecmp(cmd, "CustomLog")) {
3840
            if (!ffserver_debug)
3841
                get_arg(logfilename, sizeof(logfilename), &p);
3842
        } else if (!strcasecmp(cmd, "<Feed")) {
3843
            /*********************************************/
3844
            /* Feed related options */
3845
            char *q;
3846
            if (stream || feed) {
3847
                fprintf(stderr, "%s:%d: Already in a tag\n",
3848
                        filename, line_num);
3849
            } else {
3850
                feed = av_mallocz(sizeof(FFStream));
3851
                get_arg(feed->filename, sizeof(feed->filename), &p);
3852
                q = strrchr(feed->filename, '>');
3853
                if (*q)
3854
                    *q = '\0';
3855

    
3856
                for (s = first_feed; s; s = s->next) {
3857
                    if (!strcmp(feed->filename, s->filename)) {
3858
                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
3859
                                filename, line_num, s->filename);
3860
                        errors++;
3861
                    }
3862
                }
3863

    
3864
                feed->fmt = guess_format("ffm", NULL, NULL);
3865
                /* defaut feed file */
3866
                snprintf(feed->feed_filename, sizeof(feed->feed_filename),
3867
                         "/tmp/%s.ffm", feed->filename);
3868
                feed->feed_max_size = 5 * 1024 * 1024;
3869
                feed->is_feed = 1;
3870
                feed->feed = feed; /* self feeding :-) */
3871

    
3872
                /* add in stream list */
3873
                *last_stream = feed;
3874
                last_stream = &feed->next;
3875
                /* add in feed list */
3876
                *last_feed = feed;
3877
                last_feed = &feed->next_feed;
3878
            }
3879
        } else if (!strcasecmp(cmd, "Launch")) {
3880
            if (feed) {
3881
                int i;
3882

    
3883
                feed->child_argv = av_mallocz(64 * sizeof(char *));
3884

    
3885
                for (i = 0; i < 62; i++) {
3886
                    get_arg(arg, sizeof(arg), &p);
3887
                    if (!arg[0])
3888
                        break;
3889

    
3890
                    feed->child_argv[i] = av_strdup(arg);
3891
                }
3892

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

    
3895
                snprintf(feed->child_argv[i], 30+strlen(feed->filename),
3896
                    "http://%s:%d/%s",
3897
                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
3898
                    inet_ntoa(my_http_addr.sin_addr),
3899
                    ntohs(my_http_addr.sin_port), feed->filename);
3900
            }
3901
        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
3902
            if (feed) {
3903
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3904
                feed->readonly = 1;
3905
            } else if (stream) {
3906
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3907
            }
3908
        } else if (!strcasecmp(cmd, "File")) {
3909
            if (feed) {
3910
                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
3911
            } else if (stream)
3912
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
3913
        } else if (!strcasecmp(cmd, "Truncate")) {
3914
            if (feed) {
3915
                get_arg(arg, sizeof(arg), &p);
3916
                feed->truncate = strtod(arg, NULL);
3917
            }
3918
        } else if (!strcasecmp(cmd, "FileMaxSize")) {
3919
            if (feed) {
3920
                char *p1;
3921
                double fsize;
3922

    
3923
                get_arg(arg, sizeof(arg), &p);
3924
                p1 = arg;
3925
                fsize = strtod(p1, &p1);
3926
                switch(toupper(*p1)) {
3927
                case 'K':
3928
                    fsize *= 1024;
3929
                    break;
3930
                case 'M':
3931
                    fsize *= 1024 * 1024;
3932
                    break;
3933
                case 'G':
3934
                    fsize *= 1024 * 1024 * 1024;
3935
                    break;
3936
                }
3937
                feed->feed_max_size = (int64_t)fsize;
3938
                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
3939
                    fprintf(stderr, "%s:%d: Feed max file size is too small, "
3940
                            "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
3941
                    errors++;
3942
                }
3943
            }
3944
        } else if (!strcasecmp(cmd, "</Feed>")) {
3945
            if (!feed) {
3946
                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
3947
                        filename, line_num);
3948
                errors++;
3949
            }
3950
            feed = NULL;
3951
        } else if (!strcasecmp(cmd, "<Stream")) {
3952
            /*********************************************/
3953
            /* Stream related options */
3954
            char *q;
3955
            if (stream || feed) {
3956
                fprintf(stderr, "%s:%d: Already in a tag\n",
3957
                        filename, line_num);
3958
            } else {
3959
                FFStream *s;
3960
                const AVClass *class;
3961
                stream = av_mallocz(sizeof(FFStream));
3962
                get_arg(stream->filename, sizeof(stream->filename), &p);
3963
                q = strrchr(stream->filename, '>');
3964
                if (*q)
3965
                    *q = '\0';
3966

    
3967
                for (s = first_stream; s; s = s->next) {
3968
                    if (!strcmp(stream->filename, s->filename)) {
3969
                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
3970
                                filename, line_num, s->filename);
3971
                        errors++;
3972
                    }
3973
                }
3974

    
3975
                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
3976
                /* fetch avclass so AVOption works
3977
                 * FIXME try to use avcodec_get_context_defaults2
3978
                 * without changing defaults too much */
3979
                avcodec_get_context_defaults(&video_enc);
3980
                class = video_enc.av_class;
3981
                memset(&audio_enc, 0, sizeof(AVCodecContext));
3982
                memset(&video_enc, 0, sizeof(AVCodecContext));
3983
                audio_enc.av_class = class;
3984
                video_enc.av_class = class;
3985
                audio_id = CODEC_ID_NONE;
3986
                video_id = CODEC_ID_NONE;
3987
                if (stream->fmt) {
3988
                    audio_id = stream->fmt->audio_codec;
3989
                    video_id = stream->fmt->video_codec;
3990
                }
3991

    
3992
                *last_stream = stream;
3993
                last_stream = &stream->next;
3994
            }
3995
        } else if (!strcasecmp(cmd, "Feed")) {
3996
            get_arg(arg, sizeof(arg), &p);
3997
            if (stream) {
3998
                FFStream *sfeed;
3999

    
4000
                sfeed = first_feed;
4001
                while (sfeed != NULL) {
4002
                    if (!strcmp(sfeed->filename, arg))
4003
                        break;
4004
                    sfeed = sfeed->next_feed;
4005
                }
4006
                if (!sfeed)
4007
                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",
4008
                            filename, line_num, arg);
4009
                else
4010
                    stream->feed = sfeed;
4011
            }
4012
        } else if (!strcasecmp(cmd, "Format")) {
4013
            get_arg(arg, sizeof(arg), &p);
4014
            if (stream) {
4015
                if (!strcmp(arg, "status")) {
4016
                    stream->stream_type = STREAM_TYPE_STATUS;
4017
                    stream->fmt = NULL;
4018
                } else {
4019
                    stream->stream_type = STREAM_TYPE_LIVE;
4020
                    /* jpeg cannot be used here, so use single frame jpeg */
4021
                    if (!strcmp(arg, "jpeg"))
4022
                        strcpy(arg, "mjpeg");
4023
                    stream->fmt = guess_stream_format(arg, NULL, NULL);
4024
                    if (!stream->fmt) {
4025
                        fprintf(stderr, "%s:%d: Unknown Format: %s\n",
4026
                                filename, line_num, arg);
4027
                        errors++;
4028
                    }
4029
                }
4030
                if (stream->fmt) {
4031
                    audio_id = stream->fmt->audio_codec;
4032
                    video_id = stream->fmt->video_codec;
4033
                }
4034
            }
4035
        } else if (!strcasecmp(cmd, "InputFormat")) {
4036
            get_arg(arg, sizeof(arg), &p);
4037
            if (stream) {
4038
                stream->ifmt = av_find_input_format(arg);
4039
                if (!stream->ifmt) {
4040
                    fprintf(stderr, "%s:%d: Unknown input format: %s\n",
4041
                            filename, line_num, arg);
4042
                }
4043
            }
4044
        } else if (!strcasecmp(cmd, "FaviconURL")) {
4045
            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4046
                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4047
            } else {
4048
                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",
4049
                            filename, line_num);
4050
                errors++;
4051
            }
4052
        } else if (!strcasecmp(cmd, "Author")) {
4053
            if (stream)
4054
                get_arg(stream->author, sizeof(stream->author), &p);
4055
        } else if (!strcasecmp(cmd, "Comment")) {
4056
            if (stream)
4057
                get_arg(stream->comment, sizeof(stream->comment), &p);
4058
        } else if (!strcasecmp(cmd, "Copyright")) {
4059
            if (stream)
4060
                get_arg(stream->copyright, sizeof(stream->copyright), &p);
4061
        } else if (!strcasecmp(cmd, "Title")) {
4062
            if (stream)
4063
                get_arg(stream->title, sizeof(stream->title), &p);
4064
        } else if (!strcasecmp(cmd, "Preroll")) {
4065
            get_arg(arg, sizeof(arg), &p);
4066
            if (stream)
4067
                stream->prebuffer = atof(arg) * 1000;
4068
        } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4069
            if (stream)
4070
                stream->send_on_key = 1;
4071
        } else if (!strcasecmp(cmd, "AudioCodec")) {
4072
            get_arg(arg, sizeof(arg), &p);
4073
            audio_id = opt_audio_codec(arg);
4074
            if (audio_id == CODEC_ID_NONE) {
4075
                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",
4076
                        filename, line_num, arg);
4077
                errors++;
4078
            }
4079
        } else if (!strcasecmp(cmd, "VideoCodec")) {
4080
            get_arg(arg, sizeof(arg), &p);
4081
            video_id = opt_video_codec(arg);
4082
            if (video_id == CODEC_ID_NONE) {
4083
                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",
4084
                        filename, line_num, arg);
4085
                errors++;
4086
            }
4087
        } else if (!strcasecmp(cmd, "MaxTime")) {
4088
            get_arg(arg, sizeof(arg), &p);
4089
            if (stream)
4090
                stream->max_time = atof(arg) * 1000;
4091
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
4092
            get_arg(arg, sizeof(arg), &p);
4093
            if (stream)
4094
                audio_enc.bit_rate = atoi(arg) * 1000;
4095
        } else if (!strcasecmp(cmd, "AudioChannels")) {
4096
            get_arg(arg, sizeof(arg), &p);
4097
            if (stream)
4098
                audio_enc.channels = atoi(arg);
4099
        } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4100
            get_arg(arg, sizeof(arg), &p);
4101
            if (stream)
4102
                audio_enc.sample_rate = atoi(arg);
4103
        } else if (!strcasecmp(cmd, "AudioQuality")) {
4104
            get_arg(arg, sizeof(arg), &p);
4105
            if (stream) {
4106
//                audio_enc.quality = atof(arg) * 1000;
4107
            }
4108
        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4109
            if (stream) {
4110
                int minrate, maxrate;
4111

    
4112
                get_arg(arg, sizeof(arg), &p);
4113

    
4114
                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4115
                    video_enc.rc_min_rate = minrate * 1000;
4116
                    video_enc.rc_max_rate = maxrate * 1000;
4117
                } else {
4118
                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",
4119
                            filename, line_num, arg);
4120
                    errors++;
4121
                }
4122
            }
4123
        } else if (!strcasecmp(cmd, "Debug")) {
4124
            if (stream) {
4125
                get_arg(arg, sizeof(arg), &p);
4126
                video_enc.debug = strtol(arg,0,0);
4127
            }
4128
        } else if (!strcasecmp(cmd, "Strict")) {
4129
            if (stream) {
4130
                get_arg(arg, sizeof(arg), &p);
4131
                video_enc.strict_std_compliance = atoi(arg);
4132
            }
4133
        } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4134
            if (stream) {
4135
                get_arg(arg, sizeof(arg), &p);
4136
                video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4137
            }
4138
        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4139
            if (stream) {
4140
                get_arg(arg, sizeof(arg), &p);
4141
                video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4142
            }
4143
        } else if (!strcasecmp(cmd, "VideoBitRate")) {
4144
            get_arg(arg, sizeof(arg), &p);
4145
            if (stream) {
4146
                video_enc.bit_rate = atoi(arg) * 1000;
4147
            }
4148
        } else if (!strcasecmp(cmd, "VideoSize")) {
4149
            get_arg(arg, sizeof(arg), &p);
4150
            if (stream) {
4151
                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
4152
                if ((video_enc.width % 16) != 0 ||
4153
                    (video_enc.height % 16) != 0) {
4154
                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
4155
                            filename, line_num);
4156
                    errors++;
4157
                }
4158
            }
4159
        } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4160
            get_arg(arg, sizeof(arg), &p);
4161
            if (stream) {
4162
                AVRational frame_rate;
4163
                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
4164
                    fprintf(stderr, "Incorrect frame rate\n");
4165
                    errors++;
4166
                } else {
4167
                    video_enc.time_base.num = frame_rate.den;
4168
                    video_enc.time_base.den = frame_rate.num;
4169
                }
4170
            }
4171
        } else if (!strcasecmp(cmd, "VideoGopSize")) {
4172
            get_arg(arg, sizeof(arg), &p);
4173
            if (stream)
4174
                video_enc.gop_size = atoi(arg);
4175
        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4176
            if (stream)
4177
                video_enc.gop_size = 1;
4178
        } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4179
            if (stream)
4180
                video_enc.mb_decision = FF_MB_DECISION_BITS;
4181
        } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4182
            if (stream) {
4183
                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4184
                video_enc.flags |= CODEC_FLAG_4MV;
4185
            }
4186
        } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4187
                   !strcasecmp(cmd, "AVOptionAudio")) {
4188
            char arg2[1024];
4189
            AVCodecContext *avctx;
4190
            int type;
4191
            get_arg(arg, sizeof(arg), &p);
4192
            get_arg(arg2, sizeof(arg2), &p);
4193
            if (!strcasecmp(cmd, "AVOptionVideo")) {
4194
                avctx = &video_enc;
4195
                type = AV_OPT_FLAG_VIDEO_PARAM;
4196
            } else {
4197
                avctx = &audio_enc;
4198
                type = AV_OPT_FLAG_AUDIO_PARAM;
4199
            }
4200
            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4201
                fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
4202
                errors++;
4203
            }
4204
        } else if (!strcasecmp(cmd, "VideoTag")) {
4205
            get_arg(arg, sizeof(arg), &p);
4206
            if ((strlen(arg) == 4) && stream)
4207
                video_enc.codec_tag = AV_RL32(arg);
4208
        } else if (!strcasecmp(cmd, "BitExact")) {
4209
            if (stream)
4210
                video_enc.flags |= CODEC_FLAG_BITEXACT;
4211
        } else if (!strcasecmp(cmd, "DctFastint")) {
4212
            if (stream)
4213
                video_enc.dct_algo  = FF_DCT_FASTINT;
4214
        } else if (!strcasecmp(cmd, "IdctSimple")) {
4215
            if (stream)
4216
                video_enc.idct_algo = FF_IDCT_SIMPLE;
4217
        } else if (!strcasecmp(cmd, "Qscale")) {
4218
            get_arg(arg, sizeof(arg), &p);
4219
            if (stream) {
4220
                video_enc.flags |= CODEC_FLAG_QSCALE;
4221
                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4222
            }
4223
        } else if (!strcasecmp(cmd, "VideoQDiff")) {
4224
            get_arg(arg, sizeof(arg), &p);
4225
            if (stream) {
4226
                video_enc.max_qdiff = atoi(arg);
4227
                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4228
                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
4229
                            filename, line_num);
4230
                    errors++;
4231
                }
4232
            }
4233
        } else if (!strcasecmp(cmd, "VideoQMax")) {
4234
            get_arg(arg, sizeof(arg), &p);
4235
            if (stream) {
4236
                video_enc.qmax = atoi(arg);
4237
                if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4238
                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",
4239
                            filename, line_num);
4240
                    errors++;
4241
                }
4242
            }
4243
        } else if (!strcasecmp(cmd, "VideoQMin")) {
4244
            get_arg(arg, sizeof(arg), &p);
4245
            if (stream) {
4246
                video_enc.qmin = atoi(arg);
4247
                if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4248
                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",
4249
                            filename, line_num);
4250
                    errors++;
4251
                }
4252
            }
4253
        } else if (!strcasecmp(cmd, "LumaElim")) {
4254
            get_arg(arg, sizeof(arg), &p);
4255
            if (stream)
4256
                video_enc.luma_elim_threshold = atoi(arg);
4257
        } else if (!strcasecmp(cmd, "ChromaElim")) {
4258
            get_arg(arg, sizeof(arg), &p);
4259
            if (stream)
4260
                video_enc.chroma_elim_threshold = atoi(arg);
4261
        } else if (!strcasecmp(cmd, "LumiMask")) {
4262
            get_arg(arg, sizeof(arg), &p);
4263
            if (stream)
4264
                video_enc.lumi_masking = atof(arg);
4265
        } else if (!strcasecmp(cmd, "DarkMask")) {
4266
            get_arg(arg, sizeof(arg), &p);
4267
            if (stream)
4268
                video_enc.dark_masking = atof(arg);
4269
        } else if (!strcasecmp(cmd, "NoVideo")) {
4270
            video_id = CODEC_ID_NONE;
4271
        } else if (!strcasecmp(cmd, "NoAudio")) {
4272
            audio_id = CODEC_ID_NONE;
4273
        } else if (!strcasecmp(cmd, "ACL")) {
4274
            IPAddressACL acl;
4275

    
4276
            get_arg(arg, sizeof(arg), &p);
4277
            if (strcasecmp(arg, "allow") == 0)
4278
                acl.action = IP_ALLOW;
4279
            else if (strcasecmp(arg, "deny") == 0)
4280
                acl.action = IP_DENY;
4281
            else {
4282
                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
4283
                        filename, line_num, arg);
4284
                errors++;
4285
            }
4286

    
4287
            get_arg(arg, sizeof(arg), &p);
4288

    
4289
            if (resolve_host(&acl.first, arg) != 0) {
4290
                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4291
                        filename, line_num, arg);
4292
                errors++;
4293
            } else
4294
                acl.last = acl.first;
4295

    
4296
            get_arg(arg, sizeof(arg), &p);
4297

    
4298
            if (arg[0]) {
4299
                if (resolve_host(&acl.last, arg) != 0) {
4300
                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
4301
                            filename, line_num, arg);
4302
                    errors++;
4303
                }
4304
            }
4305

    
4306
            if (!errors) {
4307
                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
4308
                IPAddressACL **naclp = 0;
4309

    
4310
                acl.next = 0;
4311
                *nacl = acl;
4312

    
4313
                if (stream)
4314
                    naclp = &stream->acl;
4315
                else if (feed)
4316
                    naclp = &feed->acl;
4317
                else {
4318
                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
4319
                            filename, line_num);
4320
                    errors++;
4321
                }
4322

    
4323
                if (naclp) {
4324
                    while (*naclp)
4325
                        naclp = &(*naclp)->next;
4326

    
4327
                    *naclp = nacl;
4328
                }
4329
            }
4330
        } else if (!strcasecmp(cmd, "RTSPOption")) {
4331
            get_arg(arg, sizeof(arg), &p);
4332
            if (stream) {
4333
                av_freep(&stream->rtsp_option);
4334
                stream->rtsp_option = av_strdup(arg);
4335
            }
4336
        } else if (!strcasecmp(cmd, "MulticastAddress")) {
4337
            get_arg(arg, sizeof(arg), &p);
4338
            if (stream) {
4339
                if (resolve_host(&stream->multicast_ip, arg) != 0) {
4340
                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",
4341
                            filename, line_num, arg);
4342
                    errors++;
4343
                }
4344
                stream->is_multicast = 1;
4345
                stream->loop = 1; /* default is looping */
4346
            }
4347
        } else if (!strcasecmp(cmd, "MulticastPort")) {
4348
            get_arg(arg, sizeof(arg), &p);
4349
            if (stream)
4350
                stream->multicast_port = atoi(arg);
4351
        } else if (!strcasecmp(cmd, "MulticastTTL")) {
4352
            get_arg(arg, sizeof(arg), &p);
4353
            if (stream)
4354
                stream->multicast_ttl = atoi(arg);
4355
        } else if (!strcasecmp(cmd, "NoLoop")) {
4356
            if (stream)
4357
                stream->loop = 0;
4358
        } else if (!strcasecmp(cmd, "</Stream>")) {
4359
            if (!stream) {
4360
                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
4361
                        filename, line_num);
4362
                errors++;
4363
            } else {
4364
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4365
                    if (audio_id != CODEC_ID_NONE) {
4366
                        audio_enc.codec_type = CODEC_TYPE_AUDIO;
4367
                        audio_enc.codec_id = audio_id;
4368
                        add_codec(stream, &audio_enc);
4369
                    }
4370
                    if (video_id != CODEC_ID_NONE) {
4371
                        video_enc.codec_type = CODEC_TYPE_VIDEO;
4372
                        video_enc.codec_id = video_id;
4373
                        add_codec(stream, &video_enc);
4374
                    }
4375
                }
4376
                stream = NULL;
4377
            }
4378
        } else if (!strcasecmp(cmd, "<Redirect")) {
4379
            /*********************************************/
4380
            char *q;
4381
            if (stream || feed || redirect) {
4382
                fprintf(stderr, "%s:%d: Already in a tag\n",
4383
                        filename, line_num);
4384
                errors++;
4385
            } else {
4386
                redirect = av_mallocz(sizeof(FFStream));
4387
                *last_stream = redirect;
4388
                last_stream = &redirect->next;
4389

    
4390
                get_arg(redirect->filename, sizeof(redirect->filename), &p);
4391
                q = strrchr(redirect->filename, '>');
4392
                if (*q)
4393
                    *q = '\0';
4394
                redirect->stream_type = STREAM_TYPE_REDIRECT;
4395
            }
4396
        } else if (!strcasecmp(cmd, "URL")) {
4397
            if (redirect)
4398
                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4399
        } else if (!strcasecmp(cmd, "</Redirect>")) {
4400
            if (!redirect) {
4401
                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
4402
                        filename, line_num);
4403
                errors++;
4404
            } else {
4405
                if (!redirect->feed_filename[0]) {
4406
                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
4407
                            filename, line_num);
4408
                    errors++;
4409
                }
4410
                redirect = NULL;
4411
            }
4412
        } else if (!strcasecmp(cmd, "LoadModule")) {
4413
            get_arg(arg, sizeof(arg), &p);
4414
#if HAVE_DLOPEN
4415
            load_module(arg);
4416
#else
4417
            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
4418
                    filename, line_num, arg);
4419
            errors++;
4420
#endif
4421
        } else {
4422
            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
4423
                    filename, line_num, cmd);
4424
        }
4425
    }
4426

    
4427
    fclose(f);
4428
    if (errors)
4429
        return -1;
4430
    else
4431
        return 0;
4432
}
4433

    
4434
static void handle_child_exit(int sig)
4435
{
4436
    pid_t pid;
4437
    int status;
4438

    
4439
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4440
        FFStream *feed;
4441

    
4442
        for (feed = first_feed; feed; feed = feed->next) {
4443
            if (feed->pid == pid) {
4444
                int uptime = time(0) - feed->pid_start;
4445

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

    
4449
                if (uptime < 30)
4450
                    /* Turn off any more restarts */
4451
                    feed->child_argv = 0;
4452
            }
4453
        }
4454
    }
4455

    
4456
    need_to_start_children = 1;
4457
}
4458

    
4459
static void opt_debug(void)
4460
{
4461
    ffserver_debug = 1;
4462
    ffserver_daemon = 0;
4463
    logfilename[0] = '-';
4464
}
4465

    
4466
static void opt_show_help(void)
4467
{
4468
    printf("usage: ffserver [options]\n"
4469
           "Hyper fast multi format Audio/Video streaming server\n");
4470
    printf("\n");
4471
    show_help_options(options, "Main options:\n", 0, 0);
4472
}
4473

    
4474
static const OptionDef options[] = {
4475
    { "h", OPT_EXIT, {(void*)opt_show_help}, "show help" },
4476
    { "version", OPT_EXIT, {(void*)show_version}, "show version" },
4477
    { "L", OPT_EXIT, {(void*)show_license}, "show license" },
4478
    { "formats", OPT_EXIT, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
4479
    { "loglevel", HAS_ARG | OPT_FUNC2, {(void*)opt_loglevel}, "set libav* logging level", "loglevel" },
4480
    { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4481
    { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4482
    { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4483
    { NULL },
4484
};
4485

    
4486
int main(int argc, char **argv)
4487
{
4488
    struct sigaction sigact;
4489

    
4490
    av_register_all();
4491

    
4492
    show_banner();
4493

    
4494
    config_filename = "/etc/ffserver.conf";
4495

    
4496
    my_program_name = argv[0];
4497
    my_program_dir = getcwd(0, 0);
4498
    ffserver_daemon = 1;
4499

    
4500
    parse_options(argc, argv, options, NULL);
4501

    
4502
    unsetenv("http_proxy");             /* Kill the http_proxy */
4503

    
4504
    av_lfg_init(&random_state, ff_random_get_seed());
4505

    
4506
    memset(&sigact, 0, sizeof(sigact));
4507
    sigact.sa_handler = handle_child_exit;
4508
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4509
    sigaction(SIGCHLD, &sigact, 0);
4510

    
4511
    if (parse_ffconfig(config_filename) < 0) {
4512
        fprintf(stderr, "Incorrect config file - exiting.\n");
4513
        exit(1);
4514
    }
4515

    
4516
    /* open log file if needed */
4517
    if (logfilename[0] != '\0') {
4518
        if (!strcmp(logfilename, "-"))
4519
            logfile = stdout;
4520
        else
4521
            logfile = fopen(logfilename, "a");
4522
        av_log_set_callback(http_av_log);
4523
    }
4524

    
4525
    build_file_streams();
4526

    
4527
    build_feed_streams();
4528

    
4529
    compute_bandwidth();
4530

    
4531
    /* put the process in background and detach it from its TTY */
4532
    if (ffserver_daemon) {
4533
        int pid;
4534

    
4535
        pid = fork();
4536
        if (pid < 0) {
4537
            perror("fork");
4538
            exit(1);
4539
        } else if (pid > 0) {
4540
            /* parent : exit */
4541
            exit(0);
4542
        } else {
4543
            /* child */
4544
            setsid();
4545
            close(0);
4546
            open("/dev/null", O_RDWR);
4547
            if (strcmp(logfilename, "-") != 0) {
4548
                close(1);
4549
                dup(0);
4550
            }
4551
            close(2);
4552
            dup(0);
4553
        }
4554
    }
4555

    
4556
    /* signal init */
4557
    signal(SIGPIPE, SIG_IGN);
4558

    
4559
    if (ffserver_daemon)
4560
        chdir("/");
4561

    
4562
    if (http_server() < 0) {
4563
        http_log("Could not start server\n");
4564
        exit(1);
4565
    }
4566

    
4567
    return 0;
4568
}